Утекание памяти при копировании массива

dune10991
Offline
Зарегистрирован: 13.04.2018

Может кто-то подскажет, куда "копать".

Короче есть необходимость из функции передавать массив.

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

char *arr_in = "abcdrt";
void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.print("свободно памяти="); Serial.println(freeRam());
  Serial.print("arr_in="); Serial.println(arr_in);
  int  SIZE = strlen(arr_in);
  Serial.print("Возвращенный массив="); Serial.println(arr_remake(arr_in, SIZE));
  delay(200);
}

//ФУНКЦИЯ ПРИНИМАЮЩАЯ МАССИВ И ОТДАЮЩАЯ ПРЕОБРАЗОВАННЫЙ
char* arr_remake(char arr[], const int size) {
   char* Array = new char[size];
  for (int j = 0; j < size; j++) {
    Array[j] = toupper(arr[j]);
  }
   return Array;
  delete [] Array;//
}

// ФУНКЦИЯ ПРОВЕРКИ СВОБОДНОЙ ОПЕРАТИВНОЙ ПАМЯТИ МИКРОКОНТРОЛЛЕРА
int freeRam()
{
  extern int __heap_start, *__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
}

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

строки 20-21 ты из функции выходишь раньше, чем уничтожаешь массив.

И вапще, так массив не возвращают

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Как, по вашему мнению, работают строки 20 и 21?

Но это первое. Второе - не надо создавать новый массив и возвращать его. Манипулируйте переданным в функцию.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

ТС почитай про ссылки и указатели.
Тебе они нужны.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dune10991 пишет:
что в коде не так
Всё.

Вы выделяете память под массив внутри функции, но никогда её не освобождаете.

И вообще, так это не делается. Но чтобы объяснять как делается, нужно понимать что нужно сделать, а Вы забыли про это написать.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Передайте указатель на массив, преобразуйте его. А лучше передайте основной программой в функцию каждый элемент массива и преобразуйте его.

dune10991
Offline
Зарегистрирован: 13.04.2018

ЕвгенийП пишет:

dune10991 пишет:
что в коде не так
Всё.

Вы выделяете память под массив внутри функции, но никогда её не освобождаете.

И вообще, так это не делается. Но чтобы объяснять как делается, нужно понимать что нужно сделать, а Вы забыли про это написать.

Если про то, что требуется вообще, то: 
внутри функции принимаются данные из серийного порта  (в моем случае по BT) и функция должна возвращать эти данные. В моем случае необходимо передавать строковые массивы.
Ну и вообще понять, как возвращать строковый массив из функции.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dune10991 пишет:

Ну и вообще понять, как возвращать строковый массив из функции.

Или передавать ей уже готовый для заполнения, а она только заполняет, или внутри функции запрашивать память, возвращать, а в вызывающей функции эту память освобождать, когда она больше не нужна.

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

Вот набросал пример первого варианта, и я сам потренировался.

void arr_remake(char arr[], const int size) {
	strcpy(arr, "hello!!!");
}

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

	char arr_in[30] = "abcdrt"; //массив буфер достсточного размера
	Serial.print("arr_in= "); Serial.print(arr_in); Serial.print("\tlen= "); Serial.println(strlen(arr_in));
	arr_remake(arr_in, strlen(arr_in));
	Serial.print("arr_in= "); Serial.print(arr_in); Serial.print("\tlen= "); Serial.println(strlen(arr_in));
}

void loop() {}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не, ну так нельзя. А если "hello!!!" туда не влезет? Как раз для этого передавался size, но его забыли использовать :-)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Либо как раньше в виндовс делали, вызывать функцию 2 раза. Первый раз с пустым указателем в качестве параметра, тогда она только отдает размер необходимого буфера. Потом запрашивать память нужного размера и вызывать функцию второй раз, уже с правильным указателем, который она в итоге и заполнит. В любом случае за распределением/освобождением памяти должна следить вызывающая функция. Часто применяется в вызовах драйверов IOCtl, которые любят отдавать структурки разной длины

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

