Ответы:
Согласно спецификациям, malloc (0) вернет либо «нулевой указатель, либо уникальный указатель, который может быть успешно передан в free ()».
Это в основном позволяет вам ничего не выделять, но по-прежнему без беспокойства передавать переменную "artist" в вызов free (). Для практических целей это почти то же самое, что:
artist = NULL;
Стандарт C (C17 7.22.3 / 1) говорит:
Если размер запрошенного пространства равен нулю, поведение определяется реализацией: либо возвращается нулевой указатель, либо поведение такое, как если бы размер был некоторым ненулевым значением, за исключением того, что возвращаемый указатель не должен использоваться для доступа к объекту.
Таким образом, malloc(0)
может быть возвращен NULL
действительный указатель, который не может быть разыменован . В любом случае вполне допустимо называтьfree()
к нему.
Я не думаю, что в этом malloc(0)
есть много пользы, кроме случаев, когда malloc(n)
вызывается, например, в цикле, иn
может быть нулевым.
Глядя на код в ссылке, я считаю, что у автора было два заблуждения:
malloc(0)
всегда возвращает действительный указатель , иfree(0)
плохо.Таким образом, он удостоверился, что эта artist
и другие переменные всегда имеют какое-то «действительное» значение. Комментарий говорит так: // these must always point at malloc'd data
.
malloc(0)
возвращен действительный указатель, то malloc()
возврат NULL
всегда означает «сбой» и 0
больше не является особым случаем, что более согласованно.
malloc
отказа получить память определяются реализацией, реализация могла бы просто определить, что выделения размера 0 всегда неудовлетворительны ( ENOMEM
), и теперь malloc(0)
возврат 0 (с errno==ENOMEM
) согласован. :-)
realloc
указатель вернуть malloc(0)
? Ты можешь realloc((char*)NULL)
?
Поведение malloc (0) зависит от реализации. Библиотека может возвращать NULL или иметь обычное поведение malloc без выделенной памяти. Что бы он ни делал, это нужно где-то задокументировать.
Обычно он возвращает действительный и уникальный указатель, но НЕ должен разыменовываться. Также обратите внимание, что он МОЖЕТ потреблять память, даже если на самом деле ничего не выделял.
Можно перераспределить ненулевой указатель malloc (0).
Однако дословное использование malloc (0) не очень полезно. Это в основном используется, когда динамическое распределение имеет нулевой байт, и вы не позаботились о его проверке.
malloc()
должен где-то хранить «служебную информацию» (например, этот размер выделенного блока и другие вспомогательные данные). Таким образом, если malloc(0)
не возвращается NULL
, он будет использовать память для хранения этой информации, а если не free()
d, будет утечка памяти.
malloc()
не вернет, либо вернуть NULL
.
malloc(0)
. Однако в той же реализации стандартной библиотеки C realloc(ptr, 0)
освобождает ptr
и возвращает NULL.
В другом месте на этой странице есть ответ, который начинается со слов «malloc (0) вернет действительный адрес памяти, диапазон которого будет зависеть от типа указателя, которому выделяется память». Это утверждение неверно (у меня недостаточно репутации, чтобы напрямую комментировать этот ответ, поэтому не могу поместить этот комментарий прямо туда).
Выполнение malloc (0) не приведет к автоматическому выделению памяти правильного размера. Функция malloc не знает, к чему вы приводите ее результат. Функция malloc полагается исключительно на число размера, которое вы указываете в качестве аргумента. Вам нужно сделать malloc (sizeof (int)), чтобы получить достаточно памяти для хранения int, например, а не 0.
malloc(0)
не имеет для меня никакого смысла, если только код не зависит от поведения, специфичного для реализации. Если код предназначен для переносимости, то он должен учитывать тот факт, что возврат NULL malloc(0)
не является ошибкой. Так почему бы просто не присвоить NULLartist
любом случае , поскольку это допустимый успешный результат, меньше кода и не заставит ваших программистов по обслуживанию тратить время на его выяснение?
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)
или, malloc(some_variable_which_might_be_zero)
возможно, могут иметь их применение, хотя опять же, вы должны проявить особую осторожность, чтобы не рассматривать возврат NULL как сбой, если значение равно 0, но размер 0 должен быть нормальным.
Здесь есть много полуправдивых ответов, так что вот неопровержимые факты. На странице руководства malloc()
сказано:
Если size равен 0, то malloc () возвращает либо NULL, либо уникальное значение указателя, которое позже может быть успешно передано в free ().
Это означает, что нет абсолютно никакой гарантии, что результат malloc(0)
будет уникальным или не будет NULL. Единственная гарантия обеспечивается определением free()
, опять же, вот что говорится на странице руководства:
Если ptr равен NULL, никакая операция не выполняется.
Итак, что бы ни malloc(0)
вернулось, его можно смело передавать free()
. Но может и NULL
указатель.
Следовательно, писать artist = malloc(0);
ничем не лучше, чем писать. artist = NULL;
malloc(0)
можно было бы вернуть, скажем, 0x1, и free()
можно было бы иметь специальную проверку 0x1, как и для 0x0.
NULL
или уникальный указатель». вместо этого «либо нулевой указатель, либо указатель на выделенное пространство». Нет никакого уникального требования. OTOH, возвращающий неуникальное специальное значение может нарушить код, который рассчитывает на уникальные значения. Возможно, это угловой вопрос для SO.
man
может также задокументировать определяемую реализацией форму, используемую в * nix. В данном случае это не так, но это все еще не канонический источник для генерала С.
Почему тебе не следует этого делать ...
Поскольку возвращаемое значение malloc зависит от реализации, вы можете получить обратно NULL-указатель или какой-либо другой адрес. Это может привести к переполнению буфера кучи, если код обработки ошибок не проверяет и размер, и возвращаемое значение, что приводит к проблемам со стабильностью (сбоям) или еще более серьезным проблемам безопасности.
Рассмотрим этот пример, где дальнейший доступ к памяти через возвращенный адрес приведет к повреждению кучи, если размер равен нулю, а реализация возвращает значение, отличное от NULL.
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 Coding Standards, где я взял приведенный выше пример для дальнейшего чтения.
По общему признанию, я никогда раньше такого не видел, впервые вижу такой синтаксис, можно сказать классический случай избытка функций. В связи с ответом Рида я хотел бы указать, что есть похожая вещь, которая выглядит как перегруженная функция realloc
:
realloc(foo, size);
. Когда вы передаете в realloc указатель, отличный от NULL, и нулевой размер, realloc ведет себя так, как если бы вы вызвали free (…)realloc(foo, size);
,. Когда вы передаете NULL-указатель и размер не равен нулю, realloc ведет себя так, как если бы вы вызвали malloc (…)Надеюсь, это поможет, С уважением, Том.
malloc (0) вернет NULL или действительный указатель, который можно правильно передать как free. И хотя кажется, что память, на которую он указывает, бесполезна или не может быть записана или прочитана, это не всегда так. :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
Мы ожидаем здесь ошибки сегментации, но, что удивительно, это выводит 100! Это потому, что malloc на самом деле запрашивает огромный кусок памяти, когда мы вызываем malloc в первый раз. Каждый последующий вызов malloc использует память из этого большого фрагмента. Только после того, как этот огромный кусок закончится, запрашивается новая память.
Использование malloc (0): если вы находитесь в ситуации, когда вы хотите, чтобы последующие вызовы malloc выполнялись быстрее, вызов malloc (0) должен сделать это за вас (за исключением крайних случаев).
*i
может не завершиться в вашем случае, но, тем не менее, это неопределенное поведение. Остерегайтесь носовых демонов!
malloc(0)
этом не упоминается. В тех реализациях, где он возвращает значение, отличное от NULL, особенно в сборке DEBUG, он, скорее всего, выделяет БОЛЬШЕ, чем вы просили, и дает вам указатель на только что прошедший его внутренний заголовок. Это позволяет вам почувствовать фактическое использование памяти, если вы получите это до и после ряда распределений. например: void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;
или что-то подобное.
malloc(0)
. Не могли бы вы сказать, о какой главе вы тоже говорите? Было бы неплохо указать точную цитату.
В Windows:
void *p = malloc(0);
выделит буфер нулевой длины в локальной куче. Возвращенный указатель является действительным указателем кучи.malloc
в конечном итоге вызывает HeapAlloc
использование кучи времени выполнения C по умолчанию, которая затем вызывает RtlAllocateHeap
и т. д.free(p);
используется HeapFree
для освобождения буфера нулевой длины в куче. Если его не освободить, это приведет к утечке памяти.На самом деле это довольно полезно, и (очевидно, ИМХО) разрешенное поведение возврата указателя NULL нарушено. Динамический указатель полезен не только тем, на что он указывает, но и тем, что его адрес уникален. Возвращение NULL удаляет это второе свойство. Все встроенные маллоки, которые я программирую (на самом деле довольно часто), имеют такое поведение.
Не уверен, согласно некоторому случайному исходному коду malloc, который я обнаружил, ввод 0 приводит к возвращаемому значению NULL. Так что это безумный способ установить указатель исполнителя на NULL.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
Вот анализ после работы с инструментом проверки памяти valgrind.
==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 и так далее.
Согласно ответу Рида Копси и странице руководства malloc, я написал несколько примеров для тестирования. И я обнаружил, что malloc (0) всегда будет давать ему уникальное значение. См. Мой пример:
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
Результатом будет «Получен действительный указатель», что означает ptr
не ноль.
malloc(0)
вернет действительный адрес памяти, диапазон которого будет зависеть от типа указателя, которому выделяется память. Также вы можете назначать значения для области памяти, но они должны находиться в диапазоне с типом используемого указателя. Вы также можете освободить выделенную память. Я объясню это на примере:
int *p=NULL;
p=(int *)malloc(0);
free(p);
Приведенный выше код будет нормально работать в gcc
компиляторе на машине Linux. Если у вас 32-битный компилятор, вы можете указать значения в целочисленном диапазоне, например, от -2147483648 до 2147483647. То же самое относится и к символам. Обратите внимание, что при изменении типа объявленного указателя диапазон значений изменится независимо от malloc
приведенного типа, т.е.
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p
примет значение от 0 до 255 char, поскольку объявлено беззнаковым int.
malloc()
ничего не знает о приведении (что на самом деле полностью избыточно в C). Разыменование возвращаемого значения malloc(0)
вызовет неопределенное поведение.
Просто чтобы исправить ложное впечатление здесь:
artist = (char *) malloc(0);
никогда не вернется NULL
; это не то же самое, что artist = NULL;
. Напишите простую программу и сравните artist
с NULL
. if (artist == NULL)
ложно и if (artist)
верно.