C: Passing by reference during dynamic allocaion

*爱你&永不变心* 提交于 2019-12-11 17:04:10

问题


My code is to allocate and initialize the array as follows (floatalloc2 is a function used to allocate the 2D array):

#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);
}

It passes the compilation. But when I run this code, it goes wrong says:

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

However, I found that if I change the alloc_arr as follows, it runs successfully:

#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);
}

My question is why I have to take the address of the 2D array, and in the alloc_arr define 3D array only for the allocation part, whereas in other functions such as init_arr, I can just pass the original 2D array into the function?


回答1:


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

In this case:

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

You are actually passing the last three argument as NULL to alloc_arr() function parameter G, L1 and L2 as the glob, local1 and local2 are initialized with NULL and in 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);
.....

the memory is getting allocated to G, L1 and L2 which are local variables of alloc_arr() function. In the main(), the glob, local1 and local2 are still null pointers after alloc_arr() function returned. These null pointers passed to init_arr() and when trying to access them in init_arr() your program is giving segmentation fault.

and in this case

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

you are passing the address of pointers glob, local1 and local2 as argument to alloc_arr() function parameters G, L1 and L2, which means G, L1 and L2 will hold address of glob, local1 and local2 pointers respectively.

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);
.....

Dereferencing the pointer G will give glob pointer i.e. *G is glob. Similarly, dereferencing *L1 and *L2 will give pointer local1 and local2 respectively. So, when allocating memory to *G, *L1 and *L2 will actually allocate memory to glob, local1 and local2 pointers.

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

Look at this:

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

the alloc_arr() will allocate memory to glob, local1 and local2 which means after returning from alloc_arr() (assuming everything works as expected) the pointers glob, local1 and local2 are pointing to valid memory locations. In the init_arr() you are just passing those memory locations as argument to the init_arr() function parameters G, L1 and L2. In the init_arr(), accessing G, L1 and L2 means it is accessing those memory locations.


Additional:

Follow good programming practice, make sure to free the allocated memory before program exits.




回答2:


That happens because of scopes.

In your main function you define:

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

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

In the alloc_arr function you want to change where array in the main funcion is pointing to. So you pass a reference to your local variable array. This way the alloc_arr function can change the local variable array.

A simpler example:

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);
}

Back to your example, if the function alloc_arr didn't take a pointer to your 2D array it would not be able to modify your pointer in the main function.

This is a good introduction to how pointers work.


PS: Your variable names should be more explicit as to what they are. "adjwfd_P" might make sense to you, but it probably doesn't to anybody else reading your code.



来源:https://stackoverflow.com/questions/57912873/c-passing-by-reference-during-dynamic-allocaion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!