【问题标题】:How to free some dynamically allocated nested array of structure in C?如何在 C 中释放一些动态分配的嵌套结构数组?
【发布时间】:2016-03-31 16:42:21
【问题描述】:

这里有一些嵌套结构:

struct bat
{
    int match,run,fifty,best;
    double average,strike_rate;
};
struct ball
{
    char *best;
    int match,wicket,fiveW;
    double economy,average;
};
struct Player
{
    char *name;
    char *country;
    char *role;
    struct bat *batting;
    struct ball *bowling;

};
struct Team
{
    char *name;
    char *owner;
    char *rank;
    char *worth;
    char *match;
    char *won;
    char *lost;
    struct Player *plist;
} *team;

下面我使用*team指针动态分配了7个struct Team类型的数组,每个指针包含16个使用*pliststruct Player类型数组。 struct Player 也有两个嵌套结构。

int i,j;
    team=(struct Team *) calloc(7,sizeof(struct Team));
    for(i=0; i<7; i++)
    {
        (team+i)->name=( char*) malloc(1*100);
        (team+i)->owner=( char*) malloc(1*100);
        (team+i)->rank=( char*) malloc(1*100);
        (team+i)->worth=( char*) malloc(1*100);
        (team+i)->match=( char*) malloc(1*100);
        (team+i)->won=( char*) malloc(1*100);
        (team+i)->lost=( char*) malloc(1*100);
        (team+i)->plist=(struct Player *) calloc(16,sizeof(struct Player));
        for(j=0; j<16; j++)
        {
            (((team+i)->plist)+j)->name=( char*) malloc(1*100);
            (((team+i)->plist)+j)->country=( char*) malloc(1*100);
            (((team+i)->plist)+j)->role=( char*) malloc(1*100);
            (((team+i)->plist)+j)->batting=(struct bat *) malloc(sizeof(struct bat));
            (((team+i)->plist)+j)->bowling=(struct ball *) malloc(sizeof(struct ball));
            ((((team+i)->plist)+j)->bowling)->best=(char*) malloc(1*100);
        }
    }

现在我已经为所有这些赋值并完成了一些任务。现在是释放所有dynamically allocated arrays 的时候了。释放上面分配的所有内容的正确方法是什么?

我尝试像下面这样释放,但程序获取 run-time error 并崩溃:

for(i=0; i<7; i++)
    {
        free((team+i)->name);
        free((team+i)->owner);
        free((team+i)->rank);
        free((team+i)->worth);
        free((team+i)->match);
        free((team+i)->won);
        free((team+i)->lost);
        for(j=0; j<16; j++)
        {
            free((((team+i)->plist)+j)->name);
            free((((team+i)->plist)+j)->country);
            free((((team+i)->plist)+j)->role);
            free((((team+i)->plist)+j)->batting);
            free(((((team+i)->plist)+j)->bowling)->best);
            free((((team+i)->plist)+j)->bowling);
        }
        free(((team+i)->plist));
    }
    free(team);

如何正确释放所有dynamically allocated memory

【问题讨论】:

  • 释放你malloc()ated的每个指针,按照分配的相反顺序。
  • OT:不要投射malloc,而sizeof(char) 始终是1
  • 是的,只是颠倒阅读,(并考虑转向 C++)。
  • 考虑到大多数内部成员malloc 是固定长度硬编码到源代码中的,我很难理解您为什么还要费心去做任何,而是首先拥有像char name[100] 这样的大小成员。动态分配:仅仅因为你可以并不意味着你应该
  • 另外,那些括号很难看。 (team+q)-&gt;plist)+b)-&gt;bowling)-&gt;best 应该写成team[q].plist[b].bowling-&gt;best

标签: c pointers struct dynamic-allocation


【解决方案1】:

我先贴了一些笔记,其中一些来自 cmets:

  • 不要转换malloc/calloc的结果。当您忘记包含 stdlib.h 时,这可能会隐藏错误/警告。
  • sizeof(char)1始终
  • 稍后初始化所有分配的内存时使用calloc 是无稽之谈:只需使用malloc
  • ((((team+q)-&gt;plist)+b)-&gt;bowling)-&gt;best 读起来难看。更好地使用数组表示法:

    team[q]->plist[b]->bowling->best
    

    虽然它在可读性方面并没有多大意义,IMO。

  • qb有意义的变量名。

  • 如果您的字符串是固定长度的,那么您为什么还要使用动态分配呢?只需使用固定长度的数组成员,例如char name[100]plist 也是如此:如果您知道它将是 16 个玩家,那么只需将其设为一个恒定大小的数组即可。

然后,您可能应该对每个结构都具有构造函数和破坏函数,模仿面向对象语言的构造函数和析构函数(因为您正在以几乎面向对象的风格进行编程)。所以考虑写函数

void construct_team(struct Team * team) {
  // allocating any members, calling construct_* of structure members
}
void destruct_team(struct Team * team) {
  // free any members, calling destruct_* of structure members, in
  // the exact reversed order as in the construct function!
}

这样,您会注意到您没有“匹配分配”

free((team+q)); // Never allocated team+q (the individual array elements), just the whole array team!

您只需在循环结束时free(team) 即可使您的代码正常工作。但是请考虑以上言论。

【讨论】:

  • 这样一个冗长而有用的答案 - 但未被接受为答案,只有 2 票(其中一张来自我)。 Stackoverflow 有时很奇怪。
【解决方案2】:

这些行是错误的:

        free(((team+q)->plist)+q);
        free((team+q));
    }

他们应该是:

        free((team+q)->plist);
    }
free(team);

注意:我认为@Tavij 的错误是认为calloced 数组的每个元素都必须单独为freed,这当然是不正确的。

【讨论】:

  • 注意这段代码是在循环中执行的,team是一个数组,不能省略+q
  • @AlterMann 我的初始版本缩进不正确。我修复了它,所以现在可能更有意义。最后的free(team);for 循环之后。
猜你喜欢
  • 2022-10-14
  • 2010-12-05
  • 2015-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多