2013-10-17 63 views
3

我对c很新,所以如果我的步骤有误,请告诉我。比方说,我有类似以下内容:我应该如何malloc/realloc包含一个数组的结构?

struct graphNode{ 
    int val; 
    graphNode* parent; 
    int succSize; 
    int succMaxSize; 
    graphNode* succ[1]; 
}; 

我将创建一个新的节点:

graphNode *n; 
n = malloc(sizeof(struct graphNode)); 
assert(n); 
n->val = 1; 
n->parent = NULL; 
n->succSize = 0; 
n->succMaxSize = 1; 

然后,如果我想给继任添加到节点

if (n->succSize == n->succMaxSize){ 
    n->succ = realloc(n->succ, sizeof(graphNode*) * n->succMaxSize * 2); 
    n->succMaxSize *= 2; 
} 
n->succ[succSize] = n2; //n2 is of type graphNode* 
succSize++; 

这是正确的吗?我是否需要重新分配结构体,或者是否足够重新分配数组?我需要对初始数组使用malloc吗?初始数组的大小应该包含在我的malloc调用中吗?

+0

你的初始结构不需要realloc。你想实现什么?我觉得realoc并不高雅。 –

+0

为什么不使用C++并将这个问题引入生活中? –

+1

@EdHeal为什么不使用Python元组或JavaScript数组来完全避免内存管理? – 2013-10-17 22:08:36

回答

7

的通常方法在C中定义了“有弹性的”阵列构件是要么指定大小的0或没有大小在所有,例如:

struct foo { 
    int stuff; 
    bar theBars[]; // or theBars[0] 
}; 

在这个定义下,sizeof(struct foo)将包括所有元素除了最后的数组之外,您可以通过说malloc(sizeof(struct foo) + numberOfBars * sizeof(bar))来分配正确的大小。

如果您需要重新分配它以更改bar元素的数量,那么您将使用相同的公式(但使用新的numberOfBars)。

要清楚,你不能只是realloc结构的一部分。你必须realloc整个事情。

+0

正在'bar theBars [];'有同样的'bar * theBars;'?比另一个更可取吗? – Lunyx

+0

+1没有人注意到“有弹性”的方面。 –

+0

@丹尼尔,不,它是不同的。有关更多解释,请参阅下面的答案。 –

0

如果你只想要一个单一的数组,只需使用一个指针succ,并且只使用malloc/realloc等来为数组分配内存。

graphNode* succ; 

你在做什么几乎肯定会中断。

0

我也是C新手,但有一些东西我可以直接看到蝙蝠。首先,你不能重新分配数组。在c89中,它们是编译时固定大小的。在C99和C11中,它们可以动态分配,但不能重新分配(据我所知)。所以对此,您需要分配一个指针和malloc(节点* sizeof(节点))

graphnode *succ; 

graphNode* succ[1]; 

这会创建一个大小为1的数组,而不是一个最大索引为1的数组。因此,它是相同的(几乎)功能作为

graphNode* succ; 

只是一旦你做它,你不能改变它的大小。

我想你想要的是做一个树,动态重新分配数量的分支。在这种情况下,只需要重新分配graphNode *指针的大小,然后像索引数组那样通过索引访问每个元素。

+0

这是有道理的。只是要清楚,你说我应该重新分配n-> succ指针,但是我不需要重新分配结构指针n?这是如何运作的?另一个人在回答下面说,我不能重新分配一个结构的一部分,我必须重新分配整个事情。 – Lunyx

+0

graphNode * succ [1];与graphNode * succ不同“(几乎)”;第一个是一个指针的数组,第二个是指针。非常不一样。看到接受的答案,看看如何使用它。 –

+0

@丹尼尔 - 这种方法和其他实际上是两种不同的方法。在这种情况下,后继数组不是结构的一部分,只有指向数组的指针,因此只有指针指向的内存需要重新分配。直到阅读“struct hack”的其他答案之前,我一直没有意识到 - 创建一个空数组作为结构的最后一个元素,并将该内存作为结构本身的一部分进行分配,以便数组内存与其余部分连续结构。在这种情况下,你将不得不重新分配整个结构,因为它们是同一块内存。 – nitetrain8

1

realloc(ptr,size)需要2个参数,而不是1,在realloc(sizeof(graphNode*) * n->succMaxSize * 2)

// Something like ... 
graphNode *n; 
n->succSize = 0; 
n->succMaxSize = 0; // set to 0 
n->succ = NULL; // Initialize to NULL 

// Then, if OP wants to add a successor to the node 
if (n->succSize <= n->succMaxSize){ 
    n->succ = realloc(n->succ, sizeof(graphNode*) * n->succMaxSize * 2); 
    n->succMaxSize *= 2; 
} 
n->succ[succSize++] = n2; 

用作与所有的内存分配,检查NULL回报。在realloc()中,应保存原始值,因此如果realloc()失败,原始指针不会丢失。

+0

感谢您提醒我。一般来说,将'n-succ [succSize ++]'分成一个赋值,然后是一个增量,以使代码更加明显,会更好吗? – Lunyx

+1

当succ被定义为graphNode *时,这是一个很好的答案。 –

+0

@Daniel关于单独或包含的'succSize ++':那是[圣战](http://meta.programmers.stackexchange.com/questions/2638/what-is-a-point-of-the-holy-war-标签)地面。 6.001或另一半。 – chux

1

通常,当您看到struct定义中最后一个字段是大小为0或1的数组时,这意味着作者将在malloc绑定时使用malloc做一些细微的事情。

例如

struct foo { 
    int x; 
    : 
    : 
    type a[0]; 
}; 

随着一个malloc像

struct foo *p = malloc(sizeof(*p) + (n * sizeof(type)); 

这样做什么是它分配一个连续的内存块的结构和尾随阵列。在这种情况下,数组大小为n。因此,在这种情况下对阵列的引用是:

p->a[i] // where i >= 0 and i < n 

这样做的一个原因是为了节省内存。

我相信在StackOver上有更好的解释。这是一个非常普通的C语言。

当数组是动态时,通常不使用它。相反,它在malloc()时已知数组大小时使用。当然,您可以动态使用,但您必须重新分配整个内存块,而不仅仅是自己的结构或数组。要增加到2n的大小,你会说

p = realloc(p, sizeof(*p) + (2 * n * sizeof(type))); 

现在你的数组是两倍大,因为它仍然是一块内存。

+0

是否需要将数组作为结构定义的最后一个字段? >当数组是动态时,通常不会使用它。这里指的是什么?你什么时候使用'type a [0]'或'type'a'来输入'a'? – Lunyx

+0

我试图指出当一个人在结构的末尾有一个大小为0或1的数组时,常见的C语言成语。如果你是struct定义的作者,并且不明白我在说什么,你可以忽略我的答案。如果有人写了它,我的答案可能是你感兴趣的。 “it”的意思是“成语”。如果可变的后继数量和你想节省一些内存的人会使用这种技术。 –

相关问题