ЕвгенийП пишет:

Не, ну так нельзя. А если "hello!!!" туда не влезет? Как раз для этого передавался size, но его забыли использовать :-)

Я и сделал специально "hello!!!" длиннее, а при объявлении arr_in выделил больше ячеек. Или не правильно?

С защитой от переполнения.

#define lenArr(sizedArr) sizeof(sizedArr)/sizeof(*sizedArr)

void arr_remake(char arr[], const int size) {
	char arr_out[]{"hello!!!"};
	if (strlen(arr_out) < (size-1)) 
           strcpy(arr, arr_out);
}

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

	char arr_in[30]{"abcdrt"}; //массив буфер достсточного размера
	Serial.print("arr_in= "); Serial.print(arr_in); Serial.print("\tlenStr= "); Serial.println(strlen(arr_in));
	arr_remake(arr_in, lenArr(arr_in));
	Serial.print("arr_in= "); Serial.print(arr_in); Serial.print("\tlenStr= "); Serial.println(strlen(arr_in));
}

void loop() {}

 

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

dune10991 пишет:

Ещё, если я не ошибаюсь, ваша функция удаляет служебный символ окончания строки. Хотя может и ошибаюсь.

dune10991
Offline
Зарегистрирован: 13.04.2018

AndreyD пишет:

dune10991 пишет:

Ещё, если я не ошибаюсь, ваша функция удаляет служебный символ окончания строки. Хотя может и ошибаюсь.

короче открывать книгу по С++ и "лопатить"

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

У меня вот такая функция работает, но на правильность не претендую, сам только учусь.

void arr_remake(char arr[]) {
	for (uint8_t i = 0; i < strlen(arr); i++)
		arr[i] = toupper(arr[i]);
}

 

dune10991
Offline
Зарегистрирован: 13.04.2018

AndreyD пишет:

У меня вот такая функция работает, но на правильность не претендую, сам только учусь.

void arr_remake(char arr[]) {
	for (uint8_t i = 0; i < strlen(arr); i++)
		arr[i] = toupper(arr[i]);
}

 

тоже пришел к подобному варианту. осталось понять, будет ли работать с массивами разного размера. так как на выходе может быть массив от 16 до 100 символов. 

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

AndreyD пишет:

У меня вот такая функция работает, но на правильность не претендую, сам только учусь.

void arr_remake(char arr[]

А вот нахера тут strlen(arr); нужно- непонятно.

 

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

mykaida пишет:

AndreyD пишет:

У меня вот такая функция работает, но на правильность не претендую, сам только учусь.

void arr_remake(char arr[]

А вот нахера тут strlen(arr); нужно- непонятно.

Чтобы размер массива не передавать в функцию, а стоповый символ там по любому будет.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

AndreyD пишет:
Чтобы размер массива не передавать в функцию, а стоповый символ там по любому будет.

Ну я не знаю - возможно нас тогда неправильно учили программированию, но нам вдалбливали - "надо делать меньше операций". А зачем каждый раз вычислять длинну массива, если Вы ее и так знаете? Передайте...

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

mykaida пишет:

Ну я не знаю - возможно нас тогда неправильно учили программированию, но нам вдалбливали - "надо делать меньше операций". А зачем каждый раз вычислять длинну массива, если Вы ее и так знаете? Передайте...

Я задачу ТС понял так, что в функцию поступает массив char в виде строки и каждый раз строка может быть разной длинны, а в самой функции строчные буквы заменяются на заглавные.

Вот мой вариант решения на примере одной строки. Размер вычисляется один раз.

void arr_remake(char arr[]) {
	for (uint8_t i = 0; i < strlen(arr); i++)
		arr[i] = toupper(arr[i]);
}

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

	char arr_in[]{"abcdrt"};
	Serial.print("arr_in= "); Serial.print(arr_in); 
	arr_remake(arr_in);
	Serial.print("arr_in= "); Serial.print(arr_in); 
}

void loop() {}

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

AndreyD пишет:

Я задачу ТС понял так, что в функцию поступает массив char в виде строки и каждый раз строка может быть разной длинны, а в самой функции строчные буквы заменяются на заглавные.

А зачем в строке 2 вычислять строку массива каждый раз? Один раз в локальную переменную нельзя вычислить? Зажрались вы со скоростью вычислений!

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

mykaida пишет:

AndreyD пишет:

Я задачу ТС понял так, что в функцию поступает массив char в виде строки и каждый раз строка может быть разной длинны, а в самой функции строчные буквы заменяются на заглавные.

А зачем в строке 2 вычислять строку массива каждый раз? Один раз в локальную переменную нельзя вычислить? Зажрались вы со скоростью вычислений!

А, да, дошло до меня.

void arr_remake(char arr[]) {
	uint8_t len = strlen(arr);
	for (uint8_t i = 0; i < len; i++)
		arr[i] = toupper(arr[i]);
}

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

	char arr_in[]{"abcdrt"};
	Serial.print("arr_in= "); Serial.println(arr_in); 
	arr_remake(arr_in);
	Serial.print("arr_in= "); Serial.println(arr_in); 
}

