【问题标题】:Changing array inside function in C在C中更改函数内部的数组
【发布时间】:2016-04-22 23:47:03
【问题描述】:

我正在学习 C 并且很困惑为什么在 main 中创建的数组不会在函数内部更改,我假设传递的数组是一个指针,并且更改指针应该会更改数组,对吗?有人可以解释在这种情况下发生了什么吗?

感谢您的帮助。

int main(){
    int i, length = 10;
    int array[length];

    for (i = 0 ; i < length ; i++)
        array[i] = i * 10;
    printf("Before:");
    print(array, length);
    change(array, length);
    printf("After:");
    print(array, length);

    return 0;
}

// Print on console the array of int
void print(int *array,int length)
{
    int i;
    for(i = 0 ; i < length ; i++)
        printf("%d ", array[i]);
    printf("\n");
}

// Change the pointer of the array
void change(int *array,int length)
{
    int *new = (int *) malloc(length * sizeof(int));
    int i;
    for(i = 0 ; i < length ; i++)
        new[i] = 1;
    array = new;
}

我希望看到以下输出:

Before:0 10 20 30 40 50 60 70 80 90 
After:1 1 1 1 1 1 1 1 1 1 

我得到了什么:

Before:0 10 20 30 40 50 60 70 80 90 
After:0 10 20 30 40 50 60 70 80 90 

【问题讨论】:

  • 从不,甚至不用于测试。
  • 那你能给点建议吗?谢谢
  • 数组是mainchange 中的一个局部变量。它的地址从main 传递到change。之后,change 可以重新分配它,它不会影响main 中的数组。这两个变量不相关。现在,change 可能会更改array内容,在这种情况下main 也会看到更改。
  • 看看我的回答,你就明白我的意思了。对于编译器for(int i=0;i&lt;length;i++) 是完全可读的,但对于人类......最好是for (int i = 0 ; i &lt; length ; i++)。此外,在同一行中编写多个语句会使阅读变得更加困难。
  • 不要将 malloc 用于此类任务。 Try this.

标签: c arrays function pointers


【解决方案1】:

中,您不能通过引用传递变量,您在函数内部分配的array 变量最初包含与传递的指针相同的地址,但它是它的副本,因此修改它不会改变传递的指针。

你需要传递指针的地址才能改变它,像这样

// Change the pointer of the array
void change(int **array, int length)
{
    *array = malloc(length * sizeof(int));
    if (*array == NULL)
        return;
    for (int i = 0 ; i < length ; i++)
        (*array)[i] = 1;
}

那么在main() 中你不能分配给一个数组,通过这种函数这样做肯定是未定义的行为。 main() 中定义的数组是在堆栈上分配的,您不能将任何内容分配给数组,因为它们是 non-writeable lvalues 所以你不能让它指向堆使用malloc()获得的内存位置,你需要像这样传递一个指针

int *array;
change(&array, length);
free(array);

如果您希望该函数替换之前的数组,则必须将free()malloc()ed 数据(注意将NULL 传递给free() 是明确定义的),所以

// Change the pointer of the array
void change(int **array, int length)
{
    free(*array);

    *array = malloc(length * sizeof(int));
    if (*array == NULL)
        return;
    for (int i = 0 ; i < length ; i++)
        (*array)[i] = 1;
}

然后在main()

int *array;
array = NULL;
change(&array, length);
change(&array, length);
change(&array, length);
change(&array, length);
free(array);

会做你想做的事。

【讨论】:

  • 除了free()之外,它们看起来都一样。我只想更改数组中的一个元素,那么我该使用哪一个?
  • 但是如果我直接更改在main() 中创建的arr,我不需要执行任何操作,因为更改会应用于main() 中的arr
【解决方案2】:

好的,我会简短地回答。

  1. 在 C 中数组总是通过引用传递

更改(数组,长度); 在这一行中,这意味着将对数组变量的第一个元素的引用传递给函数。

现在函数需要一个指针来捕获引用,它可以是指针也可以是数组。请注意,指针或数组是函数本地的。

  1. 您在一个名为数组的指针中收到它。这绝对是一个指针,但它与主函数中的数组不同。它是 change 函数的局部变量。

  2. 您动态声明了一个新数组,并为其分配了一个名为 new 的指针。您所做的所有更改都是针对新指针。

到目前为止一切正常。

  1. 现在您将新指针分配给更改函数的本地数组指针。

