Intereting Posts
Инициализация массивов в C Время принятое: основная сумма строки Основная сумма столбца пространство имен или пакеты в c-модулях Проверка того, является ли массив в C симметричным вернуться в libc работает в gdb, но не при запуске в одиночку Что делать, если malloc не удается? Есть ли макрос препроцессора C для печати структуры? C – преобразование в дополнение к 2s Почему мы используем оператор «& (*», когда двойной указатель на struct является аргументом функции? Быстрый поиск некоторых грызунов в двух ints с одинаковым смещением (C, микрооптимизация) Многоадресная рассылка, не принимаемая сетевыми компьютерами Почему тип с плавающей запятой C изменяет фактический ввод от 125.1 до 125.099998 на выходе? Изменение параметров framebuffer (/ dev / graphics / fb0) с использованием модуля Loadable Kernel найти палиндром, не работает с fgets Распределение памяти кучи

Должен ли я принудительно проверять realloc, если размер нового блока меньше начального?

Может ли realloc сбой в этом случае?

int *a = NULL; a = calloc(100, sizeof(*a)); printf("1.ptr: %d\n", a); a = realloc(a, 50 * sizeof(*a)); printf("2.ptr: %d\n", a); if(a == NULL){ printf("Is it possible?\n"); } return (0); 

}

Результат в моем случае:

 1.ptr: 4072560 2.ptr: 4072560 

Поэтому «a» указывает на тот же адрес. Так должен ли я проводить проверку realloc?

Позднее редактирование :

  • Использование компилятора MinGW в Windows XP.
  • Является ли поведение похожим на gcc на Linux?

Позже отредактируйте 2: Можно ли проверить этот путь?

 int *a = NULL, *b = NULL; a = calloc(100, sizeof(*a)); b = realloc(a, 50 * sizeof(*a)); if(b == NULL){ return a; } a = b; return a; 

Да, вы всегда должны проводить проверку на realloc или любое другое распределение памяти.

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

Вероятно, это когда-нибудь провалится? Наверное, нет, я был бы поражен, если бы мог найти случай, который он делает. Однако это не значит, что этого не произойдет. Обертка realloc в функции, которая автоматически выполняет проверку для каждой операции, достаточно проста, что нет причин не делать этого.

 void* xrealloc(void* ptr, size_t size) { ptr = realloc(ptr, size); if ( !ptr ) { exit(EXIT_FAILURE); } return ptr; } 

Было бы удивительно, если бы realloc потерпел неудачу, если был принят размер меньше первоначального распределения, но ничто в стандарте C (7.20.3.4) не гарантирует, что он всегда будет успешным:

Функция realloc освобождает старый объект, на который указывает ptr и возвращает указатель на новый объект, размер которого задан по size . Содержимое нового объекта должно быть таким же, как и у старого объекта до освобождения, вплоть до меньшего размера нового и старого. Любые байты нового объекта за пределами размера старого объекта имеют неопределенные значения.

Если ptr является нулевым указателем, функция realloc ведет себя как функция malloc для указанного размера. В противном случае, если ptr не соответствует указателю, ранее возвращенному функцией calloc , malloc или realloc , или если пространство было освобождено вызовом функции free или realloc , поведение не определено. Если память для нового объекта не может быть выделена, старый объект не освобождается и его значение не изменяется.

Возвращает

Функция realloc возвращает указатель на новый объект (который может иметь то же значение, что и указатель на старый объект), или нулевой указатель, если новый объект не может быть выделен.

Очень простая соответствующая реализация realloc будет realloc :

 void *realloc(void *ptr, size_t size) { void *new_ptr= malloc(size); if (new_ptr && ptr) { size_t original_size= _get_malloc_original_size(ptr); memcpy(new_ptr, ptr, min(original_size, size)); free(ptr); } return new_ptr; } 

В условиях низкой памяти (или любых условий, при которых malloc вернет NULL ), это вернет NULL .

