Какое правильное использование realloc() при сбое и возвращает NULL?

Может ли кто-нибудь обобщить правильное использование realloc()?

Что вы делаете, когда realloc() терпит неудачу?

Из того, что я видел до сих пор, кажется, что если realloc() терпит неудачу, вы должны использовать free() старый указатель. Это правда?

Вот пример:

   1.  char *ptr = malloc(sizeof(*ptr) * 50);
   2.  ...
   3.  char *new_ptr = realloc(ptr, sizeof(*new_ptr) * 60);
   4.  if (!new_ptr) {
   5.      free(ptr);
   6.      return NULL;
   7.  }

Предположим, что realloc() терпит неудачу в строке 3. Правильно ли я делаю это на линии 5 на free() ing ptr?

Ответы

Ответ 1

От http://www.c-faq.com/malloc/realloc.html

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

Поэтому вам действительно нужно освободить ранее выделенную память.

Ответ 2

Это зависит от того, что вы хотите сделать. Когда realloc выходит из строя, что вы хотите сделать: освободите старый блок или сохраните его в живых и не изменив? Если вы хотите освободить его, то освободите его.

Имейте в виду также, что в C89/90, если вы делаете запрос realloc с нулевым размером цели, функция realloc может возвращать нулевой указатель, даже если исходная память была успешно освобождена. Это был дефект в C89/90, так как не удалось сказать успех от отказа при нулевом возврате.

В C99 этот дефект был исправлен, и была гарантирована строгая связь между нулевым возвратом и успехом/неудачей перераспределения. В C99 нулевой возврат всегда означает полный сбой realloc.

Ответ 3

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

Ответ 4

Edit: Correction, некоторые люди избивают меня за то, что я сказал, то, как вы выделили свой указатель, кажется, это лучшая практика среди них, меня учили всегда идти с типом cast в sizeof(), но, очевидно, ваш путь правильнее, поэтому не обращайте внимания на то, что я сказал =)

Взяв заглянуть в http://en.wikipedia.org/wiki/Malloc#realloc, вы, возможно, сделали вам что-то хорошее.

Вы не совсем понимаете sizeof() - он имеет значение размера аргумента, передаваемого ему в байтах. Например, sizeof(int) будет 4 в большинстве 32-битных систем, но вы должны использовать sizeof(int) вместо 4, потому что компиляция вашего кода в 64-битной системе (как пример) сделает это значение равным 8 и ваш код все равно будет компилироваться. Для чего вы выделяете память? Указатели? Если это так, вы должны использовать sizeof(void*) вместо этого (вы можете сказать sizeof(int*), но это общепринятое соглашение не упоминать компилятору, что вы хотите сохранить в этих указателях, поскольку все указатели должны быть одного размера - поэтому большинство программистов говорят sizeof(void*)), если вам нужно место для символов, используйте sizeof(char) и т.д.

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