Ответ 1
Вы не переназначаете указатель после его освобождения, вы просто повторно используете переменную ptr
. Это прекрасно.
Является ли это законным? Можете ли вы присвоить ptr
чему-то после его освобождения?
int * ptr = (int*) malloc(sizeof(int));
free(ptr);
ptr = (int *) malloc(sizeof(int));
Вы не переназначаете указатель после его освобождения, вы просто повторно используете переменную ptr
. Это прекрасно.
Прежде всего, как я упоминал в комментариях, пожалуйста, ознакомьтесь с этим обсуждением, почему бы не использовать возвращаемое значение malloc() и семейства в C..
Тем не менее, да, (re) -ассортировка здесь прекрасна.
Собственно, формулировка вопроса
Можете ли вы назначить
ptr
чему-то после его освобождения?
должен читать
Можно ли назначить
ptr
с помощью после освобождения?
Угадайте, что назначение без free
-ing также является законным согласно C, но оно создаст утечку памяти как побочный эффект, поскольку переменная ptr
удерживала возвращаемое значение функции распределения памяти, и вам нужно освободить память, как только вы закончите, используя ее. Если вы повторно назначаете указатель, не сохраняя копию указателя, вы потеряете доступ к памяти, выделенной функцией распределителя, и не сможете использовать free()
его.
В случае, если указатель удерживает адрес статически назначенной переменной, вы не можете (бесплатно) освободить его, а прямое переназначение отлично. подумайте об этом ниже.
int x = 5, y = 10;
int * p = &x;
//do something with p
p = &y; //this is fine, just a re-assignment.
Да. он действителен на языке C.
Связанный вопрос для дополнительной информации: Повторное использование бесплатных указателей в C
Согласно cwe.mitre.org:
В этом сценарии рассматриваемая память выделяется другой указатель действительно в какой-то момент после его освобождения. Оригинал указатель на освобожденную память снова используется и указывает куда-то в рамках нового распределения. По мере изменения данных он развращает действительная используемая память; это приводит к undefined поведению в процессе.
Является ли это законным? Можете ли вы присвоить
ptr
чему-то после его освобождения?
Да, это законно. ptr
можно переназначить столько раз, сколько захотите. Освобождение этого указателя необязательно для его переназначения, например
int * ptr = malloc(sizeof(int));
int *temp_ptr = ptr; // temp_ptr is pointing to the location ptr is pointing
ptr = malloc(sizeof(int)); // ptr points to new location.
Обратите внимание, что вы не должны указывать возвращаемое значение malloc
.
Можете ли вы назначить
ptr
чему-то после его освобождения?int * ptr = (int*) malloc(sizeof(int)); /* line 1 */ free(ptr); /* line 2 */ ptr = (int *) malloc(sizeof(int)); /* line 3 */
Принимая ваш вопрос как:
"Является ли законным присваивать адрес свежей динамически выделенной памяти указателю (строка 3) после того, как память, указатель которой указана на предыдущее динамическое выделение (строка 1), была освобождена (строка 2)?"
Тогда этот ответ да.
Запуск строки 3 также будет действителен без выполнения строки 2. Тем не менее, если не вызывать free()
(строка 2), значение, присвоенное ptr
(строка 1), перезаписывается (строка 3), и с этим возможность вызывать free()
на ptr
начальное значение теряется, что в свою очередь оставляет программу утечкой именно этой памяти, выделенной изначально.
Да, вы назначаете новую память в кучу и ее юридическую.
Я бы рекомендовал вместо этого использовать realloc
.
В случае неудачи realloc()
из c11, глава §7.22.3.5,
Функция realloc возвращает... нулевой указатель, если новый объект не может быть выделено.
и
[....] Если память для нового объекта не может быть выделена, старый объект не освобождается и его значение не изменяется.
Правильный способ использования realloc будет
ptr_new = realloc(ptr, sizeof(int)*2);
if (ptr_new == NULL)
{
free(ptr);
}
Также, пожалуйста, прочитайте почему я не должен указывать возвращаемое значение malloc.
Да. Это совершенно законно. ptr
- автономная переменная, которая продолжает существовать независимо от ее содержимого. Ничего не происходит с местом памяти, где хранится ptr
. Нет ничего, что помешало бы вам присвоить вам какую-либо ценность. Правильность распределения памяти (malloc
/realloc
и т.д.) - это другая история, но нет ничего плохого в повторном использовании переменной (ячейки памяти) для хранения адреса ячейки памяти.
Когда вы объявляете указатель, ему будет выделено место памяти. Это местоположение можно переназначить.
Если вы переназначите его после присвоения ему значения с вызовом malloc()
и до free()
, это утечка памяти. После free()
вы можете переназначить его, и утечки не произойдет, не забудьте снова free()
.
Фактически, операционные системы, которые являются полезными программами, которые никогда не заканчиваются, все время переназначают некоторые фиксированные указатели на процессы, освобождают их при завершении процесса и т.д.
Программирование, в котором присвоения недопустимы, называется functional programming
.