void loop() {}

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

AndreyD пишет:

Вот мой вариант решения на примере одной строки. Размер вычисляется один раз.

А вот мой. Размер не имеет значения

#include <string.h>
void setup() {
	Serial.begin(9600);

	char arr_in[]{"abcdrt"};
	Serial.print("arr_in= "); Serial.print(arr_in); 
	strupr(arr_in);
	Serial.print("arr_in= "); Serial.print(arr_in); 
}

void loop() {}

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

AndreyD пишет:

А, да, дошло до меня.

Отлично! Но точно, что там меньше длины массива? Или равно? Или меньше и равно?

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

mykaida пишет:

AndreyD пишет:

А, да, дошло до меня.

Отлично! Но точно, что там меньше длины массива? Или равно? Или меньше и равно?

 Там же не длинна массива, а длинна строки, '\0' мы не трогаем, он так и останется в arr_in[].

DetSimen пишет:

Да, так лучше, но ТС хотел разобраться в обработке массива функцией. А там потом может и и придётся и с размером выходного массива, что-то "придумывать", смотря как входящий массив будет обрабатываться.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

AndreyD пишет:
Там же не длинна массива, а длинна строки, '\0' мы не трогаем, он так и останется в arr_in[].

Рад за Вас! Вот пусть теперь ТС это поймет.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DetSimen пишет:
Размер вычисляется один раз.
Размер всегда имеет значение! :-)

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

Более интересно, когда на входе строка, длинна строки неизвестна, возможный максимальный размер тоже неизвестен.

Нужно передать эту строку в функцию для обработки, при этом получиться строка большей длинны. (в коде я увеличил строку на один символ)

Правильно вот так или я где-то ошибся, или можно оптимальнее?

#define lenArr(sizedArr) sizeof(sizedArr)/sizeof(*sizedArr)

char* arr_remake(char arr[]) {
	uint8_t len = strlen(arr);
	char* newArr = new char[len+2];
	strcpy(newArr, arr);
	for (uint8_t i = 0; i < len; i++)
		newArr[i] = toupper(arr[i]);
	newArr[len] = '1';
	newArr[len + 1] = '\0';
	delete[] arr;
	return newArr;
}

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

	uint8_t lenArrIn = lenArr("abcdrt");
	char* arrIn = new char[lenArrIn];
	strcpy(arrIn, "abcdrt");

	Serial.print("arrIn= "); Serial.print(arrIn); Serial.print("\tarrLen= "); Serial.println(lenArrIn);
	
    char* arrOut = arr_remake(arrIn);

	Serial.print("arrOut= "); Serial.print(arrOut); Serial.print("\tarrLen= "); Serial.println(strlen(arrOut)+1);

        delete[] arrOut;
}

void loop() {}

 

dune10991
Offline
Зарегистрирован: 13.04.2018

AndreyD пишет:

Более интересно, когда на входе строка, длинна строки неизвестна, возможный максимальный размер тоже неизвестен.

