Ответ 1
В соответствии с Single Unix Specification, malloc
вернет NULL
и установит errno
, когда он сработает.
Каков переносимый способ проверить, не удалось ли malloc
выделить ненулевой блок памяти?
В соответствии с Single Unix Specification, malloc
вернет NULL
и установит errno
, когда он сработает.
Я всегда делаю это:
tok = malloc( sizeof( char ) * ( strlen(tc) + 1 ) );
if( tok == NULL )
{
/* Malloc failed, deal with it */
}
Некоторые люди делают tok = (type) malloc( ... )
, но вы должны использовать результат, потому что, по-видимому, он покрывает некоторые неприятные ошибки. Я сделаю некоторые исследования и посмотрю, смогу ли я узнать, что они собой представляют.
Edit:
Кастинг malloc может скрыть отсутствующий #include <stdlib.h>
Я нашел эту ссылку, которая содержала очень хорошее объяснение:
http://cboard.cprogramming.com/faq-board/25799-faq-casting-malloc.html
"Итак, когда вы говорите это (char *) malloc (10)
Вы говорите, что принимаете все malloc возвращает, преобразует его в char *, и присваиваем это переменной в вопрос.
Это хорошо и хорошо, если malloc прототип правильно (путем включения stdlib.h), где он определяется как return void *.
Проблема возникает, когда вы не можете include stdlib.h, а компилятор изначально предполагает, что malloc возвращает int. Реальная проблема заключается в том, что вы НЕ ДОЛЖНЫ получить предупреждение от компилятора.
Вы весело конвертируете этот int в char * (через литой). На машинах где sizeof (char *) отличается от sizeof (int), код серьезно сломан.
Теперь, если у вас есть только char * var = malloc (10); И вы пропускаете включите, вы получите предупреждение от компилятора."
Конечно. Портативный способ - проверить, возвращается ли malloc(...)
NULL
.
Вы можете обнаружить сбой, если:
malloc(n)
возвращает NULL
Это самый распространенный и надежный тест для обнаружения отказа распределения. Если вы хотите быть переносимым за пределы POSIX/SUS, я бы не стал доверять errno
. Если вам нужны детали, скажем, для ведения журнала, я должен был бы обнулить errno
перед вызовом, посмотреть, изменилось ли оно, а затем, возможно, зарегистрировать это.
malloc(n)
возвращает не адрес NULL
, который не поддерживается фактической памятьюПрикоснитесь к нему и посмотрите, не убили ли вы ОС. Да, это может произойти. Он называл overcommit памяти и напоминает дробный резервный банк. Это оптимистичный подход к ОС или гипервизору для возврата адресов в виртуальную память, которую они играют в азартные игры, которые им никогда не понадобится. Это происходит на Linux, VMware. (Я не могу найти никаких явных доказательств чрезмерной обработки Windows, хотя запрошенные страницы только "зафиксированы" , когда они коснулись.)
Тогда возникает вопрос: "Как я уверенно обнаруживаю, что моя программа вот-вот потерпит крах при доступе к адресу, который я получил от malloc, которому я ранее доверял, как подростковая подача?". Одним из способов может быть read()
случайный файл в тестовой области и посмотреть, вернет ли ОС EINVAL или эквивалент.
Для дополнительных очков
malloc(0)
возвращает NULL
и оставляет errno
undefinedЯ знаю, что вопрос задан для "ненулевого [размера] блока памяти", но это интересно. Рассмотрим SUS-совместимый распределитель, который намеревается вернуть не NULL
для распределения нулевого размера (он может это сделать), но затем он терпит неудачу, поэтому он должен вернуть NULL
. И он может попытаться установить errno
. Это провал? Я думаю, что Хоар говорит, что мы заплатили миллиард долларов за эту двусмысленность. Таким образом, вызов malloc(0)
не переносится, и, вероятно, этот вопросник знал об этом!
malloc(n)
возвращает NULL
при ошибке. malloc(0)
может возвращать NULL
.
Чтобы обнаружить отказ:
void ptr = malloc(n);
if (ptr == NULL && n > 0) Handle_Failure();
Примечания:
Как и в случае OP: "... выделить ненулевой блок памяти", часто код таков, что запрос на размещение 0
не может быть выполнен, поэтому тест 0
не нужен.
size_t nstr = strlen(some_string) + 1;
void ptrstr = malloc(nstr);
if (ptrstr == NULL) Handle_Failure();
Некоторые системы устанавливают errno
при сбое, но не все. Установка errno
из-за сбоя выделения памяти не указана в спецификации C11.
malloc(n)
ожидает, что n
будет неподписанным типом size_t
. Использование int n
с отрицательным значением, безусловно, преобразуется в какое-то большое значение без знака, а затем, скорее всего, не удастся выделить память.