Могу ли я по-прежнему вызывать free () для переменной, для которой был второй вызов malloc ()? - PullRequest
0 голосов
/ 06 сентября 2018

Мне было интересно, связан ли вызов malloc () с его начальной переменной, которой вы вообще назначаете malloc (), когда речь идет о том, как система освобождает память.

Например, могу ли явыполните следующее:

void * ptr1 = malloc(50);
void * ptr2 = ptr1;
ptr1 = malloc(25);
free(ptr2);

Я намеревался освободить память, которая была изначально назначена для ptr1, но позже освободить ее другим указателем.

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Краткий ответ: Да

Более длинный ответ:

Вы не вызываете free "для переменной", но для значения , хранящегося в переменной.

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

Когда вы делаете

void * ptr1 = malloc(50);

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

Теоретически мы могли бы (на некоторых архитектурах) написать

int ptr1 = (int)malloc(50);

Причины, по которым мы этого не делаем:

  1. sizeof(int) может быть недостаточно большим, чтобы удерживать указатель
  2. void * сообщает компилятору, что числовое значение, хранящееся в ptr1, должно рассматриваться как адрес памяти.

Если мы продолжим смотреть на ваш код:

void * ptr2 = ptr1;

Ничего волшебного здесь не происходит. «Числовое значение», сохраненное в ptr1, копируется в ptr2, как если бы ptr1 и ptr2 были обычными целочисленными переменными.

ptr1 = malloc(25);

Здесь вы перезаписываете содержимое ptr1 новым «числовым значением», но старым значением все еще существует как копия в ptr2.

free(ptr2);

Здесь вы звоните free со значением, сохраненным в ptr2. Это значение, возвращаемое malloc(50). free не волнует, какая переменная содержит это значение / адрес. Нужно только, чтобы значение / адрес указывало на первый байт блока памяти, который был зарезервирован с malloc.

Теоретически, если бы вы знали, что malloc(50) вернул значение 0xb00b1e5, вы могли бы сделать

free((void *) 0xb00b1e5);

Но вы не можете с уверенностью предсказать, что malloc вернется, поэтому не делайте этого.

0 голосов
/ 06 сентября 2018

Давайте пройдем по шагам (UNDEF означает, что мы не знаем, что такое значение; valid означает, что указатель безопасен в использовании):

void *ptr1, *ptr2;    /* ptr1=UNDEF (invalid), ptr2=UNDEF (invalid) */
ptr1 = malloc(50);    /* ptr1=0xAAA (valid),   ptr2=UNDEF (invalid) */
ptr2 = ptr1;          /* ptr1=0xAAA (valid),   ptr2=0xAAA (valid)   */
ptr1 = malloc(25);    /* ptr1=0xBBB (valid),   ptr2=0xAAA (valid)   */
free(ptr2);           /* ptr1=0xBBB (valid),   ptr2=UNDEF (invalid) */

free() не знает, в какой если есть какая-либо переменная , в которой хранится указатель, в котором она передана;не гарантируется (но также не гарантируется не to) обновление или взаимодействие с переменными каким-либо образом.Все, что эффективно меняется с точки зрения разработчика приложения, это то, безопасно ли на самом деле использовать этот указатель, или любые другие ссылки на блок памяти, выделенный во время вызова malloc(), который его возвратил.

Как упомянуто @ MM в комментариях , спецификация языка C явно указывает, что значение указателя на освобожденный объект не определено, и компилятору разрешено изменятьэто никак;см. Почему MISRA C заявляет, что копия указателей может вызвать исключение памяти? для дальнейшего обсуждения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...