Правильное использование realloc()

From man realloc: функция realloc () возвращает указатель на вновь выделенную память, которая соответствующим образом выровнена для любой переменной и может быть отличается от ptr или NULL, если запрос не выполняется.

Так вот в этом фрагменте кода:

ptr = (int *) malloc(sizeof(int));
ptr1 = (int *) realloc(ptr, count * sizeof(int));
if(ptr1 == NULL){           //reallocated pointer ptr1
    printf("Exiting!!n");
    free(ptr);
    exit(0);
}else{
    free(ptr);          //to deallocate the previous memory block pointed by ptr so as not to leave orphaned blocks of memory when ptr=ptr1 executes and ptr moves on to another block
    ptr = ptr1;         //deallocation using free has been done assuming that ptr and ptr1 do not point to the same address                     
}

достаточно ли просто предположить, что перераспределенный указатель указывает на другой блок memeory, а не на тот же блок.Потому что, если предположение будет ложным и realloc возвращает адрес исходного блока памяти, на который указывает ptr, а затем free(ptr) выполняется (по причине, приведенной в комментариях), тогда блок памяти будет стерт, и программа сойдет с ума. Должен ли я поставить другое условие, которое будет сравнивать равенство ptr и ptr1 и исключать выполнение свободного(ptr) оператора?

6 ответов


просто не звони free() на вашем оригинальном ptr в счастливом пути. По существу realloc() сделал это для вас.

ptr = malloc(sizeof(int));
ptr1 = realloc(ptr, count * sizeof(int));
if (ptr1 == NULL) // reallocated pointer ptr1
{       
    printf("\nExiting!!");
    free(ptr);
    exit(0);
}
else
{
    ptr = ptr1;           // the reallocation succeeded, we can overwrite our original pointer now
}

OP: ... может отличаться от ptr или NULL в случае сбоя запроса.
О: не всегда. NULL может быть законно возвращен (не сбой), если count равен 0.

OP: достаточно ли просто предположить, что перераспределенный указатель указывает на другой блок памяти, а не на тот же блок.
A: Нет

OP: должен ли я поставить другое условие, которое будет сравнивать равенство ptr и ptr1 и исключать выполнение свободного (ptr) заявление?
отсутствие.

если realloc() возвращает NULL (и count не 0), значение ptr по-прежнему действует, указывая на данные без изменения размера. free(ptr) или нет, зависит от ваших целей.

если realloc() возвращает не NULL, не free(ptr), все готово.

пример: https://codereview.stackexchange.com/questions/36662/critique-of-realloc-wrapper

#include <assert.h>
#include <stdlib.h>

int ReallocAndTest(char **Buf, size_t NewSize) {
  assert(Buf);
  void *NewBuf = realloc(*Buf, NewSize);
  if ((NewBuf == NULL) && (NewSize > 0)) {
    return 1;  // return failure
  }
  *Buf = NewBuf;
  return 0;
}

применение исправлений правок в комментариях ниже.

чтение этот комп.ленг.С вопрос, выявлены 3 случая:

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

это можно перевести непосредственно в код:

int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
    // Case 3, clean up then terminate.
    free(ptr);
    exit(0);
}
else if(tmp == ptr)
{
    // Case 1: They point to the same place, so technically we can get away with
    // doing nothing.
    // Just to be safe, I'll assign NULL to tmp to avoid a dangling pointer.
    tmp = NULL;
}
else
{
    // Case 2: Now tmp is a different chunk of memory.
    ptr = tmp;
    tmp = NULL;
}

Итак, если вы думаете об этом, код, который вы разместили, в порядке (почти). Приведенный выше код упрощает:

int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
    // Case 3.
    free(ptr);
    exit(0);
}
else if(ptr != tmp)
{
    ptr = tmp;
}
// Eliminate dangling pointer.
tmp = NULL;

отметить лишнее else if(ptr != tmp), что исключает Случай 1, где вы не хотели бы вызывать free(ptr), потому что ptr и tmp обратитесь к тому же месту. Кроме того, просто для безопасности, я делаю назначить NULL to tmp чтобы избежать каких-либо проблем с висячим указателем, пока tmp в области.


realloc вернет тот же адрес в ptr Если у него достаточно места для расширения фактического куска памяти, на который указывает ptr. В противном случае он переместит данные в новый фрагмент и освободит старый фрагмент. Вы не можете положиться на ptr1 отличается от ptr. Ваша программа ведет себя неопределенно.

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

кстати, никогда не бросайте возвращение malloc/realloc :). Ваш код должен быть таким:

ptr=malloc(sizeof(int));
ptr=realloc(ptr,count*sizeof(int));
if(ptr==NULL)
{   
    // error!    
    printf("\nExiting!!");
    // no need to free, the process is exiting :)
    exit(0);
}

Если realloc перемещает ваши данные, он освободит старый указатель для вас за кулисами. У меня нет копии стандарта C11, но это гарантировано в стандарте C99.


вы должны не free ваш исходный указатель, если realloc успешно. Являетесь ли вы free этот указатель, если realloc не зависит от потребностей конкретного приложения; если вы абсолютно не может продолжать без этой дополнительной памяти это будет фатальная ошибка, и вы освободите любое удерживаемое хранилище и выйдете. Если, OTOH, вы все еще можете продолжить (возможно, выполнить другую операцию и надеяться, что память будет доступна позже), вы, вероятно, захотите сохранить эту память и попытаться другой realloc позже.

глава и стих:

7.22.3.5 функция realloc

справка

1
     #include <stdlib.h>
     void *realloc(void *ptr, size_t size);

описание

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

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

возвращает

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

Курсив. Примечание п. 4; возвращенный указатель может быть такой же, как и исходный указатель.