it-roy-ru.com

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

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

artist = (char *) malloc(0);

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

106
jldupont

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

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

artist = NULL;
109
Reed Copsey

Стандарт 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.

46
Alok Singhal

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

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

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

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

9
Coincoin

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

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

4
Krellan

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

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

3
Steve Jessop

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

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

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

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

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

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

3
cmaster

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

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

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

2
t0mm13b

Почему ты не должен делать это ...

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

Рассмотрим этот пример, где дальнейший доступ к памяти через возвращенный адрес приведет к повреждению кучи, если размер равен нулю, а реализация возвращает значение, отличное от 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, где я взял приведенный выше пример для дальнейшего чтения.

2
auselen

Чтобы на самом деле ответить на поставленный вопрос: нет никаких оснований для этого

1
Paolo

В Windows:

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

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

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

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

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

0
Sagar Bhosale

На самом деле это весьма полезно, и (очевидно, ИМХО) допустимое поведение возврата NULL-указателя нарушено. Динамический указатель полезен не только для того, на что он указывает, но также и потому, что его адрес уникален. Возвращение NULL удаляет это второе свойство. Все встроенные malloc, которые я программирую (довольно часто на самом деле), имеют такое поведение.

0
Scott Franco