Освобождение символьного указателя
Вопрос
У меня есть функция, которая вызывается несколько раз во время выполнения программы.В указанной функции у меня есть динамический символьный указатель, размер которого я изменяю множество раз.
Мой вопрос заключается в следующем:нужно ли мне освобождать этот указатель до завершения работы функции?
void functionName()
{
char *variable = (char *) malloc(0);
//variable is resized with realloc x number of times
//should free be called here?
return;
}
Я должен также отметить, что я попытался освободить указатель, однако, gdb предупреждает меня, когда я это делаю.
Решение
Да, вы должны освободить его или утерить память. Ваш код должен выглядеть что-то подобное:
void function(void)
{
char *variable = (char *)malloc(0);
variable = realloc(variable, 10);
// do something with new memory
variable = realloc(variable, 20);
// do something with more new memory
free(variable); // clean up
}
Призыв malloc(0)
Я думаю, немного странно.
Другие советы
Необходимо отметить несколько моментов:
Я не понимаю, как ты используешь realloc()
в вашем коде, но если вы используете его таким образом, это неправильно:
variable = realloc(variable, amount);
Когда он не может выделить больше памяти, realloc()
ВОЗВРАТ NULL
но оставляет исходный указатель неизменным.В приведенной выше строке это означает, что variable
является NULL
и мы потеряли доступ к памяти, на которую он указывал, но эта память не была освобождена.Правильная идиома такова:
void *tmp = realloc(variable, amount);
if(tmp)
{
// success! variable invalid, tmp has new allocated data
variable = tmp;
}
else
{
// failure! variable valid, but same size as before, handle error
}
Причина, по которой вы должны использовать второй вариант, заключается в том, что с realloc()
, отказ - это плохо, но вполне поправимо во многих ситуациях, в отличие от malloc()
где неудача обычно означает "бросить все и умереть".
Это более спорный вопрос, но сомнительно, следует ли вам приводить возвращаемое значение malloc()
и realloc()
как и ты.Рассмотреть:
// functionally identical in C
char *a = malloc(10);
char *b = (char *)malloc(10);
В C ++ приведение должен быть созданным, потому что в C ++ void *
не может быть неявно преобразован в другой тип указателя.(Я думаю, что это языковая ошибка, но не мне судить.) Если ваш код написан на C ++, вы должны использовать new
и delete
в любом случае.Если ваш код написан на C, но его необходимо скомпилировать с помощью компиляторов C ++ (по какой-то бессмысленной причине), у вас нет выбора, кроме как выполнить приведение.Если вам не нужно компилировать код C с помощью компиляторов C ++ (что аналогично необходимости запускать код Ruby в интерпретаторе Python), перейдите к пунктам ниже, вот почему я думаю, что вам не следует приводить.
В C89, если функция используется без объявления, она будет неявно объявлена как возвращающая
int
.Если, скажем, мы забыли#include <stdlib.h>
и мы позвонилиmalloc()
, версия без приведения вызвала бы ошибку компилятора (неявные приведения изint
Дляchar *
не разрешены), в то время как версия с приведением (ошибочно) сообщит компилятору "Я знаю, это звучит безумно, но все равно приведите это". Большинство компиляторов выдадут вам предупреждение о неявных (или несовместимых) объявлениях встроенных функций, таких какmalloc()
, но актерский состав действительно усложняет поиск.Допустим, у вас есть какие-то данные:
float *array = (float *)malloc(10 * sizeof(float));
Позже вы обнаружите, что вам нужна большая точность ваших данных, и вам придется сделать это
double
массив.В приведенной выше строке вам нужно изменить не более 3-х разных мест:double *array = (double *)malloc(10 * sizeof(double));
Если бы, с другой стороны, вы написали:
float *array = malloc(10 * sizeof *array);
Вам нужно будет только измениться
float
Дляdouble
на 1 месте.Кроме того, всегда используяsizeof *obj
вместо того, чтобыsizeof(type)
и никогда не использование приведений означает, что более поздний вызовrealloc()
может работать без каких-либо изменений, в то время как использование приведений и явных имен типов потребовало бы поиска в любом месте , которое вы вызывалиrealloc
и меняйте слепки , иsizeof
s.Также, если вы забудете, сделайте и это:double *array = (float *)malloc(10 * sizeof(float));
На большинстве платформ,
array
теперь это будет только массив из 5 элементов, при условии, что выравнивание не отключено и компилятор не жалуется на то, что вы назначаетеfloat *
к adouble *
.Некоторые считают предупреждение, которое выдает компилятор, полезным, поскольку оно указывает на потенциально неправильные строки.Однако, если мы избегаемsizeof(type)
и избегать приведения, мы можем видеть, что линии не будет быть неверными, поэтому привлечение внимания компилятора к ним - пустая трата времени, которое мы могли бы использовать для программирования.
От страницы человека:
Если размер равно 0, то Malloc () возвращает либо NULL, либо уникальное значение указателя, которое позже может быть успешно передано в Free ().
Итак, я верю, что ответ «да» :).
Да, вам нужно позвонить бесплатно () один раз, чтобы выпустить блок памяти. Вам не нужно позвонить бесплатно для последующих Reallocs (), даже если они возвращают другой адрес / указатель. Менеджер памяти знает, что старый блок больше не нужен и освободит ().
Вы должны быть в состоянии просто позвонить free(variable)
в конце. Если realloc
когда-либо должен переместить данные, чтобы изменить его, это называет free
Внутренне, вам не нужно беспокоиться об этом.
Кроме того, где вы инициализировать variable
, вы могли бы просто установить это NULL
вместо звонка malloc
; realloc
будет работать так же, как malloc
первый раз.
Посмотрите на некоторые ответы, которые я дал пару вопросов в отношении управления памятью:
- Почему утечки памяти распространены?
- Какой смысл в malloc (0)?
- С строкой путаница?
- Нужна помощь в решении ошибки сегментации.
- C STDLIB RealLoc Проблема?
- C: Создание массива строк из разграниченных строк.
Все вышеперечисленное указывают на очевидную вещь, Для каждого Malloc есть бесплатный, если нет утечки памяти, так это обязательно, чтобы вы free
память, когда вы закончите с вашим переменной указателя, которая malloc
др.
Надеюсь, это поможет, наилучшие пожелания, Том.
int main(int argc, char *argv[])
{
char *p = malloc(sizeof(argv[1]));
p = argv[1];
printf("%s\n", p);
free(p);
return 0;
}
IAM получил ошибку Glibc
hello
*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00007fff66be94c6 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f38dca1db96]
./a.out[0x4005ed]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f38dc9c076d]