【问题标题】:dynamically increase size of array (int*) in c在c中动态增加数组(int *)的大小
【发布时间】:2017-02-20 11:00:48
【问题描述】:

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

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 具有新数组的正确值。但在主函数中,数组 *a 的值为 1,0。所以新插入的值 2 不会被添加。为什么?找不到原因。

【问题讨论】:

  • a = temp; 毫无用处。 a 是一个局部变量。该分配不会影响amain()
  • realloc 正是你想要的。
  • 为什么不简单地用 realloc 扩大之前分配的内存呢?
  • @RPGillespie 如果这只是一个 C++ 问题...
  • @RPGillespie 如果 OP 不熟悉 C++(请参阅 stackoverflow.com/users/3172567/user3172567)或此 C 标记帖子的查看者不熟悉 C++,那么提供 C++ 解决方案的价值远低于专注于 C,也许甚至适得其反。

标签: c arrays pointers int


【解决方案1】:

为什么?找不到原因。

那是因为你正在本地修改a 的值在addNumber。这不会改变maina 的值。

为了让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】:

    要动态更改数组大小,您可以使用realloc() 例程。除了更易于使用之外,它还可以比顺序调用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;
    }
    

    【讨论】:

      【解决方案3】:

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

      顺便说一句,与其经历所有这些麻烦,不如直接使用 realloc() 函数。它动态增加数组的大小。使用 realloc 后,您只需在最后一个索引处添加新数字即可。

      【讨论】:

        【解决方案4】:

        您正在寻找的是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 之类的库。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-17
          • 1970-01-01
          • 1970-01-01
          • 2021-08-12
          相关资源
          最近更新 更多