动态增加c中数组(int *)的大小

时间:2016-10-11 19:24:40

标签: c arrays pointers int

我想在c中动态地向数组添加数字。我的想法是只分配一个大小为+ 1的新数组,添加数字,释放根数组并将指针从temp更改为根数组。像这样:

void addNumber(int* a, int* size, int number)
{
    *size = *size + 1;
    int* temp = (int*)(calloc(*size, sizeof(int)));
    int i, j = 0;
    for(i = 0; i < *size-1; i++) {
        if(a[i] < number) {
            printf("add ai");
            temp[j] = a[i];
            j++;
        } else {
            printf("add number");
            temp[j] = number;
        }
    }
    if(j != *size) {
        printf("add new number");
        temp[j] = number;
    }
    free(a);
    a = temp;
}

int main(int argc, char* argv[])
{
    int n = 10;
    int* a;
    int size = 1;

    a = (int*) (calloc(1, sizeof(int)));
    a[0] = 1;

    if(!contains(a, size, 2)) {
        addNumber(a, &size, 2);
    }

    printArray(a,size);

    return 0;
}

问题是在addNumber函数中代码有效,而* a具有新数组的正确值。但在main函数中,数组* a的值为1,0。因此不添加新的插入值2。为什么?无法理解。

4 个答案:

答案 0 :(得分:2)

要动态更改数组大小,可以使用realloc()例程。除了使用eaiser之外,它可以比顺序调用free()malloc()的方法更快。

保证重新分配的块将填充旧内存块的内容。

  

问题是在addNumber函数中代码有效,而* a具有新数组的正确值

您的代码中存在两个主要缺陷。第一个是你的addNumber()例程没有返回新分配的内存块(因此它被泄漏),你应该使用双指针或者将新块作为函数结果返回。

第二个是第一个结果 - 在a被释放后,你继续写信给它。

如果您更愿意坚持使用当前的方法,则此修改后的代码应该有效:

void addNumber(int** a, int* size, int number)
{
    *size = *size + 1;
    int* temp = (int*)(calloc(*size, sizeof(int)));
    int i, j = 0;
    for(i = 0; i < *size-1; i++) {
        if((*a)[i] < number) {
            printf("add ai");
            temp[j] = (*a)[i];
            j++;
        } else {
            printf("add number");
            temp[j] = number;
        }
    }
    if(j != *size) {
        printf("add new number");
        temp[j] = number;
    }
    free(*a);
    *a = temp;
}

int main(int argc, char* argv[])
{
    int n = 10;
    int* a;
    int size = 1;

    a = (int*) (calloc(1, sizeof(int)));
    a[0] = 1;

    if(!contains(a, size, 2)) {
        addNumber(&a, &size, 2);
    }

    printArray(a,size);

    return 0;
}

答案 1 :(得分:1)

  

为什么呢?无法理解。

那是因为您要在a中本地修改addNumber的值。这不会改变amain的值。

为了让main能够访问新分配的内存,您需要更改addNumber以返回新分配的指针。

int* addNumber(int* a, int* size, int number){
   ...
   return a;
}

然后将main更改为:

if(!contains(a, size, 2)){
    a = addNumber(a, &size, 2);
    // Assign to a the new pointer value.
}

答案 2 :(得分:0)

你的'a'在main中已经是一个指针,将它传递给一个函数传递它的副本。你需要做的是 - 传递地址'&amp; a'并以函数形式接收它作为双指针'** a'并在函数内部,使用dereference获取数组内的值(如* a [i]和free( *一个)。 将最后一行更改为'return temp'并将其作为a = addnumber(&amp; a,&amp; size,2)收集在main中;

顺便说一下,为什么不使用realloc()函数,而不是经历所有这些麻烦。它动态增加了数组的大小。使用realloc后,您只需在最后一个索引处添加新号码。

答案 3 :(得分:0)

您正在寻找的是realloc()。它可用于在保留内容的同时增长或缩小内存。

/* array is now sizeof(int) * new_size bytes */
array = realloc(array, sizeof(int) * new_size);

realloc()可能会更改现有的内存分配,或者可能会分配一个全新的内存块。这就是为什么将结果重新分配给重新分配的东西很重要。

但是如果addNumber()通过创建新内存来重新分配数组,main()就不会知道它。出于同样的原因,这是行不通的。

void incrementNumber(int num) {
    num = num + 1;
}

int num是一个按值传递的数字。如果希望它在调用者中反映出来,则需要将其作为指针传递。

void incrementNumber(int *num) {
    *num = *num + 1;
}

指针是一样的。他们仍然是数字。 int *a按值传递指针。如果您更改a中的addNumber,则来电者无法看到它。就像以前一样,你需要将它作为指针传递。指向像这样使用的指针的指针称为double pointer

void addNumber( int **array_ptr, size_t *array_size, size_t type_size, int number ) {
    /* Increment the size and make sure that bubbles up */
    *array_size = *array_size + 1;

    /* realloc might grow the memory, or it might allocate new memory
       either way, assign the result back to its original variable
       by dereferencing the double pointer.
     */
    *array_ptr = realloc(*array_ptr, *array_size * type_size);

    /* Since it's a double pointer, we have to first dereference it before using
       it as an array */
    (*array_ptr)[*array_size - 1] = number;
}

(请注意,我也传递了数组中元素的大小,不能假设)。

通过将指针传递给数组来调用它。

addNumber(&a, &size, sizeof(int), 5);

之后,一切都是一样的。

for( int i = 0; i < size; i++ ) {
    printf("%d ", a[i]);
}
puts("");

最终,您希望通过在结构中包含数组,大小和类型来改进这一点,以便您可以在整齐的包中传递它。

typedef struct {
    int *array;
    size_t size;
} IntArray;

作为一项练习,这很棒,你会学到很多东西,并且会对静态记忆产生许多坏习惯。但是正确有效地进行动态数据结构很困难(例如,一次分配一个额外的插槽效率非常低)。

有很多很多的库提供了这样的动态结构。因此,请继续将其作为练习,但对于实际代码,请使用Gnome Lib等库。