Правильное использование free () при освобождении 2d матрицы в c - PullRequest
0 голосов
/ 07 декабря 2018

Я только начинаю изучать кодирование на языке c, и у меня есть несколько вопросов относительно двухмерных матриц в сочетании с командой free ().

Я знаю, что сначала вам нужно создать массив с указателем, указывая на разные столбцы матрицы:

double **array = (double **)malloc(5*sizeof(double *));
for(int n = 0; n<5; n++){

array[n] = (double *) malloc(6*sizeof(double));

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

for (i = 0; i < nX; i++){  
   free(array[i]); }     

free(array);

Мой вопрос: зачем это нужно?Я знаю, что это неверно, но почему вы не можете просто использовать: free (array)?Это освободило бы массив указателей, насколько я понимаю.Разве память, используемая столбцами, не будет просто перезаписана, когда кому-то еще понадобится доступ к ней?Может ли free (array) привести к повреждению памяти?

Любая помощь очень ценится!

Ответы [ 4 ]

0 голосов
/ 07 декабря 2018

Это необходимо, потому что C не имеет сборщика мусора.Когда вы выделяете память с помощью malloc или аналогичной функции, она помечается как «используемая», пока ваша программа работает.

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

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

Так что, когда вы free указатель (или массив указателей), нет логики "осознать", что это указатели, которые содержат адреса памяти.

Это просто то, как спроектирован язык C: управление динамической памятью почти 1 полностью ручное - оставлено на усмотрение программиста, поэтому вы должны вызывать free для каждого вызова malloc.


1 Язык C обрабатывает некоторые из более утомительных задач, необходимых для динамического выделения памяти в программе, таких как поиск места для получения свободного непрерывного фрагмента памяти того размера, который вы запрашивали.

0 голосов
/ 07 декабря 2018

Давайте рассмотрим простой пример:

int **ptr = malloc(2*sizeof *ptr);
int *foo = malloc(sizeof *foo);
int *bar = malloc(sizeof *bar);
ptr[0] = foo;
ptr[1] = bar;
free(ptr);

Если бы ваше предложение было реализовано, foo и bar теперь были бы висячими указателями.Как бы вы решили сценарий, если вы просто хотите бесплатно ptr?

0 голосов
/ 07 декабря 2018

Ваш код не только выделяет память для массива указателей (синий массив), но и в цикле for вы также выделяете память для красных массивов.Таким образом, одна строка free(array) просто освободит память, выделенную синим массивом, но не красным.Вы должны освободить красные, прежде чем потерять контакт с ними;то есть до освобождения синего массива.

И кстати;

Не будет ли просто перезаписана память, используемая столбцами, когда к ней понадобится что-то еще?

Нет.Операционная система будет отслеживать память, выделенную вашим процессом (программой), и не позволит никаким другим процессам получать доступ к выделенной памяти, пока ваш процесс не завершится.При нормальных обстоятельствах - я имею в виду, помня, что язык C не имеет сборщика мусора - ОС никогда не узнает, что вы потеряли соединение с выделенным пространством памяти, и никогда не будет пытаться что-то вроде: «Ну, это пространство памяти бесполезно для этого процессабольше, поэтому давайте выделим его и используем для другого процесса. "

enter image description here

0 голосов
/ 07 декабря 2018

Это не приведет к повреждению, нет, но создаст утечка памяти .

Если сделать это однажды в вашей программе, это, вероятно, не имеет большого значения (много профессионалов/ дорогие приложения имеют - небольшие, непреднамеренные - утечки памяти), но повторите это в цикле, и через некоторое время у вас может закончиться память.То же самое, если ваш код вызывается из внешней программы (если ваш код находится в библиотеке).

В сторону: не освобождение буферов может быть полезным (временно) для проверки, происходит ли сбой, в который вы входитеВаши программы происходят из-за поврежденного выделения памяти или освобождения (когда вы не можете использовать Valgrind).Но, в конце концов, вы хотите освободить все, один раз .

Если вы хотите выполнить только один malloc, вы также можете выделить один большой блок, а затем вычислить адреса строк,В конце просто освободите большой кусок (пример здесь: Как мы можем выделить 2-D массив, используя одну инструкцию malloc )

...