将动态数组传递给C中的函数

时间:2008-12-04 16:48:09

标签: c arrays function realloc

我正在尝试创建一个函数,该函数将数组作为参数,向其添加值(必要时增加其大小)并返回项的计数。 到目前为止,我有:

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中的动态结构?我应该实施一个链表来处理这些吗?

8 个答案:

答案 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,如果做得正确它甚至看起来很好。

在这个简单的例子中,你不需要继承或多态,只需要封装和方法概念:

  • 定义具有长度和数据指针的结构。也许是元素大小。
  • 编写对该结构指针进行操作的getter / setter函数。
  • 'grow'函数修改结构中的数据指针,但任何结构指针都保持有效。

答案 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”的一个很好的应用,它正是一个动态大小的数组(只需一次调用就可以轻松调整大小,而不必自己编写和调试)。