Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Pointer of Multi-Dimension Arrays Work in C

I'm experimenting with the concept of pointer to multi-dimension array in C. Suppose I want to process a multi-dimensional array via a function. The code kinda looks like this:

#include <stdio.h>

void proc_arr(int ***array)
{
    // some code
}

int main(int argc, char **argv)
{
    int array[10][10];
    for(int i = 0; i < 10; i++)
    {
        for(int j = 0; j < 10; j++)
        {
            array[i][j] = i * j;
        }
    }

    proc_arr(&array);

    return 0;
}

The problem is, when I want to access array inside proc_arr, i can't. From my understanding, we should access it this way:

void proc_arr(int ***array)
{
    (*array)[0][1] = 10;
}

So I derefer the array to tell the compiler that I want to go to that address and get the value. But somehow, it crashes. I've tried several combinations of * and parentheses and still can't make it work. I'm pretty sure it's because of me not understanding pointers and pointers of pointers.

Oh, and I've noticed that it's different if we work with a char **(array of string) too, like for argv and envp. But for envp, I somehow can access it with (*envp). Why?

Here's the function that procces envp (and worked):

int envplen(char ***envp)
{
    int count = 0;

    while((*envp)[count] != NULL)
    {
        count++;
    }

    return count;
}

Also, can I somehow access envp in the envplen function with only envp, but still pass it by reference?

Thanks before.

like image 450
bertzzie Avatar asked Dec 10 '22 06:12

bertzzie


2 Answers

The problem is because int array[10][10] allocated on the stack does not lay out memory the way you think it does. This is because arrays are not pointers. The memory is still laid out in a linear array, not a "two dimensional" array, even though that's what the subscripts might indicate. In other words, the memory for int array[10][10] looks like the following:

starting address:                                    ending address:
| Block_1 of 10 int | Block_2 of 10 int | ... | Block_10 of 10 int |

So when you implicitly convert the array to an int***, and then try to access the array like (*array)[1][10], what this actually translates to is something like *(*((*array) + 1) + 10), and the memory layout for such an operation wants to see memory setup like the following:

int*** array
|
|
| Pointer |
|
|
| Pointer_0 | Pointer_1 | ... | Pointer 10 |
       |          |                 |
       |          |                 | Block of 10 int |
       |          |
       |          | Block of 10 int |
       |
       |Block of 10 int|
like image 158
Jason Avatar answered Dec 29 '22 13:12

Jason


You have a type mismatch. Given the declaration int array[10][10], the type of the expression &array will be int (*)[10][10], not int ***. If you change your function prototype to read

void proc_arr(int (*array)[10][10])

then your code should work as written.

The following table shows the types for various array expressions given a particular declaration.

Declaration: T a[M]; 

Expression      Type               Decays To        
----------      ----               ---------        
         a      T [M]              T *              
        &a      T (*)[M]                   

        *a      T                           
      a[i]      T                           

Declaration: T a[M][N]; 

Expression      Type               Decays To        
----------      ----               ---------        
         a      T [M][N]           T (*)[N]         
        &a      T(*)[M][N]
        *a      T [N]              T *
       a[i]     T [N]              T *
      &a[i]     T (*)[N]
      *a[i]     T 
    a[i][j]     T

Declaration: T a[M][N][O]; 

Expression      Type               Decays To        
----------      ----               ---------        
         a      T [M][N][O]        T (*)[N][O]
        &a      T (*)[M][N][O]     
        *a      T [N][O]           T (*)[O]
      a[i]      T [N][O]           T (*)[O]
     &a[i]      T (*)[N][O]     
     *a[i]      T [N]              T *
   a[i][j]      T [N]              T *
  &a[i][j]      T (*)[N]
  *a[i][j]      T
a[i][j][k]      T

The pattern for higher-dimensioned arrays should be clear.

like image 26
John Bode Avatar answered Dec 29 '22 13:12

John Bode