Очистка памяти после создания двумерного «непрерывного в памяти» массива
Допустим, хочется в C99 (в С++ такой способ тоже сработает) хочется создать двумерный массив в «непрерывной!» области памяти, чтобы в дальнейшем обращаться к его элементам как a[i][j] :
#include #include int main() < int n = 12; double (*a)[n] = (double (*)[n])malloc(n * n * sizeof(double)) a[11][0] = 40.0; printf("a[11][0] = %4.2f\n", a[11][0]); // выход за границу массива с заползанием в следующий блок: a[10][12] = 50.0; printf("a[11][0] = %4.2f\n", a[11][0]); printf("a[10][12] = %4.2f\n", a[10][12]); return 0; >
Подскажите, кто-нибудь, пожалуйста, как при помощи free() очистить память выделенного таким образом массива?
P.S. Казалось бы, что при создании подобного массива можно было бы описать его так:
#include #include int main() < int n = 12; // при присваивании, не выходя за границу массива, можно перезаписывать другие элементы: double (*b)[1] = (double (*)[1])malloc (n * n * sizeof(double)); b[11][0] = 40.0; printf("\nb[11][0] = %4.2f\n", b[11][0]); // перезаписывает значение b[11][0]: b[5][6] = 50.0; printf("b[11][0] = %4.2f\n", b[11][0]); printf("b[5][6] = %4.2f\n", b[5][6]); return 0; >
grem ★★★★★
16.03.17 14:41:41 MSK
← 1 2 →
что это была за херня такая? ты что написал вообще.
покайся, создай обычный массив необходимого размера(N*M) и массив указателей на строки(N). можешь даже одним вызовом маллока это сделать, я разрешаю.
ckotinko ☆☆☆
( 16.03.17 14:45:31 MSK )
Создай одномерный массив и с помощью адресной арифметики работай с ним как с двумерным
kasha
( 16.03.17 14:47:22 MSK )
как при помощи free() очистить память выделенного таким образом массива?
free(a);
На самом деле это расширение в C++.
xaizek ★★★★★
( 16.03.17 14:50:10 MSK )
Последнее исправление: xaizek 16.03.17 14:51:15 MSK (всего исправлений: 1)
Ответ на: комментарий от kasha 16.03.17 14:47:22 MSK
Создай одномерный массив и с помощью адресной арифметики работай с ним как с двумерным
«Этим нас не удивишь!». Я ж сразу написал, что хотеть обращение к элементу как a[i][j] , а не a[n*i+j] , но чтобы в памяти массив (в данном случае он тоже линейный, а иначе и быть не может), лежал сплошным куском. При выделении в цикле его разбросает в куче как получится, разве не так?
grem ★★★★★
( 16.03.17 14:52:10 MSK ) автор топика
Наркомания. Последние стандарты C оставляют после себя стойкое ощущение, что пишут их какие-то упоротые.
Gvidon ★★★★
( 16.03.17 14:58:43 MSK )
Ответ на: комментарий от xaizek 16.03.17 14:50:10 MSK
Хм, осталось вспомнить, чего он у меня крашился раньше в дебагере при таком вызове 🙁 Сейчас не крашится, но после такой «очистки» элементу массива всё равно можно присвоить новое значение и вывести его. B программа даже не падает.
Угу, в С++ через расширение, так как malloc не его родная функция.
а вот для одномерного при такой очистке падает:
double *cc = (double*) malloc(sizeof(double)); cc[0] = 2.0; printf("cc = %4.2f\n", cc[0]); free(cc); cc[0]=3333.0; printf("cc = %4.2f\n", cc[0]);
grem ★★★★★
( 16.03.17 15:03:36 MSK ) автор топика
Последнее исправление: grem 16.03.17 15:10:52 MSK (всего исправлений: 2)
Ответ на: комментарий от grem 16.03.17 15:03:36 MSK
после такой «очистки» элементу массива всё равно можно присвоить новое значение и вывести его.
потому что библиотека закешировала сначала выделенные процессу страницы памяти и освобожденные потом, т.е. с точки зрения ядра эта память все еще принадлежит процессу
anonymous
( 16.03.17 15:13:24 MSK )
Ответ на: комментарий от grem 16.03.17 14:52:10 MSK
Ну так напишите класс, который будет абстрагировать арифметику указателей.
RazrFalcon ★★★★★
( 16.03.17 15:14:12 MSK )
Ответ на: комментарий от grem 16.03.17 15:03:36 MSK
а вот для одномерного при такой очистке падает:
ну, он же падает не на free(), а на следующей строке
anonymous
( 16.03.17 15:16:23 MSK )
Ответ на: комментарий от grem 16.03.17 15:03:36 MSK
Угу, в С++ через расширение, так как malloc не его родная функция.
Родная. Но VLA в C++ нет.
а вот для одномерного при такой очистке падает
free() это освобождение, а не очистка. Память после free() нельзя использовать.
xaizek ★★★★★
( 16.03.17 15:21:54 MSK )
Ответ на: комментарий от anonymous 16.03.17 15:16:23 MSK
да, т.к. уже, видимо, освободил память и теперь там пытаюсь присвоить.
потому что библиотека закешировала сначала выделенные процессу страницы памяти и освобожденные потом, т.е. с точки зрения ядра эта память все еще принадлежит процессу
странно, fflush(stdout), не исправляет ситуации и в первом случае с массивом a всё равно выводит новые значения после очистки. Либо это не та функции для очистки кэша.
grem ★★★★★
( 16.03.17 15:31:45 MSK ) автор топика
Ответ на: комментарий от xaizek 16.03.17 15:21:54 MSK
как заставить программу ‘падать’ после присвоения нового значения для массива ‘a’ если уже было использовано free()?
grem ★★★★★
( 16.03.17 15:33:41 MSK ) автор топика
Ответ на: комментарий от RazrFalcon 16.03.17 15:14:12 MSK
Можно, что-нибудь, как мне подсказали, содержащее в виде
double & arr(i,j)
или просто прописать #define arr(i,j) arr=i*n+j
grem ★★★★★
( 16.03.17 15:38:29 MSK ) автор топика
Ответ на: комментарий от grem 16.03.17 15:31:45 MSK
странно, fflush(stdout), не исправляет ситуации
гы-гы, сделал мой день! 🙂
у потоков это называется буферизация, а не кеш, впрочем, ты и освобождение очисткой называешь, короче, тебе надо K&R прочитать внимательно раза три-четыре
anonymous
( 16.03.17 15:49:22 MSK )
Ответ на: комментарий от anonymous 16.03.17 15:49:22 MSK
Надо, надо. Как тогда буфер то очистить, т.е. сделать так, чтобы для созданного описанным выше способом массиве, действительно было видно в процессе выполнения (в виде падения программы), что память освободилась и присваивать новые значения элементам массива уже нельзя?
Для примера отсюда (Очистка памяти после создания двумерного «непрерывного в памяти» массива (комментарий)) приложение падает, как и ожидается. В исходном примере продолжает себе работать дальше с присвоением элементов, их суммированием и выводом на экран, словно free(a) и не вызывали.
grem ★★★★★
( 16.03.17 15:57:27 MSK ) автор топика
Ответ на: комментарий от grem 16.03.17 15:38:29 MSK
Не в коем случае.
RazrFalcon ★★★★★
( 16.03.17 15:58:37 MSK )
Ответ на: комментарий от grem 16.03.17 15:57:27 MSK
В исходном примере продолжает себе работать дальше с присвоением элементов, их суммированием и выводом на экран, словно free(a) и не вызывали.
не знаю, что такое «исходный пример», если речь о стартовом сообщении топика, то там два примера, и ни в одном нет ни суммирования, ни вызова free(), хотя присвоения некоторые есть, да.
anonymous
( 16.03.17 16:10:32 MSK )
Ответ на: комментарий от grem 16.03.17 15:33:41 MSK
Можно во время разработки/тестов использовать санитайзер и настроить на немедленное падение. Или запускать под valgrind. C и C++ сами по себе такое не делают, надо следить самому.
xaizek ★★★★★
( 16.03.17 16:13:01 MSK )
Ответ на: комментарий от anonymous 16.03.17 16:10:32 MSK
имеется ввиду, что если туда добавить
free(a); a[11][0] = 500000.0; printf("a[11][0] = %4.2f\n", a[11][0]); a[0][11] = a[11][0] + 1100000.0; printf("a[0][11] = %4.2f\n", a[0][11]);
то всё спокойно отрабатывает и выводит новые значения на экран. Можно, конечно, сразу после вызова free(a) добавить на всякий случай «a = NULL», тогда да, будет падать при попытке записать в что-нибуль в элемент массива. Почему-то фраза
Для избежания повреждения кучи некоторые руководства по языку Си рекомендуют обнулять каждый освобождаемый указатель.»
попалась пока только в википедии о_О
grem ★★★★★
( 16.03.17 16:20:47 MSK ) автор топика
Последнее исправление: grem 16.03.17 16:21:16 MSK (всего исправлений: 1)
Ответ на: комментарий от grem 16.03.17 16:20:47 MSK
Зачем ты постоянно пытаешься выстрелить себе в ногу ? Используй адресную арифметику, calloc(), valgrind, ну и по желанию
Для избежания повреждения кучи некоторые руководства по языку Си рекомендуют обнулять каждый освобождаемый указатель.»
И будет у тебя все хорошо. А то что делаешь ты называется use-after-free, и влечет за собой кучу проблем и багов.
joy4eg ★★★★★
( 16.03.17 16:27:47 MSK )
Последнее исправление: joy4eg 16.03.17 16:29:21 MSK (всего исправлений: 1)
Ответ на: комментарий от xaizek 16.03.17 15:21:54 MSK
Память после free() нельзя использовать.
Кажется, я начал что-то подозревать :). Free() указывает, что блок памяти свободен и туда теперь можно что-то записывать. Но при этом указатель «a» всё ещё продолжает указывать на эту же область памяти и туда, гипотетически, при определённых условиях, можно успеть записать новые значения и использовать их до обнуления указатели или до того, как этот участок памяти займёт кто-то другой?
grem ★★★★★
( 16.03.17 16:30:06 MSK ) автор топика
Ответ на: комментарий от joy4eg 16.03.17 16:27:47 MSK
Для избежания повреждения кучи некоторые руководства по языку Си рекомендуют обнулять каждый освобождаемый указатель.»
И будет у тебя все хорошо.
С таким «хорошо» лучше на яве программить и не лезть в C.
vodz ★★★★★
( 16.03.17 16:32:27 MSK )
Ответ на: комментарий от grem 16.03.17 16:30:06 MSK
Угу. Указатель сам по себе не обнулится. Он продолжает указывать туда же, но соответствующий блок памяти уже помечен как свободный. Проблема в том, что свободные блоки могут содержать служебную информацию о куче, которую можно разрушить выполнив запись. Так что после free() блока о нём надо забыть и не использовать.
xaizek ★★★★★
( 16.03.17 16:34:55 MSK )
Ответ на: комментарий от vodz 16.03.17 16:32:27 MSK
Все приходит с опытом 😉
joy4eg ★★★★★
( 16.03.17 16:42:14 MSK )
Ответ на: комментарий от joy4eg 16.03.17 16:27:47 MSK
И будет у тебя все хорошо. А то что делаешь ты называется use-after-free, и влечет за собой кучу проблем и багов.
Угу, поэтому меня это и насторожило. Наверное, из-за такого последующего присваивания элементам массива я и решил, что «free(a)» не совсем то, что мне было нужно для освобождения памяти занятой указателем. Немного смутило, что использование «free(*a)» тоже срабатывает (всё равно это одно и то же), поэтому при использовании «free(a)» у меня не было уверенности, что я вызвал внутри неё именно тот указатель и вся выделенная память действительно освободилась.
grem ★★★★★
( 16.03.17 16:51:45 MSK ) автор топика
Ответ на: комментарий от grem 16.03.17 16:20:47 MSK
то всё спокойно отрабатывает и выводит новые значения на экран.
почему так может происходить, тебе объяснили, но это всего лишь следствие конкретной реализации кучи, так что никаких гарантий, что обязательно упадет при использовании освобожденной памяти, или что точно не упадет в том же случае, просто нет и быть не может
не пойму, что ты хочешь то?
anonymous
( 16.03.17 16:57:37 MSK )
Ответ на: комментарий от anonymous 16.03.17 16:57:37 MSK
Уже всё более менее («не менее чем при создании темы») понятно стало, что нужно в обязательном порядке указатель обнулять. Но в том же K&R, Кочане, Прате, Дейтеле, при беглом осмотре, максимум что пишут, это проверять не равен ли указатель NULL после попытки выделить память, а про желательное обнуление указателей, во избежание случайного (или из-за опечатки) запихивания значений в свободную память ничего не попалось.
grem ★★★★★
( 16.03.17 17:18:31 MSK ) автор топика
Ответ на: комментарий от grem 16.03.17 16:51:45 MSK
Немного смутило, что использование «free(*a)» тоже срабатывает (всё равно это одно и то же)
всё равно это одно и то же
НЕТ! Это совершенно разные вещи!
joy4eg ★★★★★
( 16.03.17 17:23:13 MSK )
Ответ на: комментарий от xaizek 16.03.17 16:34:55 MSK
Так что после free() блока о нём надо забыть и не использовать.
Это само собой, но при опечатке в какой-нибудь длинной формуле в блоке с несколькими вложенными циклами парой строчек ниже можно случайно обратиться к такому элементу и программа может проскочить это место как ни в чём ни бывало. И искать это место, наверное, можно долго.
P.S. Всем спасибо.
grem ★★★★★
( 16.03.17 17:28:34 MSK ) автор топика
Ответ на: комментарий от grem 16.03.17 17:18:31 MSK
во избежание случайного (или из-за опечатки) запихивания значений в свободную память ничего не попалось.
Потому что это бред. Присваивание 0 самому указателю это защита от prt[0. page_size/sizeof(*ptr)] и нисколько вас не защитит от скрытой ошибки присваивания в ptr[1000]. Не нужно оно вам — так и забудьте о этом указателе.
vodz ★★★★★
( 16.03.17 17:30:17 MSK )
Ответ на: комментарий от joy4eg 16.03.17 17:23:13 MSK
В дебаггере у них отображался один и тот же адрес. Мне нужно больше спать. Что из этого тогда дейтсвительно полностью освобождает память на выделенный double (*a)[n] = (double (*)[n])malloc(n * sizeof(double)); ?
grem ★★★★★
( 16.03.17 17:31:28 MSK ) автор топика
Ответ на: комментарий от vodz 16.03.17 17:30:17 MSK
Спасибо. Обдумаю это получше, когда чуть лучше высплюсь, уже ничего не соображаю.
grem ★★★★★
( 16.03.17 17:33:47 MSK ) автор топика
Ответ на: комментарий от grem 16.03.17 17:31:28 MSK
Вполне достаточно просто free(a).
joy4eg ★★★★★
( 16.03.17 17:37:27 MSK )
Ответ на: комментарий от grem 16.03.17 17:28:34 MSK
Для поиска таких ситуация и используют тесты с санитайзерами и valgrind.
xaizek ★★★★★
( 16.03.17 18:41:15 MSK )
Ответ на: комментарий от RazrFalcon 16.03.17 15:58:37 MSK
tyro33
( 16.03.17 19:27:10 MSK )
Ответ на: комментарий от grem 16.03.17 15:33:41 MSK
free(a); a = nullptr; a[0] = 1; //сегфолт
Ограничено, и, конечно, не работает если
b = a; free(a); a = nullptr; b[0] = 1;
ymuv ★★★★
( 16.03.17 19:32:01 MSK )
Ответ на: комментарий от grem 16.03.17 15:33:41 MSK
a = NULL;
после free() и тогда будет падать. P.S. Оратор выше меня опередил.
WRG ★★★★
( 16.03.17 19:51:37 MSK )
Последнее исправление: WRG 16.03.17 19:52:11 MSK (всего исправлений: 1)
Ответ на: комментарий от tyro33 16.03.17 19:27:10 MSK
RazrFalcon ★★★★★
( 16.03.17 20:05:15 MSK )
Ответ на: комментарий от tyro33 16.03.17 19:27:10 MSK
#define arr(i,j) i*n+j
Плохо потому что макрос это не функция. Вот смотри:
мы передаём в arr i+5 и j
тогда макрос раскроется в
i + 5*n +j
(i + 5)*n + j
Так что лучше использовать
#define arr(i,j) (i)*n+(j)
А ещё лучше использовать функцию, так как здесь у нас один один тип(size_t), и нам не нужна перегрузка. Макросы в виде функций нужно использовать только когда нужна перегрузка функций, а компилятор не поддерживает C11
В C11 используется generic макросы.
fsb4000 ★★★★★
( 16.03.17 20:25:39 MSK )
Ответ на: комментарий от fsb4000 16.03.17 20:25:39 MSK
Да, про скобки я забыл здесь. Подумал, что имелось ввиду вообще лучше не использовать макросы. Функцию, чтобы было a[Indx(i, j)]?
grem ★★★★★
( 16.03.17 20:48:34 MSK ) автор топика
Последнее исправление: grem 16.03.17 20:50:40 MSK (всего исправлений: 1)
Ответ на: комментарий от grem 16.03.17 20:48:34 MSK
Да, функцию описывать чуть чуть дольше, зато будет понадёжнее макроса будет. (Можно конечно и макрос такой же написать, который будет приводить типы, и делать ассерты, но обычно такие длинные макросы никто не пишет) Можно assert подсунуть, опять же будет приведение типов до size_t(а то, если int i,j,n; и индекс больше 2^31, так как макрос не приведёт типы, то произойдёт overflow)
size_t Indx(size_t i, size_t j) < assert (0 < n); // число элементов в строке должно быть больше нуля if (0 != i) < assert ( SIZE_MAX / i >= n); // проверяем что нет переполнения при i*n > assert (SIZE_MAX - i * n >= j); // проверяем что нет переполнения при i*n + j return i * n + j; >
Имхо макросы использовать можно в C коде когда нужна именно перегруженная функция, и относительно простой логикой.
fsb4000 ★★★★★
( 16.03.17 21:33:32 MSK )
Ответ на: комментарий от grem 16.03.17 15:33:41 MSK
invy ★★★★★
( 17.03.17 10:58:33 MSK )
Ответ на: комментарий от invy 17.03.17 10:58:33 MSK
спасибо, clang «на-посмотреть» вчера скачал вместе с html-документацией, выложенной на сайте
grem ★★★★★
( 17.03.17 11:05:25 MSK ) автор топика
Ответ на: комментарий от fsb4000 16.03.17 21:33:32 MSK
Имхо макросы использовать можно в C коде когда нужна именно перегруженная функция, и относительно простой логикой.
Для вашего примера вполне может быть n через #define.
vodz ★★★★★
( 17.03.17 11:08:07 MSK )
Ответ на: комментарий от joy4eg 16.03.17 16:42:14 MSK
Я розовая звезда дятел! 🙂
double (*a)[n] = (double (*)[n])malloc(n * sizeof(double)); , хоть мы и объявили тип double (*a)[n] для 12 элементов, он, естественно, выделяет память только под 12 элементов, а не для 144. Поэтому a[11][0] = 40.0; , который до free(a), пишет не в выделенный участок памяти, а за его пределы, повреждая кучу. Инициализация должна быть следующей (подправлю в теме):
double (*a)[n] = (double (*)[n])malloc(n * n * sizeof(double));
grem ★★★★★
( 17.03.17 13:37:04 MSK ) автор топика
Последнее исправление: grem 17.03.17 13:39:17 MSK (всего исправлений: 1)
Возьми python + numpy. C не для тебя.
kawaii_neko ★★★★
( 17.03.17 14:00:36 MSK )
Ответ на: комментарий от kawaii_neko 17.03.17 14:00:36 MSK
Возьми python + numpy. Возьми python + numpy.
я ничего и не считаю, уже и поизвращаться нельзя
grem ★★★★★
( 17.03.17 14:31:55 MSK ) автор топика
std::vector arr(rows * cols); arr[y * cols + x] = 42;
yoghurt ★★★★★
( 18.03.17 00:31:09 MSK )
Ответ на: комментарий от grem 16.03.17 14:52:10 MSK
Я ж сразу написал, что хотеть обращение к элементу как a[j], а не a[n*i+j]
Сахарок сахарный. Если такого действительно хочется, да ещё чтоб с выравниванием строк/элементов (мало ли), то только костылять свой класс над плоским буфером и переопределять операторы.
yoghurt ★★★★★
( 18.03.17 00:33:58 MSK )
Ответ на: комментарий от yoghurt 18.03.17 00:33:58 MSK
чтобы в дальнейшем обращаться к его элементам как a[i][j]
ну так работает же. Другое дело, что подобными вещами в виде возни с адресами лучше не заниматься и использовать готовые решения предоставленными библиотеками. Переопределение операторов для индексации в векторе для описания трёхмерного массива мне уже сегодня показали. После этого невольно завидуешь тем, кто пишет на фортране, где подобными вещами заниматься вообще не нужно.
и как этот «класс» будет выглядеть в чистом С? Функцию или макрос описывали выше.
На самом деле было просто интересно как сделеть подобную вещь, С позволяет внутренними средствами. Проблема была ещё и в том, что я сначала неправильно выделял память, из-за чего при присвоении значений некоторым элементам массива повреждал кучу. Меня переглючило, что раз описание типа уже говорит, что там n элементов, то и выделить он для каждого из них должен, забыв, что перед malloc просто преобразование типа из (void *) в (double (*)[n]), которое в чистом C можно и не писать, в крайнем случае warning будет и всё.
C++. Правильное удаление динамического двумерного массива
Всем привет. Я новичок в программировании и только начинаю многое осваивать(хотя и имею кое-какую подготовку, но считать её хоть сколь-либо серьезной смешно). Знакомлюсь с классами, пытаясь соорудить нечто для работы с матрицами. Код реализации не важен, важно то, что получаю ошибку: http://prntscr.com/e6y5on Ключевой вопрос в том, как её исправить. Matrix.h:
#ifndef MATRIX_H #define MATRIX_H class Matrix < private: int m_rows = 1; int m_cols = 1; int** m_matrix = new int* [m_rows]; public: Matrix(int rows, int cols); void SetSize(int rows, int cols); void Create(); int rows(); int cols(); ~Matrix(); >; #endif
#include #include #include "matrix.h" using namespace std; Matrix::Matrix(int rows, int cols) < SetSize(rows, cols); Create(); >void Matrix::SetSize(int rows, int cols) < m_rows = rows; m_cols = cols; >void Matrix::Create() < for (int i = 0; i < m_rows; i++) m_matrix[i] = new int[m_cols]; cout int Matrix::rows() < return m_rows; >int Matrix::cols() < return m_cols; >Matrix::~Matrix()
int main()
При пошаговой проверке в Visual Studio программа сыплется на удалении внешнего указателя delete[] m_matrix; Собственно, прошу помочь =)
Отслеживать
44.8k 3 3 золотых знака 38 38 серебряных знаков 89 89 бронзовых знаков
задан 10 фев 2017 в 13:08
43 1 1 золотой знак 1 1 серебряный знак 3 3 бронзовых знака
Было бы лучше, если бы вы добавили текст ошибки в вопрос не как ссылку
10 фев 2017 в 13:23
Буду иметь ввиду. Новичок на stackoverflow)
10 фев 2017 в 16:20
5 ответов 5
Сортировка: Сброс на вариант по умолчанию
int m_rows = 1; int m_cols = 1; int** m_matrix = new int* [m_rows];
Итак, у вас сразу выделяется память и создается матрица 1×1. Поскольку в конструкторе
Matrix::Matrix(int rows, int cols)
у вас нет инициализации членов, они инициализированы по умолчанию этой матрицей.
Но что вы делаете дальше? Вы переписываете m_rows и m_cols , и в уже выделенный массив для ОДНОГО указателя записываете их m_rows , т.е. в данном конкретном случае — два.
Вот вам и источник ваших неприятностей. Ваша попытка исправить ситуацию — это просто попытка не заметить ошибку. Ни к чему хорошему привести это не может. В следующий раз вы запишете туда их с десяток, и таки засорите память основательнее, только и всего.
Вот как по-хорошему должна выглядеть ваша матрица:
class Matrix < private: int m_rows; int m_cols; int** m_matrix; public: Matrix(int rows, int cols); void SetSize(int rows, int cols); void Create(); int rows(); int cols(); ~Matrix(); >; Matrix::Matrix(int rows, int cols) :m_rows(rows),m_cols(cols) < m_matrix = new int*[m_rows]; for (int i = 0; i < m_rows; i++) m_matrix[i] = new int[m_cols]; cout Matrix::~Matrix()
Как очистить двумерный массив c
Создание и удаление двухмерного динамического массива
Необходимо помнить, что в C двумерный массив является "массивом из указателей на линейные массивы". Поэтому нужно создать как массив указателей, так и сами линейные массивы. А при удалении нужно удалить и линейные массивы и массив указателей:
int **pArr = new int*[dim1];
Создание и удаления трехмерного динамического массива
Все происходит по аналогии с двумерным массивом:
ppArr = new int**[dim1];
Правильное удаление двумерного динамического массива ( нужен ли delete[] array )
Сообщение от -=ЮрА=-
в результате arr[i] - уничтожается(удалиться указатель вместе с элементами строки), тогда если делать так delete [] arr мы будем пытаться удалить уже пустой объёкт!(Не нужно делать масло маслянным)
Я так и не смог понять:
- правда ли, что удаляются указатели на строки в цикле и действительно можно не использовать delete [] arr? Мне непонятно каким образом указатели-то удаляются в цикле.
Хочу увидеть ответы и других участников форума.
Добавлено через 4 часа 23 минуты
поднимаю тему
Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Правильное удаление динамического двумерного массива
Доброго времени суток форумчани. Ну в общем перейду сразу к делу. О себе: сам пишу на JAVA.
Удаление двумерного динамического массива
Здравствуйте. Возникла ошибка при удалении двумерного динамического массива: сам код.
Удаление двумерного динамического массива (матрицы)
Вот так я создаю двумерный динамический массив. bool **gameFieldArray; gameFieldArray = new.
Удаление строки из двумерного динамического массива
Написал код который добавляет в массив структур новый элемент. Но не получается написать функцию.
Заблокирован
Сообщение от Roof
Я пришел в замешательство, когда мне сказали, что delete[] arr после цикла тут не нужен.
Явно выделил - явно удали. Иначе - утечка памяти.
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
нужно удалять.
Если было
1 2 3 4 5
int** arr = new int*[10]; for (int i = 0; i 10; i++) { arr[i] = new int[10]; }
то деструкторы нужно в обратном порядке позвать. сперва для каждого arr[i], а потом для самого arr.
1 2 3 4 5
for (int i = 0; i 10; i++) { delete [] arr[i]; } delete [] arr;
Заблокирован
Что б не думалось, достаточно выполнить маленький эксперимент:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
struct Test { Test() { cout "Test: Создаюсь\n"; } ~Test() { cout "Test: удаляюсь\n"; } int a; }; int main(int argc, char *argv[]) { const int m=3; Test** arr= new Test*[10]; //создали массив указателей for(int i = 0; i m; i++) { arr[i] = new Test[m];//создали сами объекты } delete [] arr; //вывод: сообщения о создании объектов. // сообщения об удалении объектов отсутствуют //Итого: утечка памяти. Объекты остались в памяти // А удалены были только // указатели на массивы этих объектов return 0; }
Добавлено через 4 минуты
Утечка памяти:
1 2 3
for(i = m - 1; 0 i; i--) * * * * * * * * delete [] arr[i]; //удалил массивы объектов, //но забыл удалить массив указателей