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

发布于 2024-07-09 23:23:36 字数 973 浏览 5 评论 0原文

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

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

I'm trying to create a function which takes an array as an argument, adds values to it (increasing its size if necessary) and returns the count of items.
So far I have:

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;
}

This works if mSize is large enough to hold all the potential elements of the array, but if it needs resizing, I get a Segmentation Fault.

I have also tried:

int main(int argc, char** argv) {
    ...
    ent *a;
    ...
}

int addValues(ent *a, int mSize) {
    ...
    a = calloc(1, sizeof(ent);
    //usual loop
    ...
}

To no avail.

I assume this is because when I call realloc, the copy of 'a' is pointed elsewhere - how is it possible to modify this so that 'a' always points to the same location?

Am I going about this correctly? Are there better ways to deal with dynamic structures in C? Should I be implementing a linked list to deal with these?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

旧情勿念 2024-07-16 23:23:36

这里的主要问题是您尝试将 realloc 与堆栈分配的数组一起使用。 你有:

ent a[mSize];

这是堆栈上的自动分配。 如果您想稍后使用 realloc() ,则可以使用 malloc() 在堆上创建数组,如下所示:

ent *a = (ent*)malloc(mSize * sizeof(ent));

以便 malloc 库(以及 realloc() 等)了解您的数组。 从这个看起来,您可能会感到困惑 C99 可变长度数组 具有真正的动态数组,因此在尝试解决此问题之前,请确保您了解其中的差异。

但实际上,如果您用 C 语言编写动态数组,您应该尝试使用 OOP 设计来封装有关数组的信息并向用户隐藏它。 您希望将有关数组的信息(例如指针和大小)合并到结构中,并将操作(例如分配、添加元素、删除元素、释放等)合并到与您的结构一起使用的特殊函数中。 所以你可能会:

typedef struct dynarray {
   elt *data;
   int size;
} dynarray;

并且你可能会定义一些函数来使用动态数组:

// 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);

这样用户就不必准确记住如何分配事物或数组当前的大小。 希望这能让你开始。

The main problem here is that you're trying to use realloc with a stack-allocated array. You have:

ent a[mSize];

That's automatic allocation on the stack. If you wanted to use realloc() on this later, you would create the array on the heap using malloc(), like this:

ent *a = (ent*)malloc(mSize * sizeof(ent));

So that the malloc library (and thus realloc(), etc.) knows about your array. From the looks of this, you may be confusing C99 variable-length arrays with true dynamic arrays, so be sure you understand the difference there before trying to fix this.

Really, though, if you are writing dynamic arrays in C, you should try to use OOP-ish design to encapsulate information about your arrays and hide it from the user. You want to consolidate information (e.g. pointer and size) about your array into a struct and operations (e.g. allocation, adding elements, removing elements, freeing, etc.) into special functions that work with your struct. So you might have:

typedef struct dynarray {
   elt *data;
   int size;
} dynarray;

And you might define some functions to work with 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);

This way the user doesn't have to remember exactly how to allocate things or what size the array is currently. Hope that gets you started.

浅紫色的梦幻 2024-07-16 23:23:36

尝试重新处理它,以便传入指向数组的指针,即 ent **a。 然后您将能够在数组的新位置上更新调用者。

Try reworking it so a pointer to a pointer to the array is passed in, i.e. ent **a. Then you will be able to update the caller on the new location of the array.

橙味迷妹 2024-07-16 23:23:36

这是使用 OOP 的一个很好的理由。 是的,你可以在 C 上进行 OOP,如果做得正确的话,它甚至看起来不错。

在这个简单的情况下,您不需要继承也不需要多态性,只需要封装和方法概念:

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

this is a nice reason to use OOP. yes, you can do OOP on C, and it even looks nice if done correctly.

in this simple case you don't need inheritance nor polymorphism, just the encapsulation and methods concepts:

  • define a structure with a length and a data pointer. maybe an element size.
  • write getter/setter functions that operate on pointers to that struct.
  • the 'grow' function modifies the data pointer within the struct, but any struct pointer stays valid.
天赋异禀 2024-07-16 23:23:36

如果您将 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;

如果当前缓冲区需要调整大小,从而使原始代码变得不必要,

If you changed the variable declaration in main to be

ent *a = NULL;

the code would work more like you envisioned by not freeing a stack-allocated array. Setting a to NULL works because realloc treats this as if the user called malloc(size). Keep in mind that with this change, the prototype to addValue needs to change to

int addValues(ent **a, int mSize)

and that the code needs to handle the case of realloc failing. For example

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++;
}

I would expect that most implementations of realloc will internally allocate twice as much memory if the current buffer needs resizing making the original code's

size = size * 2;

unnecessary.

栩栩如生 2024-07-16 23:23:36

您正在按值传递数组指针。 这意味着:

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 中 a 的值。 要更改 main 中 a 的值,您需要将对它的引用传递给 addValues。 目前,a 的值正在被复制并传递给addValues。 传递对 use: 的引用

int addValues (int **a, int mSize)

并像这样调用它:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
    addValues (&a, mSize);
}

addValues 中,像这样访问 a 的元素:

(*a)[element]

并像这样重新分配数组:

(*a) = calloc (...);

You are passing the array pointer by value. What this means is:

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
    ...
}

so changing the value of a in the addValues function does not change the value of a in main. To change the value of a in main you need to pass a reference to it to addValues. At the moment, the value of a is being copied and passed to addValues. To pass a reference to a use:

int addValues (int **a, int mSize)

and call it like:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
    addValues (&a, mSize);
}

In the addValues, access the elements of a like this:

(*a)[element]

and reallocate the array like this:

(*a) = calloc (...);
給妳壹絲溫柔 2024-07-16 23:23:36

Xahtep 解释了调用者如何处理 realloc() 可能将数组移动到新位置的事实。 只要你这样做,就应该没问题。

如果您开始使用大型数组,realloc() 可能会变得昂贵。 这时就需要开始考虑使用其他数据结构——链表、二叉树等。

Xahtep explains how your caller can deal with the fact that realloc() might move the array to a new location. As long as you do this, you should be fine.

realloc() might get expensive if you start working with large arrays. That's when it's time to start thinking of using other data structures -- a linked list, a binary tree, etc.

说谎友 2024-07-16 23:23:36

如前所述,您应该将指针传递给指针以更新指针值。
但我建议重新设计并避免这种技术,在大多数情况下它可以而且应该避免。 如果不知道您到底想实现什么目标,就很难提出替代设计,但我 99% 确信其他方式也是可行的。 正如 Javier 悲伤 - 思考面向对象并且你总是会得到更好的代码。

As stated you should pass pointer to pointer to update the pointer value.
But I would suggest redesign and avoid this technique, in most cases it can and should be avoided. Without knowing what exactly you trying to achieve it's hard to suggest alternative design, but I'm 99% sure that it's doable other way. And as Javier sad - think object oriented and you will always get better code.

怀中猫帐中妖 2024-07-16 23:23:36

你真的需要使用C吗? 这将是 C++ 的“std::vector”的一个很好的应用,它恰好是一个动态大小的数组(通过一次调用即可轻松调整大小,无需自己编写和调试)。

Are you really required to use C? This would be a great application of C++'s "std::vector", which is precisely a dynamically-sized array (easily resizeble with a single call you don't have to write and debug yourself).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文