Также было бы очень простой оптимизацией для возврата одного и того же указателя, если размер исходного распределения больше или равен запрашиваемому размеру. Но ничто в Стандарте C не диктует это.

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

В стандарте C99 §7.20.3.4 (realloc) говорится:

Функция realloc освобождает старый объект, на который указывает ptr, и возвращает указатель на новый объект, размер которого задан по размеру. Содержимое нового объекта должно быть таким же, как и у старого объекта до освобождения, вплоть до меньшего размера нового и старого. Любые байты нового объекта за пределами размера старого объекта имеют неопределенные значения.

Если ptr является нулевым указателем, функция realloc ведет себя как функция malloc для указанного размера. В противном случае, если ptr не соответствует указателю, ранее возвращенному функцией calloc, malloc или realloc, или если пространство было освобождено вызовом функции free или realloc, поведение не определено. Если память для нового объекта не может быть выделена, старый объект не освобождается и его значение не изменяется.

Возвращает

Функция realloc возвращает указатель на новый объект (который может иметь то же значение, что и указатель на старый объект), или нулевой указатель, если новый объект не может быть выделен.

Обратите внимание, что старый объект освобождается; новый объект может оказаться в том же месте, что и старый. И могут быть проблемы. Это маловероятно, но гораздо проще пойти с правилом «всегда», чем иметь странные исключения.

Обычный аргумент-аргумент – «если это не может потерпеть неудачу, значит, у меня есть путь ошибки, который я не могу проверить». До точки, это правда. Однако может случиться, что некоторая портирование памяти так, что распределение не может быть успешным, потому что информация управления повреждена. Скорее всего, вы просто получите дамп ядра, но, возможно, код достаточно прочен, чтобы избежать этого. (Я предполагаю, что жестко закодированные 100 и 50 предназначены для того, чтобы задавать вопрос: код реальной жизни не будет чрезмерно распределяться, когда он знает, сколько ему действительно нужно.)

Там, где два вызова «realloc ()» смежны, как здесь, есть очень мало места для чего-либо, чтобы пойти не так. Тем не менее, рабочий код реальной жизни будет иметь некоторые операции между ними – и этот код может привести к сбою второго «realloc ()».

Что касается вашего «Редактировать 2» …

Код может быть лучше написан как:

 if (b != NULL) a = b; return a; 

Но основная концепция в порядке. Обратите внимание, что в стандарте явно указано, что исходное распределение безопасно, если новое невозможно создать.

Время, необходимое для проверки, настолько мало по сравнению с временем, проведенным в realloc (), что я даже не могу понять, почему это будет проблемой. Или вы хотите уменьшить количество строк кода?

realloc() может вернуть NULL достаточно легко при уменьшении размера.

 void *ptr = malloc(10); ptr = realloc(ptr, 0); if (ptr == NULL) { puts("Failure because return value is NULL? - not really"); } 

realloc(any_pointer, 0) может возвращать NULL или, возможно, некоторый указатель not-NULL , это реализация определена.

Вот почему ошибка realloc()/malloc() не должна быть простой проверкой if (ptr == NULL) но

 void *ptr = malloc(newsize); // or realloc(..., newsize) if (ptr == NULL && newsize > 0) { exit(0); // Handle OOM; } 

Из-за этой двусмысленности код должен сделать оболочку realloc() , порекомендовать что-то вроде:

 void *xrealloc(void *ptr, size_t newsize, bool *falure) { *failure = 0; if (newsize > 0) { void *tmp = realloc(ptr, newsize); if (tmp == NULL) { *failure = 1; return ptr; // old value } return tmp; // new value } free(ptr); return NULL; // new value } 

Таким образом, получение NULL в realloc() с уменьшенным размером не является неудачным, поэтому этот ответ касается только тангенциально, но вопрос OP: «… принудительно выполнить realloc, если новый размер блока меньше начального?» а затем использовала менее достоверную, if (ptr == NULL) парадигму.