Освобождение указателя на символ - PullRequest
1 голос
/ 31 января 2010

У меня есть функция, которая вызывается несколько раз во время выполнения программы. В указанной функции у меня есть динамический символьный указатель, который я меняю несколько раз.

У меня вопрос: нужно ли освободить этот указатель до конца функции?

void functionName()
{
 char *variable = (char *) malloc(0);
    //variable is resized with realloc x number of times

 //should free be called here?
 return;
}

Следует также отметить, что я попытался освободить указатель, однако gdb выдает мне предупреждения, когда я делаю это.

Ответы [ 7 ]

3 голосов
/ 01 февраля 2010

Несколько замечаний:

Я не вижу, как вы используете 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), перейдите к пунктам ниже, поэтому я думаю, что вам не следует приводить.

  1. В C89, если функция используется без объявления, она будет неявно объявлена ​​как возвращающая int. Если, скажем, мы забыли #include <stdlib.h> и вызвали malloc(), версия без преобразования вызовет ошибку компилятора (неявные преобразования от int до char * не допускаются), в то время как версия с приведением (неправильно) сказал бы компилятору: «Я знаю, это звучит безумно, но все равно произнесу». Большинство компиляторов будут предупреждать вас о неявных (или несовместимых) объявлениях встроенных функций, таких как malloc(), но приведение затрудняет поиск.

  2. Скажем, у вас есть некоторые данные:

    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 с. Также, если вы забудете и сделаете это:

    double *array = (float *)malloc(10 * sizeof(float));
    

    На большинстве платформ array теперь будет представлять собой массив из 5 элементов, при условии, что выравнивание не отключено, и компилятор не будет жаловаться, что вы присваиваете float * для double *. Некоторые считают полезным предупреждение о проблемах компилятора, поскольку оно указывает на потенциально неправильные строки. Однако, если мы избегаем sizeof(type) и избегаем приведения, мы можем видеть, что строки не будут некорректными, поэтому компилятор, обращающий на них внимание, тратит время, которое мы могли бы использовать для программирования.

3 голосов
/ 31 января 2010

Да, вы должны освободить его, или вы потеряете память. Ваш код должен выглядеть примерно так:

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) немного странно, я думаю.

0 голосов
/ 27 марта 2013
int main(int argc, char *argv[])
{
        char *p = malloc(sizeof(argv[1]));

        p = argv[1];
        printf("%s\n", p);
        free(p);
        return 0;
}

я получаю ошибку 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]
0 голосов
/ 31 января 2010

Посмотрите на некоторые ответы, которые я дал на пару вопросов, касающихся управления памятью:

Все вышеперечисленное указывает на очевидную вещь, для каждого malloc есть свободное место, если нет утечки памяти , поэтому крайне важно, чтобы вы free запомнили, когда закончите с вашей переменной-указателем malloc d.

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

0 голосов
/ 31 января 2010

Вы должны просто позвонить free(variable) в конце. Если realloc когда-либо приходится перемещать данные, чтобы изменить их размер, он вызывает free внутри, вам не нужно беспокоиться об этом.

Кроме того, там, где вы инициализируете variable, вы можете просто установить его на NULL вместо вызова malloc; realloc будет работать так же, как malloc в первый раз.

0 голосов
/ 31 января 2010

Да, вам нужно вызвать free () один раз, чтобы освободить блок памяти. Вам не нужно вызывать free для последующих выполняемых вами reallocs (), даже если они возвращают другой адрес / указатель. Менеджер памяти знает, что старый блок больше не нужен, и освободит его ().

0 голосов
/ 31 января 2010

Из справочных страниц:

Если размер равен 0, то malloc () возвращает либо NULL, либо уникальное значение указателя, которое впоследствии может быть успешно передано free ().

Итак, я считаю, что ответ "да":).

...