Search code examples
cinitializationpass-by-referenceallocation

C: Passing by reference during dynamic allocaion


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?


Solution

  • 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.