Устанавливает ли указатели на освобожденную память, ссылающиеся на нее, в null?

#c #pointers #null

#c #указатели #null

Вопрос:

Представьте, что у меня есть структура для связанного списка:

 struct node{
     int data;
     struct node* next;
     struct node* prev;
};
  

Я освобождаю последний узел; next указатель узла, прежде чем он станет NULL автоматически?

Потому что я заметил, что не делал этого в программе, но все работает нормально..

Комментарии:

1. Стандартная free() функция не устанавливает освобожденный указатель на NULL . Если у вашей функции для освобождения есть функция настройки, она может стать NULL автоматической.

2. @MikeCAT Другие указатели на ту же память не будут, о чем спрашивает OP.

3. Нет, указатель и любые другие указатели на free общую память становятся недействительными (поскольку им больше не выделена память). Вы должны вести домашнее хозяйство самостоятельно.

4. if физически невозможно, поскольку free принимает только один указатель, поэтому он не может быть изменен этой функцией.

Ответ №1:

Нет.

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

Комментарии:

1. Я бы сказал, что это было не удачно. Сбой запроса сделал бы проблему сразу очевидной. Вместо этого «успех» означал, что была скрытая ошибка, которая только и ждала, чтобы вызвать сбой.

2. @AndrewHenle Вашей программе повезло, что она не потерпела крах. Вам не повезло, что ваша программа потерпела крах, когда вы продемонстрировали ее своему боссу, а не когда вы ее писали.

Ответ №2:

void free(void *ptr);

прототип функции показывает , что невозможно установить какое — либо значение для указателя ptr .

Таким образом, сохраненная ссылка будет такой же, как и до вызова, но она будет ссылаться на недопустимую ячейку памяти. Такого рода указатели вызываются "dangling pointers" . Если вы используете этот указатель, это неопределенное поведение.

Программа, вызывающая UB, может вести себя любым образом, включая правильное наблюдаемое поведение, но это неверно.

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

Ответ №3:

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

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

Комментарии:

1. «… вы не должны полагаться на то, что какие-либо указатели на эту память, которые существуют в другом месте вашей программы, обнуляются». Стоит отметить, что ни один указатель не обнуляется free функцией, даже указатель, который передается free() .

2. Хм, да… вот почему вы не должны полагаться на это 😉 Но, да, я понимаю, что я использовал «полагаться» в двух разных смыслах в одном и том же ответе. Моя ошибка.

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

4. Хорошо, уже — я изменил это. Вы хотите, чтобы я тоже упал на свой меч? 😉

Ответ №4:

free не удается обнулить его аргумент указателя в вызывающем объекте, потому что аргумент указателя принимается по значению (копировать).

 void free(void *ptr);
  

У вас не может быть функции, которая выполняла бы это, оставаясь такой же универсальной, как free , потому что free освободит не только указатель на void, но и любой другой указатель на неквалифицированный тип (= любой другой указатель, который неявно преобразуется в void * ).

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

Пример:

 #include <stdlib.h>
#include <assert.h>
#define FREE(Pp) (free(*(Pp)),*(Pp)=NULL)
int main(void)
{
    char *m = malloc(1);
    if (!m) return 1;
    FREE(amp;m);
    assert(!m);
}