Нужно передать эту строку в функцию для обработки, при этом получиться строка большей длинны. (в коде я увеличил строку на один символ)

Правильно вот так или я где-то ошибся, или можно оптимальнее?

#define lenArr(sizedArr) sizeof(sizedArr)/sizeof(*sizedArr)

char* arr_remake(char arr[]) {
	uint8_t len = strlen(arr);
	char* newArr = new char[len+2];
	strcpy(newArr, arr);
	for (uint8_t i = 0; i < len; i++)
		newArr[i] = toupper(arr[i]);
	newArr[len] = '1';
	newArr[len + 1] = '\0';
	delete[] arr;
	return newArr;
}

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

	uint8_t lenArrIn = lenArr("abcdrt");
	char* arrIn = new char[lenArrIn];
	strcpy(arrIn, "abcdrt");

	Serial.print("arrIn= "); Serial.print(arrIn); Serial.print("\tarrLen= "); Serial.println(lenArrIn);
	
    char* arrOut = arr_remake(arrIn);

	Serial.print("arrOut= "); Serial.print(arrOut); Serial.print("\tarrLen= "); Serial.println(strlen(arrOut)+1);

        delete[] arrOut;
}

void loop() {}

Вставьте ваш код в loop и будет тоже самое, про что я говорил. Память ардуинки за 30 секунд забьется.
Т.е. delete[] arr; не спасает.

Т.е. если функция просто преобразовывает массив что в глобальной области видимости , то все хорошо.
А вот если массив объявляется в функции, то память сжирается. delete[] arr не должна очищать?
Понять не могу, в какие адреса памяти пишется массив. 
В С++ это просто можно узнать с помощью cout<<&arr, а на ардуино Serial.println(&arr) вызывает ошибку

А вообще благодаря обсуждению, разобрался частично. Ну изменить массив функцией void.

В принципе на данный момент мне этого достаточно.
 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dune10991 пишет:

Т.е. delete[] arr; не спасает.

Почему не спасает?

dune10991 пишет:

А вот если массив объявляется в функции, то память сжирается. delete[] arr не должна очищать?

Вы, что так ничего и не поняли? Нормально delete всё освобождает, если её вызывать, Вы же просто НЕ вызываете delete!!!

Вам про это писали несколько раз, см. посты #1#2#4

Неужели Вы не поняли, что вся Ваша проблема в том, что Вы прост НЕ ВЫЗЫВАЕТЕ delete? Потому она и не освобождает память. Вызвали бы - освободила бы!

dune10991 пишет:

В С++ это просто можно узнать с помощью cout<<&arr, а на ардуино Serial.println(&arr) вызывает ошибку

А на ардуино какой язык? Вы не поверите, но С++. У методов print просто нет такой перегрузки. Поставьте преобразование к числу - всё выведется - Serial.println((unsigned)(&arr))

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

dune10991 пишет:

Вставьте ваш код в loop и будет тоже самое, про что я говорил. Память ардуинки за 30 секунд забьется.
Т.е. delete[] arr; не спасает.

Приведённая вами функция расчёта свободной памяти её уменьшения не показывает.

#define lenArr(sizedArr) sizeof(sizedArr)/sizeof(*sizedArr)

int freeRam()
{
	extern int __heap_start, * __brkval;
	int v;
	return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
}

char* arr_remake(char arr[]) {
	uint8_t len = strlen(arr);
	char* newArr = new char[len+2];
	strcpy(newArr, arr);
	delete[] arr;
	for (uint8_t i = 0; i < len; i++)
		newArr[i] = toupper(newArr[i]);
	newArr[len] = '1';
	newArr[len + 1] = '\0';
	
	return newArr;
}

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

