C语言 - 为包含另一个结构体数组的结构体正确分配内存

6
我希望为一个包含另一种名为table的结构体数组的结构体分配内存。我发现,在将指针分配给最后的函数时,linkedObjects数组中的变量会被破坏,因此我认为我的动态内存处理方式是错误的。
下面是我的处理方式:
typedef struct Object {
    void *key;
    struct Object *top;
    struct Object *next;
} Object;

typedef struct Table{
    Object *linkedObjects;
    size_t size, originalSize;
    HashFcn hfun;
    PrintFcn pfun;
    ComparisonFcn fcomp;
} Table;

TableP CreateTable(size_t tableSize, HashFcn hfun, PrintFcn pfun, ComparisonFcn fcomp)
{
    int i;
    struct Table *table = malloc(sizeof(table));
    if (table==NULL)
    {
        ReportError(MEM_OUT);
        return NULL;
    }
    table->linkedObjects = NULL;
    table->linkedObjects  = malloc(tableSize * sizeof(Object));

    for(i=0;i<tableSize;i++)
    {

        table->linkedObjects[i].next = malloc( MAX_IN_LIST*sizeof(Object) );
        table->linkedObjects[i].top = malloc( MAX_IN_LIST*sizeof(Object) );
        table->linkedObjects[i].key = NULL;
        table->linkedObjects[i].top->key = NULL;
        table->linkedObjects[i].next->key = NULL;

        if (table->linkedObjects[i].next == NULL)
        {
            ReportError(MEM_OUT);
            return NULL;
        }
    }

    table->size = tableSize;
    table->originalSize = tableSize;
    table->hfun = hfun;
    table->pfun = pfun;
    table->fcomp = fcomp;
    return table;
}

编辑:我编辑了函数代码以反映答案:

TableP CreateTable(size_t tableSize, HashFcn hfun, PrintFcn pfun, ComparisonFcn fcomp)
{
    int i;
    struct Table *table = malloc(sizeof(table));
    if (table==NULL)
    {
        ReportError(MEM_OUT);
        return NULL;
    }
    table->linkedObjects = NULL;
    table->linkedObjects  = malloc(tableSize * sizeof(Object));

    if (table->linkedObjects == NULL)
    {
        ReportError(MEM_OUT);
        return NULL;
    }

    for(i=0;i<tableSize;i++)
    {
        table->linkedObjects[i].next = NULL;
        table->linkedObjects[i].top = NULL;
        table->linkedObjects[i].key = NULL;
    }

    table->size = tableSize;
    table->originalSize = tableSize;
    table->hfun = hfun;
    table->pfun = pfun;
    table->fcomp = fcomp;
    //printf("%p\n", table->hfun);
    return table;
}

但是当我到达任务末尾时,table->linkedObjects[0].key 的值为 null,而且数值为 0x0 的时候,它会被覆盖成 0x8048cc0。这发生在执行以下代码的时候:

table->originalSize = tableSize;

另外说明:已确认这种情况会随机出现在最后几次呼叫(不仅是在上一行):

table->size = tableSize;
table->originalSize = tableSize;
table->hfun = hfun;
table->pfun = pfun;
table->fcomp = fcomp;

你的意思是要给next和top分配大量的内存吗?据我理解,除非next和top本身就是数组,否则这些对象只需要存储一个结构体即可。 - Syntactic Fructose
目前,next和top是独立的数组,分别持有自己的对象集合,这是故意的吗?我试图理解你在这里要做什么。我猜测,next和top应该是数组“key”的一部分。 - Syntactic Fructose
next和top是指向结构体的指针。 - Tom
topnext 是神秘的。它们有什么作用?为什么要为每个变量分配一个数组,并且只初始化第一个对象的一个字段?除此之外,我没有看到这段代码有什么明显的问题。错误很可能在其他地方。但是,如果 MAX_IN_LIST 为 0 的话,那就是错的。 - n. m.
@n.m. 请审核我的编辑。我正在尝试使用一个结构体来构建链表。nexttop 是指向其他类型为 object 的对象的指针。 - Tom
显示剩余2条评论
3个回答

5

struct Table *table = malloc(sizeof(Table));

应该这样写:

struct Table *table = malloc(sizeof(Table));

有时候我很喜欢 C 语言。

`


确认。我花了2个小时在这上面,如果没有别人的帮助,我永远也不会发现这个问题,谢谢! - Tom
3
首先,无论是 struct Table *table = malloc(sizeof(struct Table)) 还是 Table *table = malloc(sizeof(Table)),你需要做出决定并坚持下去。其次,我建议使用 struct Table *table = malloc(sizeof *table)。不必使用类型名称。 - AnT stands with Russia
有很多可能性,没错。我会说 typedef struct table_t Table。我不会使用 malloc(sizeof *var),而是使用 ((T*)malloc(sizeof(T))),并将其包装在宏中,就像 GNU libiberty 中一样。宏是邪恶的,但有些事情更邪恶。但无论如何,你喜欢什么就用什么吧。 - n. m.
同意@AndreyT的观点。由于OP代码中的Tabletypedef,能够使用struct Table *table = malloc(sizeof(Table))很容易引起混淆。其次,我认为最正确的答案是Table *table = malloc(sizeof *table);,正如@AndreyT在下面的回答中所述。如果将table更改为新类型,则分配仍然是正确的大小。我认为第一个赋值struct Table *table = malloc(sizeof(table));正在为指向Table的指针分配大小,但我很高兴在这里得到正确的意见。 - KyleWpppd
@KyleWpppd:是的,它会为指针大小分配空间。这实际上就是这个答案要解决的错误。 - AnT stands with Russia

1

通常情况下,要摆脱使用sizeof下的类型名称的习惯。这就是你的内存分配应该是什么样子的。

Table *table = malloc(sizeof *table);
...
table->linkedObjects = malloc(tableSize * sizeof *table->linkedObjects);

那也会修复第一个分配中的“拼写错误”。

0
table->linkedObjects[i].next = malloc( MAX_IN_LIST*sizeof(Object) );
table->linkedObjects[i].top = malloc( MAX_IN_LIST*sizeof(Object) );

这似乎没有意义。当我看到与集合相关的 nexttop 时,我期望有一个指向单个 Object 的指针(指向集合中的下一项或第一项)。

你是不是要做以下事情:

for(i=0;i < (tableSize-1);i++)
{
    table->linkedObjects[i].top = table->linkedObjects[0];
    table->linkedObjects[i].next = table->linkedObjects[i+1];
    table->linkedObjects[i].key = NULL;
}

这将为每个Object分配内存,并在之后设置指针。


我已经在进行这个分配了,但它会为每个对象分配内存吗? - Tom
哦,我没看到。你不需要为topnext分配内存,因为你已经在数组本身中分配了它们。你正在使用指针指向数组中的某些元素。如果你要分配额外的内存并为每个指针使用新的Object,它将不会指向你期望的位置。你希望它指向数组中的那些元素,而不是新分配的元素。 - Femaref
我希望所有东西都是空的,但以后应该有足够的内存。请审核我的编辑。 - Tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接