что возвращает 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
и возвращает указатель на новый выделенный буфер. Но если ... --14--> равно 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)
.
редактировать: кажется, я понимаю, в чем ваша путаница:
давайте рассмотрим фрагмент из вашего примера кода:
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()
буду еще, так любой другой 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)
is Реализации что касается C99.
С C99 [раздел 7.20.3]
порядок и непрерывность хранения, выделенные последовательными вызовами calloc, функции malloc и realloc не указаны. Указатель возвращается, если распределение успешно выровненную так, что он может быть отнесен к указателю на любой тип объекта а затем использовал для доступа к такому объект или массив таких объектов в выделенном пространстве (пока пространство не будет явно освобождено). Время жизни выделенного объекта продлевается от выделения до освобождения. Каждое такое распределение должно давать указатель на объект отделен от любого другого объекта. Указатель вернул точки в начало (самый низкий байт адрес) выделенного пространства. Если пространство не может быть выделена, указатель null возвращенный. Если размер запрошенное пространство равно нулю, поведение-реализация- определено: либо возвращается нулевой указатель, либо поведение, как если бы размер был некоторым ненулевое значение, за исключением того, что возвращается указатель не должен использоваться для доступа к объекту.
в C89 malloc (0) зависит от реализации - я не знаю, исправил ли C99 это или нет. В C++, используя:
char * p = new char[0];
хорошо определен - вы получаете действительный, ненулевой указатель. Конечно, вы не можете использовать указатель для доступа к тому, на что он указывает, без вызова неопределенного поведения.
что касается того, почему это существует, это удобно для некоторых алгоритмов и означает, что вам не нужно заполнять код тестами для нулевых значений.
стандарт C99
Если пространство не может быть выделено, а nullpointer возвращается. Если размер требуемое пространство равно нулю, поведение определяется реализацией: либо возвращается нулевой указатель, либо поведение, как если бы размер был некоторое ненулевое значение, за исключением того, что возвращенный указатель не должен использоваться для доступ к объекту.
на comp.ленг.C FAQ и следующее сказать:
стандарт ANSI / ISO говорит, что он может сделать что-либо; поведение реализация определена (см. вопрос 11.33). Портативный код должен или позаботиться не вызвать malloc( 0), или быть подготовлено для возможности null возвращаться.
поэтому, вероятно, лучше избегать использования malloc(0)
.
см. C99, раздел 7.20.3:
Если размер запрашиваемого пространства ноль, поведение implementationdefined: либо значение null возвращается указатель или поведение как будто размер был какой-то ненулевой значение, за исключением возвращенного указатель не должен использоваться для доступа к объект.
Это справедливо для всех трех функций выделения (т. е. calloc()
, malloc()
и realloc()
).
один момент, о котором никто не хотел говорить, в вашей первой программе это realloc
с длиной 0 это то же самое, что free
.
С man-страницы Solaris:
на
realloc()
функция изменяет размер указанного блока кptr
tosize
байт и возвращает указатель на (возможно переехали) блок. Содержание будет неизменным до меньший из новых и старых размеров. Еслиptr
isNULL
,realloc()
ведет себя какmalloc()
для указанного размера. Еслиsize
is0
и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
является допустимым указателем на блок памяти нулевого размера. The malloc
реализация сохраняет эту информацию в реализации определенным способом. realloc
знает (реализации) способ выяснить, что ptr
очки к блоку памяти нулевого размера.
(как malloc
/realloc
/free
это зависит от реализации. Одна из возможностей-выделить на 4 байта больше, чем требуется, и сохранить размер непосредственно перед блоком памяти. В таком случае ...--10--> даст размер блока памяти, который составляет 0
. Вы никогда не должны делать это из своего кода, он предназначен только для использования realloc
и free
).
мы реализовали структуры malloc для встроенного кода с заголовком (и дополнительным трейлером). Заголовок может содержать дополнительную отладочную информацию, такую как выделенный дескриптор задачи. Кроме того, мне нравится иметь флаги/границы, такие как 0xa5a5a5a5a5, и 0x5A5A5A5A, чтобы помочь обнаружить, если кто-то где-то перезаписал границы их выделения памяти. Сохраняя списки свободных и используемых блоков, можно также периодически проверять целостность кучи и предотвращать операции (например, free () нераспределенных память), что может привести к "взрыву".