这是真正的问题。因为即使数组在堆部分,它也会保留在内存中,但 *array 和 *new 是局部指针变量。

更改函数中的数组指针也不同于主函数中的数组指针。

  1. 这个问题的解决方案是 直接操作数组指针的数据。

    void 变化(int *array,int 长度) { 诠释我; for(i = 0 ; i

通过这种方式,您可以直接覆盖主函数中数组的值。其他一切都是正确的。

总结: 更改函数中的数组指针是更改函数的本地指针。 主函数中的数组对主函数是本地的。 使更改函数的本地数组指针指向堆部分中的数组不会更改实际数组中的数据。您更改了指针的位置,而不是数组的数据。

【讨论】:

    【解决方案3】:

    main 中的数组是一个数组。它会衰减为一个指针,以产生您期望的行为,但它不是一个指针。

    int a[10];
    int* p = a; // equivalent to &a[0]; create a pointer to the first element
    a = p;      // illegal, a is NOT a pointer.
    

    您的代码正在做的是将 a 的地址复制到函数局部变量中。修改它不会比改变长度有更多的区别。

    void change(int* local_ptr, size_t length)
    {
        local_ptr = 0;
        length = 0;
    }
    
    int main()
    {
        int a[10];
        int length = 10;
        printf("before a=%p, length=%d\n", a, length);
        change(a, length);  // we copied 'a' into 'local_ptr'. 
        printf("after a=%p, length=%d\n", a, length);
    }
    

    如果你想修改调用者的指针,你需要使用指针到指针的语法:

    void change(int** ptr, size_t length)
    {
        // change the first element:
        **ptr = 0;
        // change the pointer:
        *ptr = 0;
        // but ptr itself is a function-local variable
        ptr = 0;  // local effect
    }
    

    但是:您尝试执行的操作存在问题,比这更深。

    在您的代码中,“int a”是堆栈上的一个数组,而不是分配的指针;你不能释放它,你应该避免以这种方式混合堆/堆栈指针,因为最终你会释放错误的东西。

    【讨论】:

    • 所以改变第二个元素是**ptr[1]=0?
    【解决方案4】:

    一个简单的例子:

    #include <stdio.h>
    
    void print_array(const int arr[], const int n){
        int i;
        for(i=0; i < n; i++)
            printf("%d ", arr[i]);
        printf("\n");
    }
    
    void change_array(int arr[]){
        arr[0] = 239;
        arr[1] = 234234;
    }
    
    int main(){
        int arr[10] = {};
        print_array(arr,10);
        change_array(arr);
        print_array(arr,10);
        return 0;
    }
    
    输出:
    0 0 0 0 0 0 0 0 0 0 
    239 234234 0 0 0 0 0 0 0 0
    

    【讨论】:

      【解决方案5】:

      您将指向数组array 的指针传递给函数change。在此函数中,您创建另一个名为new 的数组(使用new 作为名称是个坏主意),然后将其分配给本地创建的函数参数array。您不要修改 main 函数中的指针。如果你想这样做,你应该使用

      array = change(array,length);
      

      在你的主要功能和

      int *change(int *array, int length) {
          int *variable_called_new =(int *)malloc(length*sizeof(int));
          [...]
          return variable_called_new
      }
      

      在您的 change 函数中。

      【讨论】:

      • 谢谢它的工作,但无论如何要更改数组的指针而不返回一个 int 指针?
      • @VictorFerreira:你可以在 iharob 答案中找到这个。只需将指针传递给指向数组的指针即可:)
      【解决方案6】:

      使用按值传递
      进行以下更改:
      在函数change(...)中,替换:

      int i;for(i=0;i<length;i++)new[i] = 1;
      

      收件人:

      int i;for(i=0;i<length;i++)array[i] = 1;
                                 ^^^^^
      

      编辑
      但要使用引用传递

      //To change the contents of a variable via a function call
      //the address of that variable has to be passed. So, if you
      //want to change the contents of an array of int, i.e. int *array, you 
      //need to pass its address, not the variable itself,  using the 
      //address of operator, it would look like this &array (read _the address of
      // pointer to int "array")
      //This requires you to change the prototype of your function:
      void change2(int **a, int len)
      {
          int i;
          for(i=0;i<len;i++) (*a)[i] = 1;//parenthesis bind * to a to assure 
                                         //array of pointers to int ( *[] )is populated
                                         //
      }
      

      然后在 main 中进行以下更改,它将按您的意图工作:

      int main(){
          int i,length=10;
          int *array;
      
          array = calloc(length, sizeof(int));
          if(!array) return 0;
          //or malloc if preferred.  But note, in C, 
          //casting the output is not required on either.
          //array = malloc(length*sizeof(int));
          //if(!array) return 0;
      
          for(i=0;i<length;i++)array[i]=i*10;
      
          printf("Before:");print(array,length);
          change2(&array,length);
          printf("After:");print(array,length);
      
          free(array);
      
          return 0;
      }
      

      【讨论】:

      • 我想改变指针,不是逐个值,但还是谢谢
      • @VictorFerreira ,那么您必须传递要更改的指针,而不是值。几分钟后查看我的编辑。
      • 维克多,你说“你想改变指针”是什么意思?你确实改变了指针。顺便说一句,如果您使用不同的名称(传递给“change”的指针的“array”除外),事情可能不会那么混乱,因此当您说要更改“X”时,您的意思会很清楚。
      • @Stuart - 我认为你必须在评论中使用“@Victor Ferreira”,它会标记 Victor...
      • @ryyker 谢谢,我不是想举报他,我想他在等你的评论,所以我不想挤在你面前。顺便说一句,如果您要告诉他将指针传递给指针,那么它将行不通。至少不是在主函数中更改“数组”的意义上(这是不可能的)。
      【解决方案7】:

      所以当你传递数组时,你会得到它的开始地址:

      内存 地址

      |-垃圾-| 1000

      |---0---| 1008

      |---10--| 1012

      。 . . .

      当您在函数中获取指针时,其值为 1008(示例),因此更改它只会意味着您现在指向另一个地方。那不是你想要的。 您可以通过 * 运算符直接更改指向的整数,所以 *array = 99; 将改变第一个元素, *(array+1) = 98; 第二个等等。 您还可以更自然地使用 [] 运算符。 所以在你的功能中 array[0] = 99; 实际上会更改原始数组。

      【讨论】:

        【解决方案8】:
                    #include<stdio.h>
                    #include<stdlib.h>
        
                    // Print on console the array of int
                    void print(int *array,int length)
                    {
                        int i;
                        for(i = 0 ; i < length ; i++)
                            printf("%d ", array[i]);
                        printf("\n");
                    }
        
                    // Change the pointer of the array
                    void change(int **array,int length)
                    {
                        int i;
                        int *ar;
                        ar = (int *)malloc(sizeof(int *) * length);
                        for(i = 0 ; i < length ; i++)
                            ar[i] = 1;
                        (*array) = ar;
                    }
        
                    int main(){
                        int i, length = 10;
                        int *array;
                        array = (int *)malloc(sizeof(int *) * length);
        
                        for (i = 0 ; i < length ; i++)
                            array[i] = i * 10;
                        printf("Before:");
                        print(array, length);
                        change(&array, length);
                        printf("After:");
                        print(array, length);
        
                        return 0;
                    }
        

        【讨论】:

        • 您能否用文字解释您的解决方案与原始问题的不同之处,以及为什么它可以解决问题?此外,原始代码和您的代码都存在内存泄漏。
        【解决方案9】:

        如果您正在寻找最简单的方法来修改 'array' 指向的数据,请将 'change' 函数重写为:

        // [OLD COMMENT] Change the pointer of the array
        // [NEW COMMENT] Change the value(s) of data pointed to by 'array'
        void change(int *array, int length)
        {
           int i;
           for(i = 0 ; i < length ; i++)
               array[i] = 1;
        }
        

        当您传递名为“array”的整数数组的名称时,您将传递一个指向 main 中声明的数组数据的指针。在函数 'change' 中,指针被复制(按值传递)并在函数中使用,就像在 main 中一样。不需要 malloc。

        【讨论】:

          【解决方案10】:

          您正在将数组的引用传递给函数change(),并且重新引用被复制到更改中的指针数组。

          然后您将创建一个变量 new 并使用 malloc 分配内存空间,然后您将为其分配一些值。

          到目前为止,change() 中的指针数组指向 main 中的数组。

          在下一条语句中,您将change() 中的数组指向变量`new 指向的空间,并且pointar 数组不再指向main 中的数组。

          因此,不要使用new[i] = 1,而是在change() 中使用array[i] = 1

          【讨论】:

            猜你喜欢
            • 2021-01-14
            • 1970-01-01
            • 1970-01-01
            • 2020-10-20
            • 1970-01-01
            • 1970-01-01
            • 2023-01-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多