Помогите разобраться

Доброго времени!
Надеюсь опытные товарищи помогут разрешить проблему- строка 16 приводит к остановке выполнения кода, сам алгоритм как бы был проверен в онлайн ЦПП компиляторе и работает. Что я делаю не так?
Спасибо заранее. Платформа МЕГА 2560

void Knube_::expand( s_Button *_arr_)  //РАШИРЯЕМ МАССИВ, СОДЕРЖАЩИЙ ОБЬЕКТЫ
{uint8_t nmb=cnt;
  s_Button *buff = new s_Button[nmb];  //ВРЕМЕННЫЙ МАССИВ
  for (uint8_t ii = 0; ii < nmb; ii++) {
    buff[ii] = arr_tst[ii];  //ПЕРЕПИСЫВАЕНМ СОДЕРЖАНИЕ ИСХОДНОГО МАССИВА ВО ВРЕМЕННЫЙ МАССИВ
    uint8_t tp=buff[ii]._pin_;
    Serial.print("Buffer=  ");Serial.println(tp);
  }
 _arr_ = (s_Button *)realloc(_arr_, nmb+1);  //РАСШИРЯЕМ ИСХОДНЫЙ МАССИВ
 if(!_arr_){Serial.println("Fuck_you!!");
 return;}
  Serial.print("expand nmb= ");Serial.println(nmb);
 // std::cout<<"nmb= "<<nmb<<"; ";
  for (uint8_t jj = 0; jj < (nmb); jj++)  //ЗАПОЛНЯЕМ ИСХОДНЫЙ МАССИВ, ОСТАЕТСЯ СВОБОДНОЙ ПОСЛЕДНЯЯ ЯЧЕЙКА
  {
_arr_[jj] = buff[jj];
  }
  delete[] buff;
 }

Выложите весь код, а то непонятно, как описаны переменные