void loop() {

	uint8_t lenArrIn = lenArr("abcdrt");
	char* arrIn = new char[lenArrIn];
	strcpy(arrIn, "abcdrt");

	Serial.print("arrIn= "); Serial.print(arrIn); Serial.print("\tarrLen= "); Serial.println(lenArrIn);

	char* arrOut = arr_remake(arrIn);

	Serial.print("arrOut= "); Serial.print(arrOut); Serial.print("\tarrLen= "); Serial.println(strlen(arrOut) + 1);

	delete[] arrOut;

	Serial.print("freeRam= "); Serial.println(freeRam());

	delay(1000);

}

 

dune10991
Offline
Зарегистрирован: 13.04.2018

1) я знаю, что С++, но все синтаксис отличается
2) с памятью разобрался) Надо массив массив уничтожить и в loop

dune10991
Offline
Зарегистрирован: 13.04.2018

Уже разобрался! Спасибо за помощь)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dune10991 пишет:

1) я знаю, что С++, но все синтаксис отличается

Нет. Не отличается ни на одну запятую и ни на один пробел.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AndreyD пишет:

Чтобы размер массива не передавать в функцию, а стоповый символ там по любому будет.

Это неверный подход к программированию.

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

andriano пишет:

AndreyD пишет:

Чтобы размер массива не передавать в функцию, а стоповый символ там по любому будет.

Это неверный подход к программированию.

Ну, да, для общего случая, массив в функцию передаётся по указателю, а как я понял по указателю размер массива определить нельзя, поэтому нужно передавать в функцию и размер. Но меня заинтересовал момент, если это массив char последний элемент которого нуль-терминатор, тогда получается, что размер массива можно определить и по указателю, т.е. он будет равен strlen(arr)+1.

Так же если в функции создан динамический массив char с нуль-терминатором, а функция возвращает указатель на него, по этому указателю можно определить его размер.

 

А как delete[] "узнаёт" сколько ячеек массива в памяти нужно очистить? Мы же ему указатель на массив даём.

b707
Offline
Зарегистрирован: 26.05.2017

AndreyD пишет:

А как delete[] "узнаёт" сколько ячеек массива в памяти нужно очистить? Мы же ему указатель на массив даём.

функция new сохраняет данные о размере выделенной области памяти.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AndreyD пишет:

А как delete[] "узнаёт" сколько ячеек массива в памяти нужно очистить? Мы же ему указатель на массив даём.

А как Вы думаете, почему если запросить через new один байт, свободная память уменьшается на три? Чиновники что ли два байта тырят?

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

b707 пишет:

AndreyD пишет:

А как delete[] "узнаёт" сколько ячеек массива в памяти нужно очистить? Мы же ему указатель на массив даём.

функция new сохраняет данные о размере выделенной области памяти.

ЕвгенийП пишет:

А как Вы думаете, почему если запросить через new один байт, свободная память уменьшается на три? Чиновники что ли два байта тырят?

А во время работы с массивом эти данные нельзя как-то запросить?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AndreyD пишет:

А во время работы с массивом эти данные нельзя как-то запросить?

Каике ЭТИ?

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

ЕвгенийП пишет:

Каике ЭТИ?

Данные, которые сохраняет функция new о размере выделенной области памяти. Они же где-то хранятся до удаления динамического массива, значит их можно прочитать.

Уточню, я про передачу массива в функцию без передачи размера массива.

 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Если запрашивали через new/malloc/calloc, то, конечно, можно узнать размер. delete и free как-то же узнают.

Запускайте, смотрите:

#define printVar(x) do { Serial.print(#x); Serial.print('='); Serial.println(x); } while (false)

static inline size_t getSize(void * p) { 
	return * (reinterpret_cast<size_t *>(p) - 1);
}

void setup(void) {
	Serial.begin(57600);
	char * a = new char[13];
	char * b = new char[21];
	long * c = new long[5];
	printVar(getSize(a));
	printVar(getSize(b));
	printVar(getSize(c));
}

void loop(void) {}

 

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

ЕвгенийП пишет:

Если запрашивали через new/malloc/calloc, то, конечно, можно узнать размер. delete и free как-то же узнают.

Запускайте, смотрите:

#define printVar(x) do { Serial.print(#x); Serial.print('='); Serial.println(x); } while (false)

