How a pointer to multidimensional arrays works in C

I am experimenting with the concept of a pointer to a multidimensional array in C. Suppose I want to process a multidimensional array through a function. The code is as follows:

#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 that when I want to access the array inside proc_arr , I cannot. In my opinion, we should access it this way:

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

So, I canceled the array to tell the compiler that I want to go to this address and get the value. But for some reason he falls. I tried several combinations of * and parentheses and still can't get it to work. I am sure that this is because I do not understand pointers and pointer pointers.

Oh, and I noticed that this is different if we work with char ** (a string array) as well as for argv and envp. But for envp, somehow I can access it using (*envp) . Why?

Here is the function that executes envp (and works):

 int envplen(char ***envp) { int count = 0; while((*envp)[count] != NULL) { count++; } return count; } 

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

Thanks before.

+4
source share
3 answers

The problem is that the int array[10][10] allocated on the stack does not allocate memory the way you think. This is because arrays are not pointers. The memory is still laid out in a linear array, and not in a "two-dimensional" array, although this may mean indexes. In other words, the memory for int array[10][10] as follows:

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

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

 int*** array | | | Pointer | | | | Pointer_0 | Pointer_1 | ... | Pointer 10 | | | | | | | Block of 10 int | | | | | Block of 10 int | | |Block of 10 int| 
+8
source

You have a type mismatch. Given the declaration of int array[10][10] , the expression type &array will be int (*)[10][10] , not int *** . If you change your function prototype, 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 based on a specific 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 large arrays should be clear.

+4
source

This will not work:

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

Because behind the scenes, the compiler will have to change this to a memory offset relative to the beginning of the array. This means that he must know the size of the array. You did not declare them in the function signature.

+2
source

All Articles