#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);
}