【问题标题】:copying pointers and memory allocation confusion复制指针和内存分配混乱
【发布时间】:2020-02-06 05:45:58
【问题描述】:

如果我想创建一个接收数组并对其进行修改的函数。

void mod_Arr(int* arr) {
    int*arr = int[3][3]; //arr is now an array
    int*arrCpy = arr;
    //some modification to arrCpy
}

``

1) arr 也会被修改吗? 即我必须包括以下行: arr = arrCpy; 还是我应该改用: arr = mod_Arr(arr) //并让 mod_Arr 返回一个数组? 2)我必须 free(arr) 以防止 arr 的旧值占用空间吗?如果指针现在指向新内存而不是修改旧地址的值,我是否必须清理仍然在旧地址中的无用内容?

【问题讨论】:

  • 也许你应该从实际编译的代码开始你的问题。
  • 不是 C 语言。

标签: c arrays pointers


【解决方案1】:

如果您在main() 中有一个数组,即int a[3][3];,并且您想将该数组传递给您的函数,以便可以在函数内对其进行修改,并在调用函数中看到更改(main() 此处),您必须将数组的地址作为参数传递。如果你只是简单地传递数组本身按值,那么函数会收到一个数组的copy-of,并且在函数中对数组所做的任何更改都会丢失返回——就像任何其他本地声明的数组一样。

当您将 address-of 设为一个数组时,您就有了一个指向该数组的指针。在您的情况下,指向二维数组的指针。上述类型的语法为int (*a)[3][3]。 (例如 int[3][3]pointer-to-array)所以要传递 address-of 数组(它仍然是传递地址 by-value,C 没有引用),您的函数声明如下所示:

void mod_arr (int (*a)[ROWS][COLS])
{
    for (int i = 0; i < ROWS; i++)
        for (int j = 0; j < COLS; j++)
            (*a)[i][j] = (i + 1) * (j + 1);
}

要在函数内对原始数组进行操作并分配/更改元素的值,您必须取消引用 指向数组的指针。如果你看上面,那将是:

            (*a)[i][j] = (i + 1) * (j + 1);

由于C operator precedence,需要在(*a) 周围加上括号。

声明一个简短的prn_arr 函数来打印结果,您可以执行以下操作:

#include <stdio.h>

#define ROWS 3
#define COLS ROWS

void mod_arr (int (*a)[ROWS][COLS])
{
    for (int i = 0; i < ROWS; i++)
        for (int j = 0; j < COLS; j++)
            (*a)[i][j] = (i + 1) * (j + 1);
}

void prn_arr (int a[ROWS][COLS])
{
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++)
            printf (" %2d", a[i][j]);
        putchar ('\n');
    }
}

int main (void) {

    int a[ROWS][COLS] = {{0}};

    mod_arr (&a);
    prn_arr (a);
}

在上面的main() 中,您只需声明数组并将值初始化为零,然后将地址传递给mod_arr 以操作数组,然后调用prn_arr 以输出结果——只需要传递数组本身(它是指向第一行值的指针)。

但是,请记住,对于大型数组,将指向数组的指针作为参数传递比传递数组的完整副本更有效(例如,无论大小如何,x86_64 上的指针都是 8 字节数组,而以 1000x1000 数组为例,它需要复制元素字节大小的 1,000,000 倍)

使用/输出示例

$ ./bin/modarr
  1  2  3
  2  4  6
  3  6  9

所以你可以看到,通过将数组按地址传递给你的函数,函数接收到数组的原始地址(而不仅仅是作为一些新地址的数组的副本),所以在@987654336 中所做的更改@ 是对原始数组本身的地址所做的更改,并将在调用函数中看到。

查看一下,如果您还有其他问题,请告诉我。在使用指针和数组时,这是一个核心问题——了解所涉及的类型以及这些类型的语法,让您能够使其全部工作。

【讨论】:

    【解决方案2】:

    如果您将变量 按值 传递给函数,则函数将不会修改此变量,如果您将变量 按引用 (如指向 @ 的指针987654323@ 在您的情况下)该函数将修改变量:

    void f(int a)
     {
       a = a+2; // or equivalently a+=2
     }
    

    不会修改a (pass-by-value)

    同时

    void f(int* a)
     {
       a* = (*a)+2;  // or equivalently (*a)+=2
     }
    

    将修改a (pass-by-reference)

    背景是函数有自己的本地作用域,在 pass-by-value 的情况下,return 可以留下但是上面的函数返回@ 987654329@ 因此它不会修改其本地范围之外的任何内容 (https://www.geeksforgeeks.org/scope-rules-in-c/)

    在 C 中,数组可以按值传递,例如 https://www.geeksforgeeks.org/pass-array-value-c/

    如果你通过引用传递数组(使用指针),你可以直接在函数中修改数组,而不需要复制一些东西

    您可以使用以下方法对此进行测试:

    #include <stdio.h>
    
    void f1(int a)   // pass-by-value
      {
         a+=2;
      }
    
    void f2(int* a)  // pass-by-reference (pointer)
      {
         (*a)+=2;
      }
    
    int main(int argc, char argv[])
    {
        int a=0;
        f1(a);
        printf("a=%i \n",a);
        a=0;
        f2(&a);
        printf("a=%i \n",a);#
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-29
      • 1970-01-01
      相关资源
      最近更新 更多