如何正确安全地释放()所有内存使用 C 中的嵌套结构?

How to correctly and safely free() all memory used a nested struct in C?

我嵌套了四层不同的结构。代码如下:

typedef struct System system;  
typedef struct College college;
typedef struct Student student;
typedef struct Family family;

#define MAX_COLLEGES 10
#define MAX_NAME_LEN 32
#define MAX_STUDENTS 10

struct System {
    college *Colleges[MAX_COLLEGES];
};

struct College {
    char name[MAX_NAME_LEN];
    student *Students[MAX_STUDENTS];
};

struct Student {
    char name[MAX_NAME_LEN];
    int id;
    family *fam; //was typo familiy
};

struct Family {
    char fatherName[MAX_NAME_LEN];
    char motherName[MAX_NAME_LEN];
};

并且我给它们都分配了内存(我不确定是否分配正确),如下:

system *collegeSys = malloc(sizeof(system));
college *colleges = malloc(sizeof(college));
student *students = malloc(sizeof(student));
family *fam = malloc(sizeof(family));

// then the following is initialization
...
...
...

现在,我需要删除 collegeSys 结构以及与之关联的所有内容。所以,我不知道我是否可以只释放第一个 collegeSys 结构而不释放任何其他结构,如下所示:

free(collegeSys);

或者为了 "delete anything associated with it",我必须自下而上释放所有内容,如下所示:

free(fam);
free(students);
free(colleges);
free(collegeSys);

或者为此,我什至必须释放每个结构中包含的所有内容并自下而上释放它们,如下所示:

free (fam -> fatherName);
free (fam -> motherName);
free (fam);
free (students -> name);
free (students -> id);
free (students -> fam);
free (students)
.
. till
.
free (collegeSys -> colleges);
free (collegeSys);

哪一种是释放内存的正确且安全的方法?或者 none 是?

我不太明白指针数组的意义,它可以用指针来完成。

定义:

struct System {
    college *Colleges;
};

struct College {
    char name[MAX_NAME_LEN];
    student *Students;
};

struct Student {
    char name[MAX_NAME_LEN];
    int id;
    familiy *fam;
};

struct Family {
    char fatherName[MAX_NAME_LEN];
    char motherName[MAX_NAME_LEN];
};

分配和初始化:

system *collegeSys = malloc(sizeof(*collegeSys));
collegeSys->colleges = malloc(MAX_COLLEGES * sizeof(*(collegeSys->colleges)));
collegeSys->colleges->students = malloc(MAX_STUDENTS * sizeof(*(collegeSys->colleges->students)));
collegeSys->colleges->students->fam = malloc(sizeof(*(collegeSys->colleges->students->fam)));

释放:

free(collegeSys->colleges->students->fam);
free(collegeSys->colleges->students);
free(collegeSys->colleges);
free(collegeSys);

更新:

Like I want to have struct student A, B, C, D under a struct college

 collegeSys->colleges->students[0] = A;
 collegeSys->colleges->students[1] = B;
 collegeSys->colleges->students[2] = C;
 collegeSys->colleges->students[3] = D;

应该做。

如果您有 student 数组,您可以使用 memcpy 或复制到 loop

struct student stud[MAX_STUDENTS] = {...};

memcpy(collegeSys->colleges->students[2], stud, MAX_STUDENTS);

for (int i = 0; i< MAX_STUDENTS; i++)
     collegeSys->colleges->students[i] = stud[i];

注:

您可以将数组分配给 collegeSys->colleges->students,在这种情况下您不需要动态内存分配或释放。

 // collegeSys->colleges->students = malloc(MAX_STUDENTS * sizeof(*(collegeSys->colleges->students)));  //Leaks memory

 collegeSys->colleges->students = stud;

//free(collegeSys->colleges->students); //wrong

分配一个结构然后将其中的所有指针设置为 NULL。 例如,要分配你的 College 结构,你需要将所有学生设置为 NULL:

struct College* CollegeAlloc( char name[MAX_NAME_LEN] ) {
    struct College* college = malloc( sizeof(struct College) );
    if ( college ) {
        for ( int i = 0; i < MAX_STUDENTS; ++i )
            college->Students[i] = NULL;
        memcpy( college->name, name, MAX_NAME_LEN );
    }
    return college;
}

或者,您可以在每个数组的结构中添加一个计数字段,以计算实际使用的数组元素的数量。

如果在不使用时将数组元素设置为NULL,则可以先从下向上释放。

void FamilyFree( struct Family *fam ) {
    free( fam );
}
void StudentFree( struct Student *student ) {
    if ( student ) {
        FamilyFree( student->fam );
        free( student );
    }
}
void CollegeFree( struct College *college ) {
    if ( college ) {
        for ( int i = 0; i < MAX_STUDENTS; ++i )
            StudentFree( college->Students[i] );
        free( college );
    }
}
void SystemFree( struct System *sys ) {
    if ( sys ) {
        for ( int i = 0; i < MAX_COLLEGES; ++i )
            CollegeFree( sys->Colleges[i] );
        free( sys );
    }
}

请注意,这假设 没有共享 指针,例如同一个学生在不止一所大学(当实施只为每个学生分配一个结构时),或者当有两个兄弟姐妹共享相同的家庭结构时。 (家庭结构不能很好地模拟家庭,例如单身 parents、离婚、再婚、同性恋 parents、法定监护人)。 当结构可以共享时,您可以在结构中放置一个引用计数,只有当它减少到零时才释放。