Из-за моего ограниченного рейтинга я пока не могу комментировать посты других, поэтому использую «ответ», пока это не ответ, но комментарий.
Ответ / комментарий Эрика Постпишила, представленный выше, требует рецензирования.
Я не согласен или не понимаю его рассуждения.
" ... Когда объект освобождается, хотя байты в указателе не меняются, данные в этих структурах могут изменяться, и тогда попытка использовать указатель может завершиться неудачей различными способами. В частности, попытка распечатать значение может не получиться, потому что .."
Обратите внимание на прототип стандартного вызова C free (): void free (void * ptr). В месте вызова значение ptr останется неизменным до и после бесплатного вызова - оно передается значением значение .
«Использовать» указатель будет / может произойти сбой различными способами, если под использованием мы подразумеваем deference после вызова free (). Печать значения указателя не вызывает его.
Кроме того, печать (значение) указателя с вызовом printf с использованием% p должна выполняться, даже если представление значения указателя определено реализацией.
"* ... Однако, поскольку это правило существует, даже менее экзотические реализации C могут использовать его для оптимизации, поэтому компилятор C может реализовать free (x); printf ("% p ", (void *) x); эквивалентно free (x); printf ("% p", (void ) NULL) ;, например. ..."
Даже если он (компилятор) сделает это, я не могу легко увидеть, что бы это оптимизировало, вызов специального свернутого printf со значением 0 для указателя?
Также рассмотрим что-то вроде:
extern void my_free (void * ptr); // определено где-то ..
my_free (myptr);
printf ("% p", myptr);
Было бы нечего оптимизировать, как вы предлагаете здесь, и он (компилятор) ничего не может сделать о значении myptr.
Так что нет, я не могу согласиться с вашей интерпретацией стандарта C на данном этапе.
(мой) EDIT:
Если только не некоторые "экзотические" реализации с указателем памяти, реализованным в виде структуры, и он приводится к / от "user" void * .. Тогда значение кучи пользователя будет недействительным или нулевым при попытке его печати ..
Но тогда каждый вызов C, который принимает void * в качестве указателя на память, должен был бы различать, какой void * указывает на кучу, которая не - скажем, memcpy, memset, - и тогда это становится довольно занятым ...