Нужно ли освобождать структуры внутри структур? - PullRequest
0 голосов
/ 01 мая 2018

У меня есть следующий кусок кода. Я хочу правильно освободить всю мою память. Как видите, у меня есть b_struct внутри a_struct. Интересно, нужно ли мне вручную освобождать b_struct внутри a_struct, и если да, то как правильно это сделать?

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

struct b_struct {
    int c;
};

struct a_struct {
    struct b_struct b;
};

int main(int argc, char **argv)
{
  struct a_struct *a;
  a = calloc(1, sizeof(*a));
  a->b.c = 5;
  printf("Value: %d", a->b.c);
  free(a);
}

Ответы [ 3 ]

0 голосов
/ 01 мая 2018

Нет. Вам не только не нужно , но вам не разрешено . Память, используемая в b, является частью памяти, используемой в a; вам нужно освободить последний как единое целое, и это включает в себя всю память для b.

Как правило, ваша программа должна вызывать free ровно один раз для каждого вызова malloc или calloc. Это не означает, что количество строк кода, вызывающих free, должно совпадать с количеством строк, вызывающих функции выделения; это означает, что каждый раз, когда вы запускаете программу, каждый вызов free должен быть связан с ровно одним вызовом функции распределения, и наоборот, с ограниченными исключениями:

  • Если распределение не выполнено (и возвращается NULL), вам не нужно звонить free на NULL.
  • Вы можете звонить free на NULL столько раз, сколько захотите, хотя обычно вы этого не хотите.
  • Вы можете вызывать библиотечные функции, которые затем выделяют или освобождают память внутри. Это на самом деле не исключение; каждая из этих функций по-прежнему должна соответствовать соответствующему свободному или выделенному (соответственно), но если вы просто посмотрите на malloc, calloc и free, вы можете что-то пропустить.
  • Когда ваша самая ранняя возможность освободить кусок памяти - это прямо перед выходом из программы, вам не нужно об этом беспокоиться, поскольку операционная система в любом случае восстанавливает всю память в этой точке. В частности, этот момент имеет свои предостережения, но в лучшем случае они касаются этой проблемы.

Если вам не удалось free памяти, которая была выделена, у вас утечка памяти. Ваша программа будет использовать все больше и больше памяти, пока операционная система больше не сможет ее отдавать, и в этот момент она, вероятно, вылетит.

Если у вас free память, которая не была выделена одной из стандартных функций выделения, или free дважды одна и та же память, это становится еще хуже: это сразу неопределенное поведение (UB) и может делать что угодно *. Это тип ошибки, которую вы могли бы ввести, пытаясь освободить b; рассматриваемая память не была фактическим указателем, возвращаемым calloc, и даже если бы он был, он уже был бы освобожден как часть a.


* Люди часто говорят, что UB может многое сделать, но на практике вы часто можете предсказать, что произойдет в реальной системе; это не заставит ваш компьютер взорваться, если вы не подключите USB-бомбу к данному компьютеру. Однако я бы классифицировал недействительные освобождения как один из менее прирученных типов UB: ошибки, которые он вводит, могут на практике появляться позже, чем фактическая ошибка, вызывать, казалось бы, несвязанные проблемы и быть нестабильными между несколькими запусками программы (то есть Выглядит хорошо, когда вы тестируете, но терпите неудачу, когда вы пытаетесь использовать программу, и вам трудно отлаживать) Со многими другими формами UB это допускается, но на практике это не так вероятно.

0 голосов
/ 01 мая 2018

В этом случае, нет.

Вам потребуется только вручную освободить внутреннюю структуру, если она была выделена отдельно от внешней структуры. Пример:

struct a_struct 
{
  struct b_struct *b;
};

int main( void )
{
  struct a_struct *a = malloc( sizeof *a );
  if ( a ) // *Always* check the result of malloc or calloc
  {
    a->b = malloc( sizeof *a->b );
    if ( a->b )
    {
      // do stuff with a->b->c
      free( a->b );  // free in reverse order that you allocated
    }
    free( a );
  }
  return 0;
}

Вы должны только free значения указателя, возвращаемые из malloc, calloc или realloc.

0 голосов
/ 01 мая 2018

Интересно, нужно ли мне вручную освобождать b_struct в a_struct

номер

Из справочной страницы malloc(3):

Функция free() освобождает пространство памяти, на которое указывает ptr, которое должно было быть возвращено предыдущим вызовом malloc(), calloc() или realloc().

Когда вы выделили sizeof(struct a_struct) байт, это включает в себя всех членов этой структуры, включая член struct b_struct. Этот элемент структуры ничем не отличается от int или char[] члена; это всего лишь один непрерывный блок памяти для распределителя.

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