static inline size_t getSize(void * p) { 
	return * (reinterpret_cast<size_t *>(p) - 1);
}

void setup(void) {
	Serial.begin(57600);
	char * a = new char[13];
	char * b = new char[21];
	long * c = new long[5];
	printVar(getSize(a));
	printVar(getSize(b));
	printVar(getSize(c));
}

void loop(void) {}

 

Буду разбираться, спасибо.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AndreyD пишет:

Ну, да, для общего случая, массив в функцию передаётся по указателю, а как я понял по указателю размер массива определить нельзя, поэтому нужно передавать в функцию и размер. Но меня заинтересовал момент, если это массив char последний элемент которого нуль-терминатор, тогда получается, что размер массива можно определить и по указателю, т.е. он будет равен strlen(arr)+1.

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

- она не должна делать лишней работы,

- она должна корректно обрабатывать неверные данные, т.е. не должна аварийно завершаться, не должна "распахивать" память и т.п.

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

andriano пишет:

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

- она не должна делать лишней работы,

- она должна корректно обрабатывать неверные данные, т.е. не должна аварийно завершаться, не должна "распахивать" память и т.п.

Шаг в право, шаг в лева - попытка побега, прыжок на месте - попытка улететь (с)

Думаю я вашу мысль понял, но интересно же поэкспериментировать.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

С ПДД Вам тоже интересно поэкспериментировать?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AndreyD пишет:

Буду разбираться, спасибо.

Надеюсь, Вы понимаете, что это голимый говнокод.

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

Вот так грамотнее? На примере числового массива.

uint8_t * arrRemake(uint8_t arr[], uint8_t &lenArr) {
	uint8_t* newArr = new uint8_t[lenArr+1];
	for (uint8_t i=0; i < lenArr; i++) newArr[i] = arr[i];
	delete[] arr; arr = nullptr;
	newArr[lenArr] = 5;
	lenArr = lenArr + 1;
	return newArr;
}

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

	uint8_t lenArr = 5;
	uint8_t* arrIn = new uint8_t[lenArr];
	for (uint8_t i = 0; i < lenArr; i++) arrIn[i] = i;

	Serial.print("arrIn= "); 
	for (uint8_t i; i < lenArr; i++) {
		Serial.print(arrIn[i]);
		Serial.print(" ");
	}
	Serial.println();

	uint8_t* arrOut = arrRemake(arrIn, lenArr);

	Serial.print("arrOut= "); 
	for (uint8_t i; i < lenArr; i++) {
		Serial.print(arrOut[i]);
		Serial.print(" ");
	}
	Serial.println();

	delete[] arrOut; arrOut = nullptr;
}

void loop() {}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AndreyD пишет:

Вот так грамотнее? 

Так - вообще ужас.

Вот здесь почитайте про работу с памятью, а, главное, обязательно возьмите библиотеку MemoryExplorer и посмотрите, что у Вас творится с фрагментацией памяти.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

AndreyD пишет:

Вот так грамотнее? На примере числового массива.

Андрейка, не сочти за нравоучения, это моё IMHO, но я щитаю, что в Си массив должен и вести себя как массив, т.е, как заложено отцами основателями, иметь постоянный размер в течение всего времени своей нехитрой жизни.  А если что-то удаляется, добавляется, меняет по 10 раз в день свой размер - это надо организовывать в список. Исключение составляют только строки aka массив символов. 

AndreyD
AndreyD аватар
Offline
Зарегистрирован: 07.10.2018

DetSimen пишет:

Андрейка, не сочти за нравоучения, это моё IMHO, но я щитаю, что в Си массив должен и вести себя как массив, т.е, как заложено отцами основателями, иметь постоянный размер в течение всего времени своей нехитрой жизни.  А если что-то удаляется, добавляется, меняет по 10 раз в день свой размер - это надо организовывать в список. Исключение составляют только строки aka массив символов. 

До умных указателей и списков я ещё не добрался в изучении. Выше хотел закрепить своё понимание ссылок и указателей. Буду изучать.