Я обнаружил, что некоторые люди и ссылки, подобные книгам, заявляют, что если p != NULL
и p
происходят из предыдущего распределения (например, malloc
), то realloc(p, 0)
эквивалентно free(p)
в GNU/Linux. Чтобы поддержать этот тезис man realloc
, указывается именно таким образом (акцент мой вперед):
Функция realloc() изменяет размер блока памяти, на который указывает от ptr до размера байтов. Содержимое будет оставаться неизменным в диапазоне от начало региона до минимума старого и нового размеров. Если новый размер больше старого, добавленная память не будет инициализируется. Если ptr равно NULL, то вызов эквивалентен malloc (размер) для всех значений размера; , если размер равен нулю, и ptr не является NULL, тогда вызов эквивалентен свободному (ptr). Если ptr NULL, он должен быть возвращен предыдущим вызовом malloc(), calloc() или realloc(). Если указанная область была перемещена, свободный (ptr) делается.
Как вы можете найти в этом вопросе, стандарт C не определяет точно, что должно произойти, а фактическое поведение определяется реализацией. Более конкретно:
C11 §7.22.3/p1 Функции управления памятью говорят:
Если размер запрашиваемого пространства равен нулю, поведение определение реализации: возвращается нулевой указатель, или поведение, как если бы размер был некотором ненулевым значением, за исключением того, что возвращаемый указатель не должен использоваться для доступа к объекту.
и C11 §7.22.3.5 Функция realloc содержит:
3) (...) Если память для нового объекта не может быть выделена, старый объект не освобождается, а его значение не изменяется.
4) Функция
realloc
возвращает указатель на новый объект (который может имеют то же значение, что и указатель на старый объект), или нулевой указатель если новый объект не может быть назначен.
Я написал базовый код, чтобы узнать фактическое поведение с помощью mcheck
, средство проверки памяти, которое поставляется с glibc
#include <mcheck.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a = 5;
int *p, *q;
mtrace();
p = malloc(sizeof(int));
q = &a;
printf("%p\n", (void *) p);
printf("%p\n", (void *) q);
q = realloc(p, 0);
printf("%p\n", (void *) p);
printf("%p\n", (void *) q);
return 0;
}
и результаты:
$ gcc -g check.c
$ export MALLOC_TRACE=report
$ ./a.out
0xfd3460
0x7ffffbc955cc
0xfd3460
(nil)
[[email protected] workspace]$ mtrace a.out report
Memory not freed:
-----------------
Address Size Caller
0x0000000000fd3460 0x4 at /home/grzegorz/workspace/check.c:12
Как вы можете видеть, q
был установлен в NULL
. Кажется, что free()
на самом деле не назывался. На самом деле это не может быть, если моя интерпретация неверна: поскольку realloc
возвратил указатель NULL
, новый объект не мог быть выделен, что подразумевает, что:
старый объект не освобождается и его значение не изменяется
Правильно ли это?