Утекание памяти при копировании массива
- Войдите на сайт для отправки комментариев
Сб, 09/01/2021 - 14:17
Может кто-то подскажет, куда "копать".
Короче есть необходимость из функции передавать массив.
В принципе это получается. Но есть одно но, через какое-то время вместо возвращенного массива лезет какая-то чушь.
Возникла мысль, что память забивается. Нашел функцию для проверки оставшейся озу мк. В принципе так и получается.
Но что в коде не так, не могу разобраться.
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); }
строки 20-21 ты из функции выходишь раньше, чем уничтожаешь массив.
И вапще, так массив не возвращают
Как, по вашему мнению, работают строки 20 и 21?
Но это первое. Второе - не надо создавать новый массив и возвращать его. Манипулируйте переданным в функцию.
ТС почитай про ссылки и указатели.
Тебе они нужны.
Вы выделяете память под массив внутри функции, но никогда её не освобождаете.
И вообще, так это не делается. Но чтобы объяснять как делается, нужно понимать что нужно сделать, а Вы забыли про это написать.
Передайте указатель на массив, преобразуйте его. А лучше передайте основной программой в функцию каждый элемент массива и преобразуйте его.
Вы выделяете память под массив внутри функции, но никогда её не освобождаете.
И вообще, так это не делается. Но чтобы объяснять как делается, нужно понимать что нужно сделать, а Вы забыли про это написать.
Если про то, что требуется вообще, то:
внутри функции принимаются данные из серийного порта (в моем случае по BT) и функция должна возвращать эти данные. В моем случае необходимо передавать строковые массивы.
Ну и вообще понять, как возвращать строковый массив из функции.
Ну и вообще понять, как возвращать строковый массив из функции.
Или передавать ей уже готовый для заполнения, а она только заполняет, или внутри функции запрашивать память, возвращать, а в вызывающей функции эту память освобождать, когда она больше не нужна.
Вот набросал пример первого варианта, и я сам потренировался.
Не, ну так нельзя. А если "hello!!!" туда не влезет? Как раз для этого передавался size, но его забыли использовать :-)
Либо как раньше в виндовс делали, вызывать функцию 2 раза. Первый раз с пустым указателем в качестве параметра, тогда она только отдает размер необходимого буфера. Потом запрашивать память нужного размера и вызывать функцию второй раз, уже с правильным указателем, который она в итоге и заполнит. В любом случае за распределением/освобождением памяти должна следить вызывающая функция. Часто применяется в вызовах драйверов IOCtl, которые любят отдавать структурки разной длины
Не, ну так нельзя. А если "hello!!!" туда не влезет? Как раз для этого передавался size, но его забыли использовать :-)
Я и сделал специально "hello!!!" длиннее, а при объявлении arr_in выделил больше ячеек. Или не правильно?
С защитой от переполнения.
Ещё, если я не ошибаюсь, ваша функция удаляет служебный символ окончания строки. Хотя может и ошибаюсь.
Ещё, если я не ошибаюсь, ваша функция удаляет служебный символ окончания строки. Хотя может и ошибаюсь.
короче открывать книгу по С++ и "лопатить"
У меня вот такая функция работает, но на правильность не претендую, сам только учусь.
У меня вот такая функция работает, но на правильность не претендую, сам только учусь.
тоже пришел к подобному варианту. осталось понять, будет ли работать с массивами разного размера. так как на выходе может быть массив от 16 до 100 символов.
У меня вот такая функция работает, но на правильность не претендую, сам только учусь.
А вот нахера тут strlen(arr); нужно- непонятно.
У меня вот такая функция работает, но на правильность не претендую, сам только учусь.
А вот нахера тут strlen(arr); нужно- непонятно.
Чтобы размер массива не передавать в функцию, а стоповый символ там по любому будет.
Ну я не знаю - возможно нас тогда неправильно учили программированию, но нам вдалбливали - "надо делать меньше операций". А зачем каждый раз вычислять длинну массива, если Вы ее и так знаете? Передайте...
Ну я не знаю - возможно нас тогда неправильно учили программированию, но нам вдалбливали - "надо делать меньше операций". А зачем каждый раз вычислять длинну массива, если Вы ее и так знаете? Передайте...
Я задачу ТС понял так, что в функцию поступает массив char в виде строки и каждый раз строка может быть разной длинны, а в самой функции строчные буквы заменяются на заглавные.
Вот мой вариант решения на примере одной строки. Размер вычисляется один раз.
Я задачу ТС понял так, что в функцию поступает массив char в виде строки и каждый раз строка может быть разной длинны, а в самой функции строчные буквы заменяются на заглавные.
А зачем в строке 2 вычислять строку массива каждый раз? Один раз в локальную переменную нельзя вычислить? Зажрались вы со скоростью вычислений!
Я задачу ТС понял так, что в функцию поступает массив char в виде строки и каждый раз строка может быть разной длинны, а в самой функции строчные буквы заменяются на заглавные.
А зачем в строке 2 вычислять строку массива каждый раз? Один раз в локальную переменную нельзя вычислить? Зажрались вы со скоростью вычислений!
А, да, дошло до меня.
Вот мой вариант решения на примере одной строки. Размер вычисляется один раз.
А вот мой. Размер не имеет значения
А, да, дошло до меня.
Отлично! Но точно, что там меньше длины массива? Или равно? Или меньше и равно?
А, да, дошло до меня.
Отлично! Но точно, что там меньше длины массива? Или равно? Или меньше и равно?
Там же не длинна массива, а длинна строки, '\0' мы не трогаем, он так и останется в arr_in[].
Да, так лучше, но ТС хотел разобраться в обработке массива функцией. А там потом может и и придётся и с размером выходного массива, что-то "придумывать", смотря как входящий массив будет обрабатываться.
Рад за Вас! Вот пусть теперь ТС это поймет.
Более интересно, когда на входе строка, длинна строки неизвестна, возможный максимальный размер тоже неизвестен.
Нужно передать эту строку в функцию для обработки, при этом получиться строка большей длинны. (в коде я увеличил строку на один символ)
Правильно вот так или я где-то ошибся, или можно оптимальнее?
Более интересно, когда на входе строка, длинна строки неизвестна, возможный максимальный размер тоже неизвестен.
Нужно передать эту строку в функцию для обработки, при этом получиться строка большей длинны. (в коде я увеличил строку на один символ)
Правильно вот так или я где-то ошибся, или можно оптимальнее?
Вставьте ваш код в loop и будет тоже самое, про что я говорил. Память ардуинки за 30 секунд забьется.
Т.е. delete[] arr; не спасает.
Т.е. если функция просто преобразовывает массив что в глобальной области видимости , то все хорошо.
А вот если массив объявляется в функции, то память сжирается. delete[] arr не должна очищать?
Понять не могу, в какие адреса памяти пишется массив.
В С++ это просто можно узнать с помощью cout<<&arr, а на ардуино Serial.println(&arr) вызывает ошибку
А вообще благодаря обсуждению, разобрался частично. Ну изменить массив функцией void.
В принципе на данный момент мне этого достаточно.
Т.е. delete[] arr; не спасает.
Почему не спасает?
А вот если массив объявляется в функции, то память сжирается. delete[] arr не должна очищать?
Вы, что так ничего и не поняли? Нормально delete всё освобождает, если её вызывать, Вы же просто НЕ вызываете delete!!!
Вам про это писали несколько раз, см. посты #1, #2, #4
Неужели Вы не поняли, что вся Ваша проблема в том, что Вы прост НЕ ВЫЗЫВАЕТЕ delete? Потому она и не освобождает память. Вызвали бы - освободила бы!
В С++ это просто можно узнать с помощью cout<<&arr, а на ардуино Serial.println(&arr) вызывает ошибку
А на ардуино какой язык? Вы не поверите, но С++. У методов print просто нет такой перегрузки. Поставьте преобразование к числу - всё выведется - Serial.println((unsigned)(&arr))
Вставьте ваш код в loop и будет тоже самое, про что я говорил. Память ардуинки за 30 секунд забьется.
Т.е. delete[] arr; не спасает.
Приведённая вами функция расчёта свободной памяти её уменьшения не показывает.
1) я знаю, что С++, но все синтаксис отличается
2) с памятью разобрался) Надо массив массив уничтожить и в loop
Уже разобрался! Спасибо за помощь)
1) я знаю, что С++, но все синтаксис отличается
Нет. Не отличается ни на одну запятую и ни на один пробел.
Чтобы размер массива не передавать в функцию, а стоповый символ там по любому будет.
Это неверный подход к программированию.
Чтобы размер массива не передавать в функцию, а стоповый символ там по любому будет.
Это неверный подход к программированию.
Ну, да, для общего случая, массив в функцию передаётся по указателю, а как я понял по указателю размер массива определить нельзя, поэтому нужно передавать в функцию и размер. Но меня заинтересовал момент, если это массив char последний элемент которого нуль-терминатор, тогда получается, что размер массива можно определить и по указателю, т.е. он будет равен
strlen(arr)+1.
Так же если в функции создан динамический массив char с нуль-терминатором, а функция возвращает указатель на него, по этому указателю можно определить его размер.
А как delete[] "узнаёт" сколько ячеек массива в памяти нужно очистить? Мы же ему указатель на массив даём.
А как delete[] "узнаёт" сколько ячеек массива в памяти нужно очистить? Мы же ему указатель на массив даём.
функция new сохраняет данные о размере выделенной области памяти.
А как delete[] "узнаёт" сколько ячеек массива в памяти нужно очистить? Мы же ему указатель на массив даём.
А как Вы думаете, почему если запросить через new один байт, свободная память уменьшается на три? Чиновники что ли два байта тырят?
А как delete[] "узнаёт" сколько ячеек массива в памяти нужно очистить? Мы же ему указатель на массив даём.
функция new сохраняет данные о размере выделенной области памяти.
А как Вы думаете, почему если запросить через new один байт, свободная память уменьшается на три? Чиновники что ли два байта тырят?
А во время работы с массивом эти данные нельзя как-то запросить?
А во время работы с массивом эти данные нельзя как-то запросить?
Каике ЭТИ?
Каике ЭТИ?
Данные, которые сохраняет функция new о размере выделенной области памяти. Они же где-то хранятся до удаления динамического массива, значит их можно прочитать.
Уточню, я про передачу массива в функцию без передачи размера массива.
Если запрашивали через new/malloc/calloc, то, конечно, можно узнать размер. delete и free как-то же узнают.
Запускайте, смотрите:
Если запрашивали через new/malloc/calloc, то, конечно, можно узнать размер. delete и free как-то же узнают.
Запускайте, смотрите:
Буду разбираться, спасибо.
Ну, да, для общего случая, массив в функцию передаётся по указателю, а как я понял по указателю размер массива определить нельзя, поэтому нужно передавать в функцию и размер. Но меня заинтересовал момент, если это массив char последний элемент которого нуль-терминатор, тогда получается, что размер массива можно определить и по указателю, т.е. он будет равен
strlen(arr)+1.
Вообще-то программирование существует уже далеко не первый год и за это время выработались определенные подходы к тому, что следует считать правильной программой. В числе прочего:
- она не должна делать лишней работы,
- она должна корректно обрабатывать неверные данные, т.е. не должна аварийно завершаться, не должна "распахивать" память и т.п.
Вообще-то программирование существует уже далеко не первый год и за это время выработались определенные подходы к тому, что следует считать правильной программой. В числе прочего:
- она не должна делать лишней работы,
- она должна корректно обрабатывать неверные данные, т.е. не должна аварийно завершаться, не должна "распахивать" память и т.п.
Шаг в право, шаг в лева - попытка побега, прыжок на месте - попытка улететь (с)
Думаю я вашу мысль понял, но интересно же поэкспериментировать.
С ПДД Вам тоже интересно поэкспериментировать?
Буду разбираться, спасибо.
Надеюсь, Вы понимаете, что это голимый говнокод.
Вот так грамотнее? На примере числового массива.
Вот так грамотнее?
Так - вообще ужас.
Вот здесь почитайте про работу с памятью, а, главное, обязательно возьмите библиотеку MemoryExplorer и посмотрите, что у Вас творится с фрагментацией памяти.
Вот так грамотнее? На примере числового массива.
Андрейка, не сочти за нравоучения, это моё IMHO, но я щитаю, что в Си массив должен и вести себя как массив, т.е, как заложено отцами основателями, иметь постоянный размер в течение всего времени своей нехитрой жизни. А если что-то удаляется, добавляется, меняет по 10 раз в день свой размер - это надо организовывать в список. Исключение составляют только строки aka массив символов.
Андрейка, не сочти за нравоучения, это моё IMHO, но я щитаю, что в Си массив должен и вести себя как массив, т.е, как заложено отцами основателями, иметь постоянный размер в течение всего времени своей нехитрой жизни. А если что-то удаляется, добавляется, меняет по 10 раз в день свой размер - это надо организовывать в список. Исключение составляют только строки aka массив символов.
До умных указателей и списков я ещё не добрался в изучении. Выше хотел закрепить своё понимание ссылок и указателей. Буду изучать.