C:动态分配时通过引用传递

C: Passing by reference during dynamic allocaion

我的代码是分配和初始化数组如下(floatalloc2是一个用于分配二维数组的函数):

#include <stdio.h>
#include <stdlib.h>

void alloc_arr(int adjwfd, int nx, int nz, float **G, float **L1, float **L2)
{
G = floatalloc2(nx, nz);
switch (adjwfd){
    case 1:
        L1 = floatalloc2(nx, nz);
        break;
    case 2:
        L2 = floatalloc2(nx, nz);
        break;
}
}

void init_arr(int adjwfd, int nx, int nz, float **G, float **L1, float **L2)
{
memset(G[0],0,nx*nz*sizeof(float));
switch (adjwfd){
    case 1:
        memset(L1[0],0,nx*nz*sizeof(float));
        break;
    case 2:
        memset(L2[0],0,nx*nz*sizeof(float));
        break;
}
}


int main(int argc, char *argv[])
{   

int adjwfd_P=1, nx=10, nz=10;
float **glob=NULL, **local1=NULL, **local2=NULL;

alloc_arr(adjwfd_P, nx, nz, glob, local1, local2);
init_arr(adjwfd_P, nx, nz, glob, local1, local2);

exit(0);
}

编译通过。但是当我 运行 这段代码时,它出错了:

YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11)

但是,我发现如果我按如下方式更改 alloc_arr,它会 运行 成功:

#include <stdio.h>
#include <stdlib.h>    

void alloc_arr(int adjwfd, int nx, int nz, float ***G, float ***L1, float ***L2)
{
*G = floatalloc2(nx, nz);
switch (adjwfd){
    case 1:
        *L1 = floatalloc2(nx, nz);
        break;
    case 2:
        *L2 = floatalloc2(nx, nz);
        break;
}
}

void init_arr(int adjwfd, int nx, int nz, float **G, float **L1, float **L2)
{
memset(G[0],0,nx*nz*sizeof(float));
switch (adjwfd){
    case 1:
        memset(L1[0],0,nx*nz*sizeof(float));
        break;
    case 2:
        memset(L2[0],0,nx*nz*sizeof(float));
        break;
}
}


int main(int argc, char *argv[])
{   

int adjwfd_P=1, nx=10, nz=10;
float **glob=NULL, **local1=NULL, **local2=NULL;

alloc_arr(adjwfd_P, nx, nz, &glob, &local1, &local2);
init_arr(adjwfd_P, nx, nz, glob, local1, local2);

exit(0);
}

我的问题是为什么我必须取二维数组的地址,而在alloc_arr中只为分配部分定义三维数组,而在其他函数如init_arr中,我可以只将原始二维数组传递给函数吗?

发生这种情况是因为 scopes

在您的 main 函数中定义:

    // [...]
    float **array = NULL;

Just a reminder that array is a pointer to a pointer (a 2D array as you call it).

alloc_arr 函数中,您想更改 array 在主函数中 指向的位置。因此,您传递了对局部变量 array 的引用。这样 alloc_arr 函数就可以改变局部变量 array.

一个更简单的例子:

void change_value(int *a)
{
    *a = 42;
}

void cant_change_value(int a)
{
    a = -21;
}

int main(void)
{
    int a = 0;
    // At this point a is 0
    cant_change_value(a);
    // a is still 0, because cant_change_value only modified the COPY of a
    // that was passed to the function
    change_value(&a);
    // a is now 42, because the function change_value received the address of a
    // and modified it's content
    return (0);
}

回到您的示例,如果函数 alloc_arr 没有使用指向您的二维数组的指针,它将无法修改 main 函数中的指针。

This 很好地介绍了指针的工作原理。


PS:你的变量名应该更明确地说明它们是什么。 “adjwfd_P”可能对您有意义,但对其他阅读您代码的人可能没有意义。

why I have to take the address of the 2D array, and in the alloc_arr define 3D array only for the allocation part,......

在这种情况下:

alloc_arr(adjwfd_P, nx, nz, glob, local1, local2);

您实际上将最后三个参数作为 NULL 传递给 alloc_arr() 函数参数 GL1L2 作为 glob, local1local2NULL 初始化,在 alloc_arr()

void alloc_arr(int adjwfd, int nx, int nz, float **G, float **L1, float **L2)
{
G = floatalloc2(nx, nz);
.....
    L1 = floatalloc2(nx, nz);
.....
    L2 = floatalloc2(nx, nz);
.....

内存正在分配给 GL1L2,它们是 alloc_arr() 函数的 局部变量 。在main()中,globlocal1local2alloc_arr()函数返回后仍然是空指针。这些空指针传递给 init_arr(),当试图在 init_arr() 中访问它们时,您的程序出现分段错误。

在这种情况下

alloc_arr(adjwfd_P, nx, nz, &glob, &local1, &local2);

您正在将指针 globlocal1local2 的地址作为参数传递给 alloc_arr() 函数参数 GL1L2,这意味着 GL1L2 将分别保存 globlocal1local2 指针的地址。

void alloc_arr(int adjwfd, int nx, int nz, float ***G, float ***L1, float ***L2)
{
*G = floatalloc2(nx, nz);
.....
        *L1 = floatalloc2(nx, nz);
.....
        *L2 = floatalloc2(nx, nz);
.....

取消引用指针 G 将得到 glob 指针,即 *Gglob。同样,取消引用 *L1*L2 将分别给出指针 local1local2。所以,当分配内存给*G*L1*L2时,实际上会分配内存给globlocal1local2指针。

whereas in other functions such as init_arr, I can just pass the original 2D array into the function?

看看这个:

alloc_arr(adjwfd_P, nx, nz, &glob, &local1, &local2);
init_arr(adjwfd_P, nx, nz, glob, local1, local2);

alloc_arr() 将内存分配给 globlocal1local2,这意味着从 alloc_arr() 返回后(假设一切正常)指针 globlocal1local2 指向有效的内存位置。在 init_arr() 中,您只是将这些内存位置作为参数传递给 init_arr() 函数参数 GL1L2。在 init_arr() 中,访问 GL1L2 意味着它正在访问这些内存位置。


附加:

遵循良好的编程习惯,确保在程序退出前释放分配的内存。