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

Я новичок, когда речь заходит о динамическом распределении памяти. Когда мы освобождаем память, используя void free(void *ptr) память освобождается, но содержимое указателя не удаляется. Это почему? Есть ли разница в более поздних компиляторах C?

Компьютеры не «удаляют» память как таковые, они просто перестают использовать все ссылки на эту ячейку памяти и забывают, что там хранится что-либо ценное. Например:

 int* func (void) { int x = 5; return &x; } printf("%d", *func()); // undefined behavior 

Как только функция закончена, программа прекращает резервирование места памяти, где хранится x , любая другая часть программы (или, возможно, другая программа) может свободно использовать ее. Таким образом, вышеприведенный код может печатать 5, или он может печатать мусор, или он может даже сбой программы: ссылка на содержимое ячейки памяти, которая перестала быть действительной, является неопределенным поведением.

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

Также см. Этот вопрос .

Дело в том, что доступ к памяти после ее освобождения – это неопределенное поведение. Мало того, что содержимое памяти не определено, доступ к ним может привести к чему-либо. По крайней мере, некоторые компиляторы при создании отладочной версии кода фактически изменяют содержимое памяти, чтобы помочь в отладке, но в версиях выпуска обычно нет необходимости делать это, поэтому память остается только как есть, но в любом случае, это не то, на что можно надежно опираться, не получить доступ к свободной памяти, это небезопасно!

В C параметры передаются по значению. Таким образом, free просто не может изменить значение ptr .
Любое изменение, которое оно произвело бы, только изменило бы значение в пределах free функции и не повлияет на переменную вызывающего.

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

Это очень нормально, потому что освобождение памяти после освобождения является накладными расходами и вообще не необходимо. Если у вас есть проблемы с безопасностью, вы можете обернуть бесплатный вызов внутри функции, которая очищает область перед освобождением. Вы также заметите, что для этого требуется знание размера распределения, что является еще одним накладным.

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

Это связано с тем, что хороший компилятор попытается агрессивно хранить все переменные в регистры процессора вместо памяти. Поэтому после того, как он видит, что stream программы вызывает функцию с именем free с аргументом ptr , он может пометить регистр ptr бесплатно для другого использования, пока не будет назначен снова, например ptr = malloc(42); ,

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