Realloc на нулевом (или неопределенном) указателе

Я читал о realloc и запутался в вопросе, упомянутом там. Рассмотрим код ниже:

#include <stdio.h>
#include <stdlib.h>

int main () {

    int* ptr = NULL;
    ptr = realloc(ptr, 10*sizeof(int));
    return 0;
}

есть ли опасность в выделении памяти с realloc используя первоначально NULL-valued ptr? Если вместо:

int* ptr = NULL;

у меня было так:

int* ptr; // no value given to ptr

было бы проблемой позвонить realloc используя ptr?

3 ответов


есть ли опасность в выделении памяти с помощью realloc с помощью изначально нулевое значение ptr

нет

7.22.3.5

если ptr является нулевым указателем, функция realloc ведет себя как malloc функция для указанного размера.

для второй части:

int* ptr; // no value given to ptr

было бы проблемой вызвать realloc с помощью ptr?

если вы используете неинициализированные указатели тогда это очень серьезная проблема, так как вы не можете предсказать, какова будет их ценность. Функция realloc корректно работает только для NULL или значения, полученные из malloc / realloc.

в противном случае, если ptr не соответствует указателю, ранее возвращенному a функция управления памятью [...] поведение не определено


при показанном конкретном коде нет проблем с использованием нулевого указателя изначально.

если переменная ptr неинициализирован - не установлен в 0 или NULL-тогда любой вызов realloc() использование опасно; поведение не определено, и если Вам ПОВЕЗЕТ, программа рухнет, но если вам не повезет, она будет работать некоторое время, пока что-то не пойдет не так позже в программе, где будет трудно определить, что проблема в коде выполняется долгое время тому назад.

есть те, кто утверждает, что лучше использовать malloc() для первоначального распределения и realloc() далее. Есть некоторая справедливость в предложении, не в последнюю очередь потому, что вы, вероятно, не использовали бы ptr = realloc(ptr, 0); чтобы освободить память, хотя вы могли бы это сделать (так что вам действительно не нужно malloc() или free(), потому что realloc() может выполнять все три операции). Но стандарт C90 требует realloc(0, new_size) работать эквивалентно malloc(new_size), и я не знаю библиотеки C, которая ведет себя по-другому (но могут быть некоторые; я использовал только несколько библиотек C, хотя в основном наиболее широко используемые).


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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char    *ptr = NULL;
    size_t   len = 0;
    char     buffer[256];

    while (fgets(buffer, sizeof(buffer), stdin))
    {
        size_t buflen = strlen(buffer) + 1;
        if (buflen > len)
        {
            if ((ptr = realloc(ptr, buflen)) == 0)  // Danger!
                // ... handle memory allocation failure ...
            len = buflen;
        }
        strcpy(ptr, buffer);
        // ... do something with ptr
    }
    free(ptr);
    return 0;
}

в чем опасность? Опасность заключается в том, что если второе или последующее выделение памяти не удается и ptr является единственным указателем на выделенную память, вы просто переписываете ее Предыдущее значение с null. Это означает, что вы не можете освободить выделенную память с помощью ptr больше нет-у вас утечка памяти. (Для первого распределения начальное значение равно 0, перезаписанное значение равно нулю, и ничего не изменилось; утечки памяти нет. Вот почему цикл был добавлен в код.)

правило

  • не пиши ptr = realloc(ptr, newsize);

сохраните новое значение в отдельной переменной, пока вы не протестировали он.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char    *ptr = NULL;
    size_t   len = 0;
    char     buffer[256];

    while (fgets(buffer, sizeof(buffer), stdin))
    {
        size_t buflen = strlen(buffer) + 1;
        if (buflen > len)
        {
            char *new_ptr = realloc(ptr, buflen);
            if (new_ptr == 0)
                // ... handle memory allocation failure ...
            ptr = new_ptr;
            len = buflen;
        }
        strcpy(ptr, buffer);
        // ... do something with ptr
    }
    free(ptr);
    return 0;
}

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

вспомогательная рекомендация: не используйте переменную с именем new; это затруднит компиляцию с компилятором c++. Даже если у вас нет намерения конвертировать в C++ (и даже если вы, вероятно, в конечном итоге перепишете управление памятью, если вы это сделаете), нет никакого преимущества в использовании ключевого слова c++new как имя переменной C...если вы явно не хотите предотвратить компиляции с компилятором c++.


существует ли опасность выделения памяти с помощью realloc с использованием изначально нулевого ptr?

нет, это было бы точно как malloc.

если вместо:

int* ptr = NULL;

у меня было так:

int* ptr; // no value given to ptr

было бы проблемой вызвать realloc с помощью ptr?

да, будет проблема. Если realloc нет NULL, он попытается расширить память, начиная с этого местоположение, или мая попытаться free и malloc другая часть памяти. С неинициализированные переменные могут иметь любое значение, шансы очень высоки, они не являются стоимостью realloc любит. Если Вам ПОВЕЗЕТ, ваша программа немедленно рухнет.