我正在尝试创建一个函数,该函数将数组作为参数,向其添加值(必要时增加其大小)并返回项的计数。 到目前为止,我有:
int main(int argc, char** argv) {
int mSize = 10;
ent a[mSize];
int n;
n = addValues(a,mSize);
for(i=0;i<n;i++) {
//Print values from a
}
}
int addValues(ent *a, int mSize) {
int size = mSize;
i = 0;
while(....) { //Loop to add items to array
if(i>=size-1) {
size = size*2;
a = realloc(a, (size)*sizeof(ent));
}
//Add to array
i++;
}
return i;
}
如果mSize足够大以容纳数组的所有潜在元素,则此方法有效,但如果需要调整大小,则会出现分段错误。
我也尝试过:
int main(int argc, char** argv) {
...
ent *a;
...
}
int addValues(ent *a, int mSize) {
...
a = calloc(1, sizeof(ent);
//usual loop
...
}
无济于事。
我认为这是因为当我调用realloc时,'a'的副本指向别处 - 如何修改它以便'a'始终指向同一位置?
我是否正确地解决了这个问题?有没有更好的方法来处理C中的动态结构?我应该实施一个链表来处理这些吗?
答案 0 :(得分:10)
这里的主要问题是你正在尝试将realloc与堆栈分配的数组一起使用。你有:
ent a[mSize];
这是堆栈上的自动分配。如果你想在以后使用realloc(),你可以使用malloc()在堆上创建数组,如下所示:
ent *a = (ent*)malloc(mSize * sizeof(ent));
因此malloc库(以及realloc()等)知道你的数组。从外观上看,您可能会将C99 variable-length arrays与真dynamic arrays混淆,因此在尝试解决此问题之前,请务必了解其中的差异。
但是,实际上,如果您在C中编写动态数组,则应该尝试使用OOP-ish设计来封装有关数组的信息并将其隐藏在用户之外。您希望将有关数组的信息(例如指针和大小)合并到结构和操作(例如,分配,添加元素,删除元素,释放等)到与结构一起使用的特殊函数中。所以你可能有:
typedef struct dynarray {
elt *data;
int size;
} dynarray;
您可以定义一些函数来使用dynarrays:
// malloc a dynarray and its data and returns a pointer to the dynarray
dynarray *dynarray_create();
// add an element to dynarray and adjust its size if necessary
void dynarray_add_elt(dynarray *arr, elt value);
// return a particular element in the dynarray
elt dynarray_get_elt(dynarray *arr, int index);
// free the dynarray and its data.
void dynarray_free(dynarray *arr);
这样,用户无需准确记住如何分配内容或当前数组的大小。希望能让你开始。
答案 1 :(得分:6)
尝试重新处理它,以便传入指向数组指针的指针,即ent **a
。然后,您将能够在阵列的新位置更新调用者。
答案 2 :(得分:1)
您正在按值传递数组指针。这意味着:
int main(int argc, char** argv) {
...
ent *a; // This...
...
}
int addValues(ent *a, int mSize) {
...
a = calloc(1, sizeof(ent); // ...is not the same as this
//usual loop
...
}
因此,更改addValues
函数中a的值不会更改main中的值。要更改main中的值,您需要将对它的引用传递给addValues
。目前,正在复制a的值并将其传递给addValues
。传递对使用的引用:
int addValues (int **a, int mSize)
并称之为:
int main(int argc, char** argv) {
...
ent *a; // This...
...
addValues (&a, mSize);
}
在addValues
中,访问以下元素:
(*a)[element]
并像这样重新分配数组:
(*a) = calloc (...);
答案 3 :(得分:1)
这是使用OOP的一个很好的理由。是的,你可以在C上做OOP,如果做得正确它甚至看起来很好。
在这个简单的例子中,你不需要继承或多态,只需要封装和方法概念:
答案 4 :(得分:1)
如果您将main中的变量声明更改为
ent *a = NULL;
通过不释放堆栈分配的数组,代码可以更像你设想的那样工作。将a设置为NULL是有效的,因为realloc将其视为用户调用malloc(size)。请记住,通过此更改,addValue的原型需要更改为
int addValues(ent **a, int mSize)
并且代码需要处理realloc失败的情况。例如
while(....) { //Loop to add items to array
tmp = realloc(*a, size*sizeof(ent));
if (tmp) {
*a = tmp;
} else {
// allocation failed. either free *a or keep *a and
// return an error
}
//Add to array
i++;
}
我希望大多数realloc实现在内部分配两倍的内存,如果当前缓冲区需要调整大小来制作原始代码
size = size * 2;
不必要的。
答案 5 :(得分:0)
Xahtep解释了调用者如何处理realloc()可能将数组移动到新位置的事实。只要你这样做,你应该没事。
如果你开始使用大型数组,那么realloc()可能会变得昂贵。那是时候开始考虑使用其他数据结构了 - 链表,二叉树等等。
答案 6 :(得分:0)
如上所述,您应该将指针传递给指针以更新指针值 但我建议重新设计并避免使用这种技术,在大多数情况下,它可以而且应该避免。在不知道你想要实现什么的情况下很难建议替代设计,但我99%肯定它是可行的其他方式。而Javier感到悲伤 - 认为面向对象,你将永远得到更好的代码。
答案 7 :(得分:0)
你真的需要使用C吗?这将是C ++的“std :: vector”的一个很好的应用,它正是一个动态大小的数组(只需一次调用就可以轻松调整大小,而不必自己编写和调试)。