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

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

有帮助吗?

解决方案

这里的主要问题是,你想用栈分配的数组使用的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;

和您可以定义某些功能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);

此方式,用户不必记得到底如何分配的事或什么大小的阵列是目前。希望得到您开始。

其他提示

尝试返工它,以便一个指向指针数组传递中,即ent **a。然后,你将能够更新在阵列的新位置的呼叫者。

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

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

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

如果你改变了主要的变量声明为

ent *a = NULL;

像你通过不释放一个堆栈分配的阵列所设想的代码将工作更多。一个设置为NULL的作品,因为realloc的将这种情况视为如果用户调用的malloc(大小)。请注意,与该变化,原型的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;

不必要的。

您是通过值传递数组的指针。这意味着:

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

所以改变a的值在addValues功能在主不改变a的值。要更改主的价值,你需要传递给它一个参考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 (...);

Xahtep解释您的来电者可以如何处理的事实,realloc()的可能的阵列转移到新的位置。只要你做到这一点,你应该罚款。

realloc()的,如果你开始使用大型数组的工作可能会贵。这时候,是时候开始使用其他数据结构的思路是 - 一个链表,二叉树等

如上所述你应该通过指针指向更新指针值。结果 不过,我会建议重新设计,避免这种技术,在大多数情况下,它可以而且应该避免。不知道你究竟想达到什么很难提出替代设计,但我99%肯定这是可行的其他方式。而作为哈维尔伤心 - 认为面向对象你总是会得到更好的代码。

您真正需要用C?这将是C ++的‘标准::载体’,而这恰恰是一个动态大小的阵列(具有单个呼叫容易resizeble你不必编写和调试自己)的一个重要的应用。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top