что возвращает malloc(0)? [дубликат]
этот вопрос уже есть ответ здесь:
- какой смысл в malloc(0)? 16 ответов
Что значит malloc(0)
возвращает? Будет ли ответ таким же для realloc(malloc(0),0)
?
#include<stdio.h>
#include<malloc.h>
int main()
{
printf("%pn", malloc(0));
printf("%pn", 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)
. Это стандартная ответ? И почему кто-то заинтересован в получении такого указателя, кроме академических исследований?
EDIT:
если malloc(0)
возвращает фиктивный указатель, а затем как работает следующее:
int main()
{
void *ptr = malloc(0);
printf("%pn", realloc(ptr, 1024));
return 0;
}
EDIT:
следующий код выводит "возможно" для каждой итерации. Почему бы ему не потерпеть неудачу ?
#include<stdio.h>
#include<malloc.h>
int main()
{
int i;
void *ptr;
printf("Testing using BRUTE FORCEn");
for (i=0; i<65000; i++)
{
ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
printf("Iteration %d: possiblen", i);
else
{
printf("Failed for iteration %dn", i);
break;
}
}
return 0;
}
10 ответов:
другие ответили как
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)
возвращает non -NULL
. Тогда вызов эквивалентенfree(malloc(0))
. В этом случаеmalloc(0)
иrealloc(malloc(0), 0)
are не эквивалентны.обратите внимание, что есть интересный случай: во втором случае, когда
malloc(0)
возвращает non -NULL
на успех, он все еще может вернутьсяNULL
, чтобы указать отказ. Это приведет к вызову типа:realloc(NULL, 0)
, который будет эквивалентноmalloc(0)
, который может или не может вернутьсяNULL
.я не уверен, является ли упущение в C99 оплошностью или это означает, что в C99,
realloc(ptr, 0)
для некурящихNULL
ptr
не эквивалентноfree(ptr)
. Я только что попробовал это сgcc -std=c99
, и вышеизложенное эквивалентноfree(ptr)
.Edit: мне кажется, я понимаю, в чем ваше замешательство:
давайте посмотрим на фрагмент из вашего примера кода:
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 возвращает non -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.С C99 [раздел 7.20.3]
порядок и смежность хранения, выделенные последовательными вызовами calloc, функции malloc и realloc не указаны. Указатель возвращается, если выделение succeeds соответствующим образом выровнен так, чтобы он мог быть назначен указателю на любой тип объекта а затем используется для доступа к такой объект или массив таких объектов в выделенном пространстве (пока пространство не будет явно освобождено). Время жизни выделенного объекта увеличивается от выделения до освобождения. Каждое такое распределение должно давать указатель на объект непересекающийся от любого другого объекта. Указатель возвращает точки начала (младший байт адрес) выделенного пространства. Если пространство не может быть выделена, указатель null возвращенный. Если размер запрошенное пространство равно нулю, поведение является реализацией- определено: либо возвращается нулевой указатель, либо поведение выглядит так, как если бы размер был некоторым ненулевое значение, за исключением того, что возвращается указатель не должен использоваться для доступа к объекту.
в C89 malloc (0) зависит от реализации - я не знаю, исправил ли C99 это или нет. В C++, используя:
char * p = new char[0];
хорошо определен - вы получаете действительный, ненулевой указатель. Конечно, вы не можете использовать указатель для доступа к тому, на что он указывает, не вызывая неопределенное поведение.
что касается того, почему это существует, это удобно для некоторых алгоритмов, и означает, что вам не нужно засорять свой код тестами для нулевых значений.
стандарт C99
Если пространство не может быть выделено, а появляется сообщение об возвращается. Если размер из запрошенного пространства равен нулю, поведение определяется реализацией: либо возвращается нулевой указатель, либо поведение, как если бы размер был некоторое ненулевое значение, за исключением того, что возвращенный указатель не должен использоваться для доступ к объекту.
на комп.ленг.с чаво и следующее сказать:
стандарт ANSI / ISO говорит, что он может сделать что-либо; поведение реализация определена (см. вопрос 11.33). Переносимый код должен либо позаботиться о том, чтобы не вызывать malloc(0), либо быть подготовлено к возможности нулевого значения возвращаться.
поэтому, вероятно, лучше избегать использования
malloc(0)
.
см. C99, раздел 7.20.3:
Если размер запрашиваемого пространства равен ноль, поведение implementationdefined: либо null возвращается указатель или поведение это как если бы размер был какой-то ненулевой значение, за исключением того, что возвращается указатель не должен использоваться для доступа к объект.
Это справедливо для всех трех функций выделения (т. е.
calloc()
,malloc()
иrealloc()
).
один момент, о котором еще никто не хотел говорить, в вашей первой программе это
realloc
с длиной 0 это то же самое, что иfree
.С man-страницы Solaris:
The
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)
возвращает ненулевое значение, затемptr
является допустимым указателем на блок памяти нулевого размера. Элементmalloc
реализация сохраняет эту информацию в реализации определенным способом.realloc
знает (реализации) способ выяснить, чтоptr
очки к блоку памяти нулевого размера.(как
malloc
/realloc
/free
сделать это зависит от конкретной реализации. Одна из возможностей состоит в том, чтобы выделить 4 байта больше, чем требуется, и сохранить размер непосредственно перед блоком памяти. В таком случае,((int *)ptr)[-1]
даст размер блока памяти, который составляет0
. Вы никогда не должны делать это из кода, это только для использованияrealloc
иfree
).
мы реализовали структуры malloc для встроенного кода с заголовком (и дополнительным трейлером). Заголовок может содержать дополнительную отладочную информацию, например дескриптор задачи, который его выделил. Кроме того, мне нравится иметь флаги/границы, такие как 0xA5A5A5A5, и 0x5A5A5A5A, чтобы помочь обнаружить, если кто-то где-то перезаписал границы их выделения памяти. Сохраняя списки свободных и используемых блоков, можно также периодически проверять целостность кучи и предотвращать операции (например, free () of unallocated память), что может привести к тому, что вещи "взорвутся".