какой смысл в malloc(0)?

только что видел этот код:

artist = (char *) malloc(0);

и мне было интересно, зачем это делать?

16 ответов


согласно спецификации, malloc (0) вернет либо " нулевой указатель, либо уникальный указатель, который может быть успешно передан в free()".

это в основном позволяет вам ничего не выделять, но все равно передавать переменную "исполнитель" вызову free() без беспокойства. Для практических целей это почти то же самое, что делать:

artist = NULL;

стандарт C говорит:

если пространство не может быть выделена, указатель null возвращенный. Если размер запрашиваемого пространства равен нулю, поведение определяется реализацией: либо возвращается нулевой указатель, либо поведение, как если бы размер был некоторым ненулевое значение, за исключением того, что возвращается указатель не должен использоваться для доступа к объекту.

и malloc(0) может вернуться NULL или допустимый указатель этого может и не быть разыменован. В любом случае, это совершенно справедливо для вызова free() на нем.

не думаю malloc(0) имеет много пользы, за исключением случаев, когда malloc(n) вызывается в цикле, например, и n может быть ноль.

глядя на код в ссылке, я считаю, что у автора было два заблуждения:

  • malloc(0) возвращает допустимый указатель всегда и
  • free(0) is плохой.

Итак, он убедился, что artist и другие переменные всегда имели некоторое "действительное" значение в них. Комментарий говорит так много:// these must always point at malloc'd data.


поведение malloc(0) специфично для реализации. Библиотека может возвращать NULL или иметь обычное поведение malloc без выделенной памяти. Что бы это ни было, оно должно быть где-то задокументированы.

обычно он возвращает указатель, который является допустимым и уникальным, но не должен быть разыменован. Также обратите внимание, что он может потреблять память, даже если на самом деле ничего не выделяет.

можно перераспределить ненулевой указатель malloc(0).

имея однако malloc (0) verbatim не очень полезен. Он в основном используется, когда динамическое распределение равно нулю байта, и вы не хотели его проверять.


в другом месте на этой странице есть ответ, который начинается "malloc (0) вернет допустимый адрес памяти и диапазон которого будет зависеть от типа указателя, который выделяется памяти". Это утверждение неверно (у меня недостаточно репутации, чтобы прокомментировать этот ответ напрямую, поэтому я не могу поместить этот комментарий прямо под ним).

выполнение malloc (0) будет не автоматически выделять память правильного размера. Функция malloc не знает о том, что вы бросая свой результат. Функция malloc полагается исключительно на номер размера, который вы даете в качестве аргумента. Вам нужно сделать malloc(sizeof (int)), чтобы получить достаточно места для хранения int, например, не 0.


есть много наполовину правдивых ответов здесь, так что вот жесткие факты. Человек-страница для malloc() говорит:

если size равен 0, то malloc () возвращает либо NULL, либо уникальное значение указателя, которое может быть позже успешно прошел бесплатно().

это означает, что нет абсолютно никакой гарантии, что результат malloc(0) является уникальным или не NULL. Единственная гарантия предоставляется определением free() опять же, вот что человек-страница говорит:

если ptr равно NULL, операция не выполняется.

так, что malloc(0) возвращает, его можно безопасно передать в free(). Но и a NULL указатель.

следовательно, писать artist = malloc(0); ничуть не лучше, чем писать artist = NULL;


malloc(0) не имеет никакого смысла для меня, если код не полагается на поведение, специфичное для реализации. Если код предназначен для переносимости, то он должен учитывать тот факт, что NULL возвращает из malloc(0) Это не провал. Так почему бы просто не назначить NULL artist в любом случае, так как это действительный успешный результат, и меньше кода, и не заставит ваших программистов по обслуживанию потратить время на его выяснение?

malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO) или malloc(some_variable_which_might_be_zero) возможно, могли бы их использовать, хотя снова вам нужно позаботиться о том, чтобы не рассматривать нулевое возвращение как сбой, если значение равно 0, но размер 0 должен быть в порядке.


По общему признанию, Я никогда не видел этого раньше, это первый раз, когда я видел этот синтаксис, можно сказать, классический случай перебора функций. В связи с ответом Рида я хотел бы отметить, что есть аналогичная вещь, которая выглядит как перегруженная функция realloc:

  • foo не является нулевым, а размер равен нулю,realloc(foo, size);. Когда вы передаете ненулевой указатель и размер нуля для перераспределения, realloc ведет себя так, как если бы вы вызвали free(...)
  • foo равно NULL а размер ненулевой и больше 1,realloc(foo, size);. Когда вы передаете нулевой указатель и размер не равен нулю, realloc ведет себя так, как если бы вы вызвали malloc(...)