Много отладочного мусора, извините(

#include <stdint.h>
#pragma once
#include "s_Button.h"
#include "get_port_2560_TST.h"
class tst_butt{
  public:
  uint8_t bb;
};


class Knube_ {
private:
  
  s_Button *arr_ = new s_Button[1];
 // s_Button arr_tst[5];
public:
s_Button *arr_tst = new s_Button[5];
  uint8_t cnt = 1;
  void repair(int _pin,bool _mode_, void (*_fnc__)(),int kk);
  void scan();
  void expand( s_Button *arr_tst);
  void add_obj(int _pin, bool _mode_, void (*_fnc__)());
  void call();
  Knube_() {}
};
void Knube_::repair(int _pin,bool _mode_, void (*_fnc__)(),int kk)
{
s_Button mm(_pin, _mode_, _fnc__);
arr_tst[kk]=mm;
Serial.print("repaired !!");Serial.println(kk);
}
void Knube_::scan()
{
  for (uint8_t ff=0;ff<4;ff++)
  { arr_tst[ff].buttom();
    //arr_tst[ff].tsprint();
  }
 // Serial.println("scan");
}
void Knube_::add_obj(int _pin, bool _mode_, void (*_fnc__)()) {
 //Проверка
  for (uint8_t kk=0; kk<cnt; kk++)
  {
    if(arr_tst[kk]._pin_==_pin)
    {
      repair(_pin,_mode_, _fnc__, kk);
      return;
    }
  }
if(cnt<5)
{
  s_Button n_b(_pin, _mode_, _fnc__);
  arr_tst[cnt-1]=n_b;
  if(cnt>1)expand(  arr_);
  cnt++;
  
  //arr_[cnt]=n_b;
 // arr_tst[cnt].tsprint();
  //cnt+=1;
}

//   if (cnt == 0)
// {repair(_pin,_mode_, _fnc__, 0);
//   Serial.print("cnt=");Serial.print(cnt);  
//  cnt=1;
//  }
// else
// {
//  // expand((cnt), arr_tst);
//   s_Button mm(_pin, _mode_, _fnc__);
  
//   cnt+=1;arr_tst[cnt] = mm;

//   }
//Serial.print("cnt=");Serial.print(cnt);
}
void Knube_::expand( s_Button *_arr_)  //РАШИРЯЕМ МАССИВ, СОДЕРЖАЩИЙ ОБЬЕКТЫ
{uint8_t nmb=cnt;
  s_Button *buff = new s_Button[nmb];  //ВРЕМЕННЫЙ МАССИВ
  for (uint8_t ii = 0; ii < nmb; ii++) {
    buff[ii] = arr_tst[ii];  //ПЕРЕПИСЫВАЕНМ СОДЕРЖАНИЕ ИСХОДНОГО МАССИВА ВО ВРЕМЕННЫЙ МАССИВ
    uint8_t tp=buff[ii]._pin_;
    Serial.print("Buffer=  ");Serial.println(tp);
  }
 _arr_ = (s_Button *)realloc(_arr_, nmb+1);  //РАСШИРЯЕМ ИСХОДНЫЙ МАССИВ
 if(!_arr_){Serial.println("Fuck_you!!");
 return;}
  Serial.print("expand nmb= ");Serial.println(nmb);
 // std::cout<<"nmb= "<<nmb<<"; ";
  for (uint8_t jj = 0; jj < (nmb); jj++)  //ЗАПОЛНЯЕМ ИСХОДНЫЙ МАССИВ, ОСТАЕТСЯ СВОБОДНОЙ ПОСЛЕДНЯЯ ЯЧЕЙКА
  {
 //_arr_[jj] = buff[jj];
  }
  delete[] buff;
 }
void Knube_::call() {
  for (int kk = 0; kk < cnt; kk++) {  //arr_tst[kk]._print_();
  }
}

кнопка

#pragma once
#include "get_port_2560_TST.h"

class s_Button {
 
  port_Def g_P;
private:
  boolean dbnc = 0;
  unsigned long period = 0;
  unsigned long period_dbnc = 0;
  byte mode = 0;  //pull_up=0, no pull_up=1
  boolean active = 0;
  boolean long_clk;
  boolean f_click = 0;
  uint8_t mask;
  volatile uint8_t PIN;
public:
  void buttom();
  bool butt_Read(int _pin_);
  int _pin_;
  bool pressed = false;
  void tsprint();  
  void (*_fnc_)(int);
  s_Button(int pin, bool _mode, void (*_fnc)()): _pin_(pin), mode(_mode), _fnc_(_fnc) {
  g_P.set_pin(pin, true); if (_mode) g_P.noPullUp(pin);  PIN = g_P.get_pin(pin);  mask = g_P.get_mask(pin);
  g_P.set_pin(pin, true);  
  Serial.print("butt added! pin= ");
  Serial.println(_pin_);
  }
  s_Button() {}
};
void s_Button::tsprint()
{
Serial.print("PIN");Serial.println(PIN);
Serial.print("mask");Serial.println(mask);  
}

bool s_Button::butt_Read(int _pin_) {
  return ((*(volatile uint8_t *)(PIN)) & (1 << mask));
}
void s_Button::buttom() 
{
  
bool RD=butt_Read( _pin_);
if(!RD){ Serial.print("here_buttom!  ");Serial.println( _pin_);}}

  1. В 77 строке вы передаете массив в метод по ссылке
s_Button *_arr_

а в 81й строке обращаетесь к нему напрямую.
Так не делают

  1. В строке 86 вы проверяете результат выделения памяти - и это верно. А в 79й почему-то нет, хотя блок выделения явно больше, чем в первом случае.

  2. Вы уверены, что ваш класс можно присваивать простым копированием?

(номера строк по сообщению 3)

Это, судя по Монитору, срабатывает. поэтому выделение памяти не проверяется.

Намекните, как правильно, если не трудно.(Адресная арифметика?)`
. Вы уверены, что ваш класс можно присваивать простым копированием?
Не уверен, но как проверить не знаю

Если я правильно понял, параметр метода - это указатель на массив, который надо расширить?

Тогда и внутри метода вы должны обращаться к _arr_, а не к _arr_tst

И еще. Что такое cnt - размер массива? Тогда при расширении массива его, наверно, тоже надо менять?

Спасибо, проверю.

Он по идее изменяется внутре:) вызывающего метода.

не увидел этого в коде

судя по ответу, вы не поняли моего замечания.
Что не понятно - переспрашивайте.

Это здесь

@Alexey_Rem причина зависания понятна. Вы запрашиваете nmb+1 БАЙТОВ

а надо (nmb + 1) * sizeof(s_Button) .

Это поправьте, но не торопитесь. Это далеко не единственная ошибка. Есть пачка ещё, в основном неинтересных (я про них скажу), но одна - очень подлая и нетривиальная. Я сейчас пытаюсь подобрать простой и понятный пример, который бы её продемонстрировал, дайте мне немного времени, пожалуйста. Ошибка очень непростая и далеко не всегда сразу проявляющаяся, потому дайте мне время подготовить развёрнутое пояснение с примерами.

1 лайк

“Если слепой ведет слепого, то оба они упадут в яму!”

Алексей Рем. Параметр в реаллоке в чем? сколько байт ты выделил (ответ: nmb+1)
:wink:
А думаешь, что nmb+1 место доя структуры s_Button.


ЗЫ: Алексей Рем, ты кого слушаешь? Ты мало знаешь о безграмотности Б707? При попытках дотянуть до “гуру”!


ЗЗЫ: Женя, как обычно! Нет бочки. которую он не заткнет! Он опередил.

1 лайк

Чем приятны образованные люди - им не нужно всё подробно растолковывать. Это я к тому, что Овечкина ты читал.

Считаю что каждый, кто хочет помочь в силу своих возможностей достоин УВАЖЕНИЯ, поэтому до личных оскорблений прошу не скатываться, сейчас, к сожалению вынужден прерваться на некоторое время

1 лайк

да лан, проехали.
Я правда облажался, писал о мелочах, а не заметил очевидного ляпа.

Не получается:(
“требую продолжения банкета…”(С)

15:22:27.539 -> arr_ &=3AF; _arr_ &=3AF
15:22:27.539 ->  realloc _arr_ &=3AF

realloc не изменил адрес массива! Значит он просто не работает?

Он может и не менять, если есть возможность расширения:

The reallocation is done by either:

a) expanding or contracting the existing area pointed to by ptr, if possible. The contents of the area remain unchanged up to the lesser of the new and old sizes. If the area is expanded, the contents of the new part of the array are undefined.

b) allocating a new memory block of size new_size bytes, copying memory area with size equal the lesser of the new and the old sizes, and freeing the old block.

1 лайк
15:30:50.966 -> arr_ &=3AF; _arr_ &=3AF
15:30:50.966 ->  realloc _arr_ &=53E

Извините, это я немного погорячился, задолбался уже

Так, ну поехали, начнём с самой вкусной ошибки, потом поговорим о других, а на закуску, поговорим о том, что expand вообще делается не так, его надо просто выбросить и написать по-другому. Я буду подводить постепенно, чтобы Вы сами догадались в чём беда.

Самая вкусная ошибка

Чтобы упростить код, я написал точно такой же (по сути) expand как у Вас, только массив у меня int и всё лишнее (не имеющее отношение к ошибке) выбросил. Все примеры полные, запускайте, любуйтесь.

В примере есть класс Kaka, в нём массив arr, который изначально запрашивается размером в INI_SIZE и заполняется числами от 0 до INI_SIZE - 1.

Также в классе есть метод expand - идейно копия Вашего (убедитесь). Он увеличивает массив на 1 элемент и все старые элементы копирует в новый массив.

Наконец, в классе есть метод printArr, который печатает первые INI_SIZE элементов массива arr в одну строку.

В основной программе создаётся экземпляр класса, печатается массив arr, вызывается expand и снова печатается массив arr для проверки как всё прошло.

Вот пример, убедитесь, что всё так и есть, потом запустите его и посмотрите на результат:

Код примера
struct Kaka {
	int * arr;
	int len;
	static constexpr uint8_t INI_SIZE = 10;

	// Изначально запросим массив размером INI_SIZE и 
	// заполним его разумными значениями
	Kaka(void) { 
		len = INI_SIZE;
		arr = new int[len];
		for (int i = 0; i < len; arr[i] = i, i++);
	}

	//
	//	expand покороче, но идейно - точно как Ваш, сверьте
	void expand(int * p) {
		int * tmp = new int[len+1]; // запрос временного массива
		for (int i = 0; i < len; tmp[i] = p[i], i++); // копирование во временный массив
		p = (int *) realloc(p, sizeof(int) * (len + 1)); // перезапрос основного массива
		for (int i = 0; i < len; p[i] = tmp[i], i++); // копирование из временного в новый основной
		len ++;
		delete [] tmp;
	}

	// Печатаем только первые INI_SIZE элементов arr
	// т.к. в добавляемый элемент мы всё равно ничего не записывали, чего грязь печатать.
	void printArr(void) {
		for (int i = 0; i < INI_SIZE; i++) {
			Serial.print(arr[i]);
			Serial.print(i == (INI_SIZE - 1) ? "\r\n" : ", ");
		}
	}
};


void setup(void) {
	Serial.begin(9600);
	static Kaka kaka;
	kaka.printArr();
	kaka.expand(kaka.arr);
	kaka.printArr();
}

void loop(void) {}
Результат выполнения
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Ну, чё? Ура! Всё работает! Здорово!

Пишем дальше программу. Понадобилось нам тут строку завести и напечатать. Добавляем в наш пример между строками №40 и №41 создание текстовой строки и её печать:

Вставить после строки №40 предыдущего примера
	String str = "Everything is fine!";
	Serial.println(str);
Результат выполнения
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Everything is fine!
0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Ну, ничего удивительного, всё работает как надо.

Тут нам приспичило изменить текст. Ну, что что надо, так изменим. В строке №41 (по последнему тексту заменяем

String str = "Everything is fine!";

на

String str = "I am a genius! My software is bugs free! No one can do it as fine as I do!";

запускаем и видим, что всё так и есть! Я - гений!

Результат выполнения
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
I am genius! My software is bugs free! No one can do it as fine as I do!
0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Ну, а собственно с чего бы её и не работать?

Прошло ещё какое-то время и мен опять приспичило поменять текст. На этот раз вместо строки №41 надо вписать
String str = "What the fucking glitches in there???";

(я приведу полный текст, чтобы впредь на него ссылаться, но изменеа в нём только строка №41)

Полный текст примера 'ГЛЮК'
struct Kaka {
	int * arr;
	int len;
	static constexpr uint8_t INI_SIZE = 10;

	// Изначально запросим массив размером INI_SIZE и 
	// заполним его разумными значениями
	Kaka(void) { 
		len = INI_SIZE;
		arr = new int[len];
		for (int i = 0; i < len; arr[i] = i, i++);
	}

	//
	//	expand покороче, но идейно - точно как Ваш, сверьте
	void expand(int * p) {
		int * tmp = new int[len+1]; // запрос временного массива
		for (int i = 0; i < len; tmp[i] = p[i], i++); // копирование во временный массив
		p = (int *) realloc(p, sizeof(int) * (len + 1)); // перезапрос основного массива
		for (int i = 0; i < len; p[i] = tmp[i], i++); // копирование из временного в новый основной
		len ++;
		delete [] tmp;
	}

	// Печатаем только первые INI_SIZE элементов arr
	// т.к. в добавляемый элемент мы всё равно ничего не записывали, чего грязь печатать.
	void printArr(void) {
		for (int i = 0; i < INI_SIZE; i++) {
			Serial.print(arr[i]);
			Serial.print(i == (INI_SIZE - 1) ? "\r\n" : ", ");
		}
	}
};


void setup(void) {
	Serial.begin(9600);
	static Kaka kaka;
	kaka.printArr();
	kaka.expand(kaka.arr);
	String str = "What the fucking glitches in there???";
	Serial.println(str);
	kaka.printArr();
}

void loop(void) {}

Запускаем и с удивлением видим:

Результат выполнения
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
What the fucking glitches in there???
0, 1, 38, 26711, 29793, 29728, 25960, 26144, 25461, 26987

Это вообще, чё щас было? Каким образом эта грёбанная строка могла поменять массив?

Если бы я этот пример запустил после первой строки (“Everything is fine!”), то можно было бы предположить, что более длинная строка переполнила память, но ведь в предыдущем примере строка была ещё более длинной! И всё работало!

Более того, когда я случайно изменил изначальный размер массива (в примере “ГЛЮК” в строке 4 поменял 10 на 5, то … сами смотрите:

Результат выполнения
0, 1, 2, 3, 4
What the fucking glitches in there???
0, 1, 2, 3, 4

Вернул обратно 10 и …

Опять 25 :(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
What the fucking glitches in there???
0, 1, 38, 26711, 29793, 29728, 25960, 26144, 25461, 26987

Хрень какая-то! Получается, что эта грёбанная строка не просто изменяет постронний массив, да ещё и делает это избирательно, то меняет, то меняет в зависимости от длины строки и длины самого массива! Всё зависит от каких-то непонятных свойств строки!

Но ведь не может эта строка менять массив! Этого не может быть! Вернее, не должно быть! Похоже, объяснение одно (вернее, два): ардуина китайская, а компилятор опенсорсный. Кругом одно дерьмо, тока я посреди него весь в белом :frowning: Пойду на форум в жилетку плакаться.

Так, @Alexey_Rem если Вы уже догадались в чём задница, отлично. Если нет, почитайте тему про память, прежде, чем читать объяснения ниже. Возможно, после прочтения той темы, Вам уже никакие объяснения не понадобятся.

Wo ist der hund begraben?

Ну, что давайте начнём с того, что посмотрим вот на такой

Крохотный пример
void kaka(int n) {
	n = n * 2;
	Serial.print("Inside 'kaka': ");
	Serial.println(n);	
}


void setup(void) {
	Serial.begin(9600);

	int iN = 11;
	Serial.print("Before 'kaka': ");
	Serial.println(iN);
	kaka(iN);
	Serial.print("After 'kaka': ");
	Serial.println(iN);
}

void loop(void) {}

и его

Результат выполнения
Before 'kaka': 11
Inside 'kaka': 22
After 'kaka': 11

Получается, переменная iN в функции setup не изменилась, хотя мы её передавали в функцию kaka и там меняли. Более того, мы убедились в том, что там она изменилась! Вас это не смущает?

Видимо, нет. И правда, с чего бы её меняться? Мы же передали её по значению, т.е. в функции kaka была совершенно другая переменная, изначально равная нашей iN. И все изменения этой другой переменной внутри функции kaka, там и останутся. На нашу iN они никак не влияют!

Ну, тогда вернёмся к примеру “ГЛЮК”.

Что мы там делаем? Мы функции expand передаём указатель. Этот указатель внутри той функции изменяем и … и ничего. Внутри функции expand совершенно другой указатель, его можно хоть заменяться - на тот указатель, что мы передали это никак не отразится! Т.е. наши изменения никак не затронули внешнюю, по отношению к функции expand, переменную arr. Никак! arr каким был, таким и остался. Меняли мы его локальную копию внутри функции expand. А сама переменная arr по-прежнему указывает на наш старый массив, а вовсе не на новый, который мы создали в expand.

Но и это не всё! Как говаривал М.С. Горбачёв, «я вам больше скажу», мы ведь в expand не только меняли локальную копию arr! Мы ведь ещё и освободили ту память, на которую наш arr указывал! Т.е. после вызова expand наш arr численно не изменился и указывает на кусок свободной памяти в которой когда-то, до вызова expand, был массив! Но память эта уже свободна!

Вот теперь мы готовы понять почему “то меняется, то не меняется”! Дело в том, что пока этой свободной памятью никто не воспользовался в ней лежит то, что и лежало и нам кажется, что всё прекрасно! Но как только эту память хапнула под себя строка, мы тут же увидели, что там что-то поменялось!

Получается, что программа наша всегда работала неправильно, просто пока памятью никто не воспользовался, мы этого не замечали, т.к. всё выглядело прилично. А как только эта память кому-то понадобилась, сразу начали “глюки”.

Теперь понятно, что происходит и откуда глюки взялись? Еще раз, работало неправильно всегда, просто не всегда это было заметно!

Как с этим бороться?

Ну, я с ходу вижу три способа.

Способ №1 (идейно-правильный) - не менять пытаться параметр функции, а возвращать новое значение. Смотрите, здесь наша функция уже не void, она возвращает локальную копию указателя, а там мы его присваиваем arr.

Исправляем пример 'ГЛЮК'. Способ №1
struct Kaka {
	int * arr;
	int len;
	static constexpr uint8_t INI_SIZE = 10;

	// Изначально запросим массив размером INI_SIZE и 
	// заполним его разумными значениями
	Kaka(void) { 
		len = INI_SIZE;
		arr = new int[len];
		for (int i = 0; i < len; arr[i] = i, i++);
	}

	//
	//	expand покороче, но идейно - точно как Ваш, сверьте
	int * expand(int * p) {
		int * tmp = new int[len+1]; // запрос временного массива
		for (int i = 0; i < len; tmp[i] = p[i], i++); // копирование во временный массив
		p = (int *) realloc(p, sizeof(int) * (len + 1)); // перезапрос основного массива
		for (int i = 0; i < len; p[i] = tmp[i], i++); // копирование из временного в новый основной
		len ++;
		delete [] tmp;
		return p;
	}

	// Печатаем только первые INI_SIZE элементов arr
	// т.к. в добавляемый элемент мы всё равно ничего не записывали, чего грязь печатать.
	void printArr(void) {
		for (int i = 0; i < INI_SIZE; i++) {
			Serial.print(arr[i]);
			Serial.print(i == (INI_SIZE - 1) ? "\r\n" : ", ");
		}
	}
};


void setup(void) {
	Serial.begin(9600);
	static Kaka kaka;
	kaka.printArr();
	kaka.arr = kaka.expand(kaka.arr);
	String str = "What the fucking glitches in there???";
	Serial.println(str);
	kaka.printArr();
}

void loop(void) {}
Результат выполнения
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
What the fucking glitches in there???
0, 1, 2, 3, 4, 5, 6, 7, 8, 9

но если нам таки очень хочется изменять параметр и оставить функцию expand void, то можно передавать параметром не сам указатель, а ссылку или указатель на него. В первом случае в пример ‘ГЛЮК’ придётся изменить (добавить) всего одну (!!!) букву!

Вот смотрите - это точно тот же пример ‘ГЛЮК’ в котором в строку №16 добавили всего один символ & - и всё заработало!

Исправляем пример 'ГЛЮК'. Способ №2
struct Kaka {
	int * arr;
	int len;
	static constexpr uint8_t INI_SIZE = 10;

	// Изначально запросим массив размером INI_SIZE и 
	// заполним его разумными значениями
	Kaka(void) { 
		len = INI_SIZE;
		arr = new int[len];
		for (int i = 0; i < len; arr[i] = i, i++);
	}

	//
	//	expand покороче, но идейно - точно как Ваш, сверьте
	void expand(int * & p) {
		int * tmp = new int[len+1]; // запрос временного массива
		for (int i = 0; i < len; tmp[i] = p[i], i++); // копирование во временный массив
		p = (int *) realloc(p, sizeof(int) * (len + 1)); // перезапрос основного массива
		for (int i = 0; i < len; p[i] = tmp[i], i++); // копирование из временного в новый основной
		len ++;
		delete [] tmp;
	}

	// Печатаем только первые INI_SIZE элементов arr
	// т.к. в добавляемый элемент мы всё равно ничего не записывали, чего грязь печатать.
	void printArr(void) {
		for (int i = 0; i < INI_SIZE; i++) {
			Serial.print(arr[i]);
			Serial.print(i == (INI_SIZE - 1) ? "\r\n" : ", ");
		}
	}
};


void setup(void) {
	Serial.begin(9600);
	static Kaka kaka;
	kaka.printArr();
	kaka.expand(kaka.arr);
	String str = "What the fucking glitches in there???";
	Serial.println(str);
	kaka.printArr();
}

void loop(void) {}
Результат выполнения
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
What the fucking glitches in there???
0, 1, 2, 3, 4, 5, 6, 7, 8, 9

ну, и, наконец, можно передавать не ссылку, а указатель (получается “указатель на указатель”). Смотрите на технику этого дела:

Исправляем пример 'ГЛЮК'. Способ №3
struct Kaka {
	int * arr;
	int len;
	static constexpr uint8_t INI_SIZE = 10;

	// Изначально запросим массив размером INI_SIZE и 
	// заполним его разумными значениями
	Kaka(void) { 
		len = INI_SIZE;
		arr = new int[len];
		for (int i = 0; i < len; arr[i] = i, i++);
	}

	//
	//	expand покороче, но идейно - точно как Ваш, сверьте
	void expand(int * * p) {
		int * tmp = new int[len+1]; // запрос временного массива
		for (int i = 0; i < len; tmp[i] = *p[i], i++); // копирование во временный массив
		*p = (int *) realloc(*p, sizeof(int) * (len + 1)); // перезапрос основного массива
		for (int i = 0; i < len; *p[i] = tmp[i], i++); // копирование из временного в новый основной
		len ++;
		delete [] tmp;
	}

	// Печатаем только первые INI_SIZE элементов arr
	// т.к. в добавляемый элемент мы всё равно ничего не записывали, чего грязь печатать.
	void printArr(void) {
		for (int i = 0; i < INI_SIZE; i++) {
			Serial.print(arr[i]);
			Serial.print(i == (INI_SIZE - 1) ? "\r\n" : ", ");
		}
	}
};


void setup(void) {
	Serial.begin(9600);
	static Kaka kaka;
	kaka.printArr();
	kaka.expand(& kaka.arr);
	String str = "What the fucking glitches in there???";
	Serial.println(str);
	kaka.printArr();
}

void loop(void) {}
Результат выполнения
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
What the fucking glitches in there???
0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Ну, вот как-то так. Мы избавились от самой вкусной ошибки.

Другие ошибки

они не так интересны. Я коротко перечислю их по коду из самого первого сообщения

  1. в строке №3 забыли проверить выделилась ли память;
  2. в строке №9 не проверили реально ил получен новый кусок памяти или просто изменён размер существующего. В последнем случае не нужно копировать содержимое массива, оно и так на месте. Да и старый освобождать нельзя, т.к. Вы его же ещё используете.

Как надо было делать

Во-первых, стоило до последнего избегать расширения массива. Лучше сразу запросить на максимальный размер, будет гораздо экономичнее.

Но, если уж нужно менять размер, то нужно это делать так:

  • сохранить указатель на старый массив в локальной переменной;
  • вызвать realloc
  • если возвращён тот же самый кусок памяти, то ничего больше не делать;
  • и только если возвращён новый кусок - скопировать старый массив в новый один раз (а не два копирования, как сейчас) и после этого освободить память старого массива.
4 лайка

Я Вам про это написал в “многобуквенном опусе”. Это его нормальное поведение. Теперь Вы понимаете, почему старый кусок памяти нельзя так нагло не глядя освобождать, как это делаете Вы.

1 лайк