как правильно освободить таблицу символов ** в C - PullRequest
6 голосов
/ 20 марта 2010

Мне нужен ваш совет по этому коду: опции полей таблицы [0], опции [1] и т. д. Спасибо за ваши ответы

int main()
{
  ....
  char **options;
  options = generate_fields(user_input);
  for(i = 0; i < sizeof(options) / sizeof(options[0]); i++)  {
    free(options[i]);
    options[i] = NULL;
  }

  free(options);
}

char ** generate_fields(char *) 
{
   char ** options = malloc(256*sizeof(char *));
   ...
   return options;

}

Ответы [ 3 ]

16 голосов
/ 20 марта 2010

Проблема заключается в следующем:

for(i = 0; i < sizeof(options) / sizeof(options[0]); i++)

options - это тип указателя, а не тип массива, поэтому sizeof(options) всегда будет одинаковым (обычно 4 байта на 32-разрядной машине или 8 байтов на 64-разрядной машине), поэтому sizeof(options)/sizeof(options[0]) почти всегда будет 1.

Ключ к тому, чтобы всегда free память была такой же, как вы malloc 'редактировали ее. Итак, если вы malloc 2-мерный массив, а затем malloc ряд 1-мерных массивов, вам нужно сделать обратное при освобождении:

char ** generate_fields(char *) 
{
   char ** options = malloc(256*sizeof(char *));
   for(int i = 0; i < 256; i++)
       options[i] = malloc(some_size);
   return options;
}

void free_fields(char ** options)
{
    for(int i = 0; i < 256; i++)
        free(options[i]);
    free(options);
}

Обратите внимание, что если размер (в данном случае 256) не является константой, вам нужно следить за ним самостоятельно, так как в противном случае вы не сможете узнать, сколько раз выполнить цикл при освобождении.

7 голосов
/ 20 марта 2010

У вас должно быть столько же free с, сколько у вас malloc с.

В своем коде вы выделяете массив указателей, но не выделяете память для отдельных элементов массива, на которые можно указать Но ваш код освобождения написан так, как будто вы это сделали.

3 голосов
/ 20 марта 2010

Я собираюсь добавить ответ Адама здесь, потому что это, вероятно, не вписывается в комментарий. Адам совершенно прав. Я подозреваю, что ваша функция generate_fields, однако, возможно, на самом деле получает информацию от пользователя, я не уверен. В любом случае, есть два подхода к этому:

char ** generate_fields(char *, int num_fields, int size_of_field) 
{
   char ** options = malloc(num_fields*sizeof(char *));
   for(int i = 0; i < num_fields; i++)
       options[i] = malloc(size_of_field);
   return options;
}

и соответствующую бесплатную функцию, которую я опущу для краткости. Вы можете видеть, что происходит - мы передаем количество полей и размер поля. Измените это вокруг, как вам нужно. Другой вариант заключается в том, чтобы сгенерировать поля, передаваемые обратно подпрограмме, которая вызывается из размера массива. Я бы сделал что-то вроде этого:

int generate_fields(char** options) 
{
   int num_fields = 0;
   // somewhere here we get num_fields
   options = malloc(num_fields*sizeof(char *));
   for(int i = 0; i < num_fields; i++)
       options[i] = malloc(size_of_field);
   return num_fields;
}

И вы звоните с основного так:

int main()
{
    int sizeofarray = 0;
    char** fields;
    sizeofarray = generate_fields(fields);

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

char** generate_fields(int* size) 

В качестве прототипа функции (верните параметры на этот раз и сделайте size= где-нибудь в коде и вызовите из main следующим образом:

int sizeofarray = 0;
char** options;
options = generate_fields(&sizeofarray);

Надеюсь, что это даст вам еще больше идей, Адам, не стесняйтесь редактировать все / все это в своем ответе соответствующим образом, в любом случае, это будет ваш ответ.

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