что возвращает malloc(0)?[дубликат]
Вопрос
На этот вопрос уже есть ответ здесь:
- какой смысл в malloc(0)? 17 ответов
Что делает malloc(0)
возвращается?Был бы ответ таким же для realloc(malloc(0),0)
?
#include<stdio.h>
#include<malloc.h>
int main()
{
printf("%p\n", malloc(0));
printf("%p\n", realloc(malloc(0), 0));
return 0;
}
Вывод из linux gcc:
manav@manav-workstation:~$ gcc -Wall mal.c
manav@manav-workstation:~$ ./a.out
0x9363008
(nil)
manav@manav-workstation:~$
Выходные данные продолжают меняться каждый раз для malloc(0)
.Это стандартный ответ?И почему кто-то может быть заинтересован в получении такого указателя, кроме академических исследований?
Редактировать:
Если malloc(0)
возвращает фиктивный указатель, тогда как работает следующее:
int main()
{
void *ptr = malloc(0);
printf("%p\n", realloc(ptr, 1024));
return 0;
}
Редактировать:
Следующий код выводит "возможно" для каждой итерации.Почему это не должно потерпеть неудачу ?
#include<stdio.h>
#include<malloc.h>
int main()
{
int i;
void *ptr;
printf("Testing using BRUTE FORCE\n");
for (i=0; i<65000; i++)
{
ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
printf("Iteration %d: possible\n", i);
else
{
printf("Failed for iteration %d\n", i);
break;
}
}
return 0;
}
Решение
Другие отвечали, как malloc(0)
работает.Я отвечу на один из заданных вами вопросов, на который еще не было ответа (я думаю).Вопрос заключается в том, realloc(malloc(0), 0)
:
Что делает
malloc(0)
вернуться?Был бы ответ таким же дляrealloc(malloc(0),0)
?
Стандарт говорит это о realloc(ptr, size)
:
- если
ptr
являетсяNULL
, он ведет себя какmalloc(size)
, - в противном случае (
ptr
не являетсяNULL
), он освобождает старый указатель на объект с помощьюptr
и возвращает указатель на новый выделенный буфер.Но еслиsize
равно 0, C89 говорит, что эффект эквивалентенfree(ptr)
.Интересно, что я не могу найти это утверждение в черновике C99 (n1256 или n1336).В C89 единственным разумным значением, которое нужно вернуть в этом случае, было быNULL
.
Итак, есть два случая:
malloc(0)
ВОЗВРАТNULL
о реализации.Тогда вашrealloc()
вызов эквивалентенrealloc(NULL, 0)
.Это эквивалентноmalloc(0)
сверху (и этоNULL
в данном случае).malloc(0)
возвращает не-NULL
.Тогда вызов эквивалентенfree(malloc(0))
.В данном случае,malloc(0)
иrealloc(malloc(0), 0)
являются не эквивалент.
Обратите внимание, что здесь есть интересный случай:во втором случае, когда malloc(0)
возвращает не-NULL
в случае успеха он все еще может вернуться NULL
чтобы указать на неудачу.Это приведет к вызову типа: realloc(NULL, 0)
, что было бы эквивалентно malloc(0)
, который может вернуться , а может и не вернуться NULL
.
Я не уверен, является ли упущение в C99 упущением или это означает, что в C99, realloc(ptr, 0)
для не-NULL
ptr
не эквивалентно free(ptr)
.Я только что попробовал это с gcc -std=c99
, и вышесказанное эквивалентно free(ptr)
.
Редактировать:Мне кажется, я понимаю, в чем заключается ваше замешательство:
Давайте посмотрим на фрагмент из вашего примера кода:
ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
Вышесказанное - это не то же самое, что malloc(0) == realloc(malloc(0), 1024)
.Во втором случае, malloc()
вызов выполняется дважды, тогда как в первом случае вы передаете ранее выделенный указатель на realloc()
.
Давайте сначала проанализируем первый код.Предполагая malloc(0)
не возвращается NULL
об успехе, ptr
имеет допустимое значение.Когда вы делаете realloc(ptr, 1024)
, realloc()
в основном дает вам новый буфер размером 1024, а ptr
становится недействительным.Соответствующая реализация может возвращать тот же адрес, что и тот, который уже есть в ptr
.Итак, ваш if
условие может возвращать значение true.(Обратите внимание, однако, на значение ptr
после realloc(ptr, 1024)
может быть неопределенное поведение.)
Теперь вопрос, который вы задаете: malloc(0) == realloc(malloc(0), 1024)
.В этом случае давайте предположим, что оба malloc(0)
на LHS и RHS возвращает не-NULL
.Тогда они гарантированно будут другими.Кроме того, возвращаемое значение из malloc()
на LHS еще не было free()
d пока, так что любой другой malloc()
, calloc()
, или realloc()
может не возвращать это значение.Это означает, что если вы записали свое условие как:
if (malloc(0) == realloc(malloc(0), 1024)
puts("possible");
ты не увидишь possible
на выходе (если только оба malloc()
и realloc()
потерпеть неудачу и вернуться NULL
).
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void *p1;
void *p2;
p1 = malloc(0);
p2 = realloc(p1, 1024);
if (p1 == p2)
puts("possible, OK");
/* Ignore the memory leaks */
if (malloc(0) == realloc(malloc(0), 1024))
puts("shouldn't happen, something is wrong");
return 0;
}
В OS X мой код ничего не выводил, когда я его запускал.В Linux он печатает possible, OK
.
Другие советы
malloc(0)
является Определенная реализация что касается C99.
От С99 [Раздел 7.20.3]
Порядок и смежность хранилища, выделенного последовательными вызовами calloc, функции malloc и realloc не указаны.Указатель, возвращаемый при успешном выделении , соответствующим образом выровнен, чтобы его можно было присвоить указателю на объект любого типа и затем использовать для доступа к такому объекту или массиву таких объектов в выделенном пространстве (до тех пор, пока пространство не будет явно освобождено).Время жизни выделенного объекта увеличивается с момента выделения до освобождения.Каждое такое выделение должно давать указатель на объект, не пересекающийся с любым другим объектом.Возвращенный указатель указывает на начало (младший байт адрес) выделенного пространства.Если пространство не может быть выделено, возвращается нулевой указатель . Если размер запрашиваемого пространства равен нулю, поведение соответствует реализации- определено:либо возвращается нулевой указатель, либо поведение такое, как если бы размер был некоторым ненулевое значение, за исключением того, что возвращаемый указатель не должен использоваться для доступа к объекту.
В C89 malloc(0) зависит от реализации - я не знаю, исправил ли C99 это или нет.В C ++, используя:
char * p = new char[0];
четко определен - вы получаете действительный, ненулевой указатель.Конечно, вы не можете использовать указатель для доступа к тому, на что он указывает, не вызывая неопределенного поведения.
Что касается того, почему это существует, то это удобно для некоторых алгоритмов и означает, что вам не нужно засорять свой код тестами на нулевые значения.
Стандарт C99
Если пространство не может быть выделено, возвращается указатель nullpointer.Если размер запрошенного пространства равен нулю, то поведение определяется реализацией:либо возвращается нулевой указатель, либо поведение такое, как если бы размер был некоторым ненулевым значением, за исключением того, что возвращенный указатель не должен использоваться для доступа к объекту.
В часто ЗАДАВАЕМЫЕ ВОПРОСЫ по comp.lang.c имеет следующее чтобы сказать:
Стандарт ANSI / ISO гласит, что он может выполнять либо;поведение определяется реализацией (см. Вопрос 11.33).Переносимый код должен либо позаботиться о том, чтобы не вызывать malloc(0), либо быть готовым к возможности возврата null .
Таким образом, вероятно, лучше избегать использования malloc(0)
.
См. C99, раздел 7.20.3:
Если размер запрашиваемого пространства равен нулю, поведение будет определено реализацией:либо возвращается значение null указатель, либо поведение такое, как если бы размер был некоторым ненулевым значением, за исключением того, что возвращаемый указатель не должен использоваться для доступа к объекту.
Это справедливо для всех трех функций распределения (т.е. calloc()
, malloc()
и realloc()
).
Один момент, о котором еще никто не позаботился поговорить в вашей первой программе, заключается в том, что realloc
с длиной 0 - это то же самое, что и free
.
со страницы руководства Solaris:
В
realloc()
функция изменяет размер блока, на который указано с помощьюptr
Дляsize
байт и возвращает указатель на (возможно, перемещенный) блок.Содержимое останется неизменным вплоть до меньшего из новых и старых размеров.Еслиptr
являетсяNULL
,realloc()
ведет себя какmalloc()
для указанного размера.Еслиsize
является0
иptr
не является нулевым указателем, пространство, на которое указано, становится доступным для дальнейшего выделения приложением, хотя и не возвращается в систему.Память возвращается системе только после завершения работы приложения.
Если кто-то не знает, что это может стать источником неприятного сюрприза (случилось со мной).
Я думаю, это зависит.Я проверил исходные тексты Visual Studio 2005 и увидел это в функции _heap_alloc:
if (size == 0)
size = 1;
Я думаю, что во многих случаях вам может понадобиться действительный указатель, даже когда вы запрашиваете нулевые байты.Это связано с тем, что такое согласованное поведение облегчает проверку ваших указателей, потому что:если у вас есть ненулевой указатель, все в порядке;если у вас есть НУЛЕВОЙ указатель, у вас, вероятно, проблема.Вот почему я думаю, что большинство реализаций вернут действительный указатель, даже когда запрашивается нулевой байт.
Если malloc(0) возвращает фиктивный указатель, то как работает следующее:
void *ptr = malloc(0);
printf("%p\n", realloc(ptr, 1024));
Я не знаю, что вы подразумеваете под "фиктивным указателем".Если malloc(0)
возвращает значение, отличное от NULL, тогда ptr
является допустимым указателем на блок памяти нулевого размера.В malloc
реализация сохраняет эту информацию специфичным для реализации способом. realloc
знает (специфичный для реализации) способ выяснить, что ptr
указывает на блок памяти нулевого размера.
(Как malloc
/realloc
/free
выполнение этого зависит от конкретной реализации.Одна из возможностей состоит в том, чтобы выделить на 4 байта больше, чем запрошено, и сохранить размер непосредственно перед блоком памяти.В таком случае, ((int *)ptr)[-1]
дало бы размер блока памяти, который равен 0
.Вы никогда не должны делать это из своего кода, это только для использования realloc
и free
).