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
любит. Если Вам ПОВЕЗЕТ, ваша программа немедленно рухнет.