надеюсь, это поможет, С уважением, Том.


чтобы на самом деле ответить на вопрос сделал:нет причин делать это


почему вы не должны делать этого...

поскольку возвращаемое значение malloc зависит от реализации, вы можете получить нулевой указатель или другой адрес. Это может привести к переполнению буфера кучи, если код обработки ошибок не проверяет размер и возвращаемое значение, что приводит к проблемам стабильности (сбоям) или еще худшим проблемам безопасности.

рассмотрим этот пример, где дальнейший доступ к памяти через возвращаемый адрес приведет к повреждению размера кучи iff равен нулю и реализации возвращает ненулевое значение обратно.

size_t size;

/* Initialize size, possibly by user-controlled input */

int *list = (int *)malloc(size);
if (list == NULL) {
  /* Handle allocation error */
}
else {
  /* Continue processing list */
}

посмотреть эта безопасная страница кодирования из стандартов кодирования CERT, где я взял пример выше для дальнейшего чтения.


Не уверен, согласно некоторым случайный источник malloc код, который я нашел, ввод 0 приводит к возвращаемому значению NULL. Таким образом, это сумасшедший способ установки указателя исполнителя на NULL.

http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html


malloc (0) вернет NULL или допустимый указатель, который может быть правильно передан в free. И хотя кажется, что память, на которую она указывает, бесполезна или не может быть записана или прочитана, это не всегда верно. :)

int *i = malloc(0);
*i = 100;
printf("%d", *i);

мы ожидаем ошибки сегментации здесь, но удивительно, что это печатает 100! Это потому, что Мэллок на самом деле просит огромный кусок памяти, когда мы вызываем Мэллока в первый раз. Каждый вызов malloc после этого использует память из этого большого куска. Только после того, как этот огромный кусок закончился, запрашивается новая память.

использование malloc(0): если вы находитесь в ситуации, когда вы хотите, чтобы последующие вызовы malloc были быстрее, вызов malloc (0) должен сделать это за вас (за исключением крайних случаев).


В Windows:

  • void *p = malloc(0); выделит буфер нулевой длины в локальной куче. Возвращаемый указатель является допустимым указателем кучи.
  • malloc в конечном счете называет HeapAlloc используя кучу времени выполнения C по умолчанию, которая затем вызывает RtlAllocateHeap, etc.
  • free(p); использует HeapFree чтобы освободить буфер 0-длины в куче. Не освобождение приведет к утечке памяти.

вот анализ после запуска с valgrind memory check tool.

==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740==     in use at exit: 0 bytes in 0 blocks
==16740==   total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible

и вот мой пример кода:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
   //int i;
   char *p1;

   p1 = (char *)malloc(0);
   printf("p1 = %p\n", p1);

   free(p1);

   return 0;

}

по умолчанию выделяется 1024 байта. Если я увеличу размер malloc, выделенные байты увеличатся на 1025 и так далее.


по данным Рид Copsey ответ и man-страница malloc, я написал несколько примеров для тестирования. И я узнал, что malloc (0) всегда будет давать ему уникальное значение. См. мой пример:

char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
    puts("Got a null pointer");
else
    puts("Got a valid pointer");

вывод будет "получил действительный указатель", что означает ptr не null.


malloc(0) возвращает действительный адрес памяти и диапазон которого будет зависеть от типа указателя, который выделяется память. Также вы можете назначить значения области памяти, но это должно быть в диапазоне с типом используемого указателя. Также можно освободить выделенную память. Я объясню это на примере:

int *p=NULL;
p=(int *)malloc(0);
free(p);

приведенный выше код будет работать нормально в gcc компилятор на Linux-машине. Если у вас есть 32-битный компилятор, вы можете предоставить значения в integer диапазон, т. е. от -2147483648 до 2147483647. То же самое относится и к персонажам. Обратите внимание, что если тип объявленного указателя изменен, диапазон значений изменится независимо от malloc typecast, то есть

unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);

p будет принимать значение от 0 до 255 char, так как он объявлен unsigned int.


просто, чтобы исправить ложное впечатление здесь:

artist = (char *) malloc(0); никогда не вернуться NULL, это не то же самое как artist = NULL;. Напишите простую программу и сравните artist С NULL. if (artist == NULL) false и if (artist) - это правда.