Как правильно выделить память для структур в C? - PullRequest
0 голосов
/ 31 марта 2019

Я не знаю, как распределить память для структуры в моей программе на C без нарушения сегментации.

typedef struct Player{
      char *name,  *surname;
      int xp;
} Player;

typedef struct Team{
      char *name;
      Player *player;
} Team;

typedef struct List
{
    Team *team;
    struct List *next;
} List_Node;

Мне нужно составить список команд с множеством игроков, но для того, чтобы моя программа не была Segfault, мне нужно распределить все элементы по каждой структуре. Тогда я должен освободить каждого члена каждой структуры. Это достаточно большой проект, и я получаю ошибки повреждения кучи, и я не знаю, правильно ли я инициализирую свои структуры.

С указателем, инициализированным в main.

List_Node *list_node = (List_Node*)malloc(sizeof(List_node));

И функция

void create_list_Node(List_Node *temp)
{
    temp->team = malloc....
    temp->team->name = malloc....
    temp->team->player = malloc....
    temp->team->player->name = malloc....
    temp->team->player->surname = malloc....
    temp->next = NULL;
}

Вызывается с узлом в качестве параметра.

Ответы [ 2 ]

1 голос
/ 31 марта 2019

Чтобы уменьшить «много частей памяти, разбросанных повсюду» (и хлопот отслеживания того, где все маленькие части выделены / освобождены), вы можете выделить один кусок памяти для нескольких вещей (например, структура плюс строка). Например:

typedef struct Player{
      char *name,  *surname;
      int xp;
} Player;

typedef struct Team{
      struct Team *next;
      char *name;
      Player *player;
} Team;

Player *createPlayer(char *name, char *surname, int xp) {
    Player *newPlayer;
    int len1, len2;

    len1 = strlen(name);
    len2 = strlen(surname);
    newPlayer = malloc(sizeof(Player) + len1+1 + len2+1);
    if(newPlayer != NULL) {
        newPlayer->next = NULL;
        newPlayer->name = (char *)newPlayer + sizeof(Player);
        memcpy(newPlayer->name, name, len1+1);
        newPlayer->surname = newPlayer->name + len1+1;
        memcpy(newPlayer->surname, surname, len2+1);
        plyer->xp = xp;
    }
    return newPlayer;
}

Team *createTeam(Player *player, char *name) {
    Team *newTeam;
    int len1;

    len1 = strlen(name);
    newTeam = malloc(sizeof(Team) + len1+1);
    if(newTeam != NULL) {
        newTeam->next = NULL;
        newTeam->name = (char *)newTeam + sizeof(Team);
        memcpy(newTeam->name, name, len1+1);
        newTeam->player = player;
    }
    return newTeam;
}

Это также означает, что легко что-либо освободить - например, Вы можете free(player) не возиться с отдельными полями.

Примечание: я избавился от List_Node и поместил поле next в структуру Team. Это помогает улучшить производительность для итерации (а также уменьшает чрезмерное количество malloc / free). Чтобы понять это, представьте, что вы перечисляете все названия команд и делаете что-то вроде этого:

    while(node != NULL) {
        printf("name: %s\n", node->team->name)
        node = node->next;
    }

В этом случае; Процессор останавливается, ожидая получения node из памяти, затем останавливается, ожидая, пока node->team будет выбран из памяти. Теперь представьте это:

    while(team != NULL) {
        printf("name: %s\n", team->name)
        team = team->next;
    }

В этом случае; Процессор останавливается один раз, а не два, поэтому итерация по списку происходит быстрее.

1 голос
/ 31 марта 2019

Если мы используем эту функцию для создания пустого узла:

void create_list_Node(List_Node *temp)
{
    temp->team = calloc(1, sizeof(Team));
    temp->team->player = calloc(1, sizeof(Player));
    temp->next = NULL;
}

То, как вы распределяете namn: s и фамилию, зависит от того, откуда эти строки берутся.Если вы получили выделенный указатель, который не освободит никакой другой код, вы можете просто «принять» указатель:

char *mystring;
... code that allocates
temp->team->name = mystring;

Если у вас есть локальный строковый массив, просто скопируйте его:

char local[100];
... code that fill it, maybe gets()
temp->team->name = strdup(local);

Не забудьте освободить строки и структуры!

...