Two-dimensional arrays and secondary pointers in function parameters

Keywords: C C++

Two-dimensional arrays and secondary pointers in function parameters

Preface:

_Two-dimensional arrays are passed through a second-order pointer in a template function given by leetcode, which also gives an array of Row rows and Col columns. a[i][j] is often used directly in the function to traverse each element of the two-dimensional array.A segment error occurs when a [i][j] traverses the array in a function when the two-dimensional array actually declared at the time of writing code is in the stack.To explore the reasons, this paper summarizes the array pointer, the pointer array, and the two-dimensional array and secondary pointer in the function parameters.

1. Array pointers and arrays of pointers

[]Operator precedence over* therefore[]First with p Combination 
int *p[10]; 	// Pointer array An int * pointer array of size 10
int (*p)[10]; 	// Array pointer An int pointer to an array of size 10

2. Array names and de-references in two-dimensional arrays

for example:2-D Array a[3][3],Where:
a			a First address			Type is:	int (*)[3]
&a			a First address			Type is:	int [3][3]
&a[0]		a First address			Type is:	int (*)[3]
&a[0][0]	a First address			Type is:	int *

_The above type declaration can be verified by the following code, which also indicates that a[3][3] is equivalent to a[9] = {1,2,3,4,5,6,7,8,9} and that a[2][1] is equivalent to a[1][4], where array crossovers or segment errors do not occur, i.e., a[i][j] = *(*(a+i)+j) = *(*(int*) a + i).

/* Array names and de-references in two-dimensional arrays */
#include <stdio.h>                                                          
int main(){
    int a[3][3] = {
        {1,2,3},
        {4,5,6},
        {7,8,9}
    };
    printf("a in stack\n");
    printf("a:%p\ta+1:%p\n",a,a+1);
    printf("&a:%p\t&a+1:%p\n",&a,&a+1);
    printf("&a[0]:%p\t&a[0]+1:%p\n",&a[0],&a[0]+1);
    printf("&a[0][0]:%p\t&a[0][0]+1:%p\n",&a[0][0],&a[0][0]+1);
}


_The above code two-dimensional arrays are declared on the stack, whereas when using malloc to dynamically declare two-dimensional arrays, it is often necessary to declare a second-level pointer (int **a) before storing the first address of each row of subarrays, where a[i][j] = *(*(a + i) + j) must be established and not necessarily equal to *((int *)a + i*Col + j), because the address space dynamically allocated by each row of subarrays is not necessarily continuous.

#include <stdio.h>   
#include <stdlib.h>
int func(int **array, int m, int n) {
    printf("array in heap\n");
    printf("array[i][j]\t*((int *)array + i * 3 + j)\n");
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {                                       
            printf("%d\t\t", array[i][j]);
            printf("%d", *((int *)array + i * n + j));
            printf("\n");
            
        }
    }
    printf("\n");
    return 0;
}
int main() {
    int **array = (int **)malloc(sizeof(int *) * 3);
    for (int i = 0; i < 3; ++i) {
        array[i] = (int *)malloc(sizeof(int) * 3);
        for (int j = 0; j < 3; ++j) {
                array[i][j] = i * 3 + j + 1;
        }
    }
    func(array,3,3);
    return 0;
} 

3. Two-dimensional arrays and secondary pointers in function parameters

_First of all, it is important to note that there is no difference between a two-dimensional array and a secondary pointer, and then when passing a two-dimensional array to a function, you need to note whether it is dynamically allocated on or in the stack.

  • Heap Allocation
    Heap allocation for two-dimensional arrays has been mentioned in the previous section. Function parameters are usually passed directly by a second-order pointer. Arrays can be traversed directly by a[i][j] in a function, but not by *((int *)a + i *Col + j).

  • Stack Assignment
    If two-dimensional arrays are allocated on the stack, this is a more complex situation, and the general pattern is as follows:

// 1.int (*)[Col] parameter type
void fun(int a[Row][Col]);
void fun(int a[][Col]);
void fun(int (*a)[Col]);

_In the above three ways, the array can be traversed either directly through a[i][j] in a function or through *((int *)a + i *Col + j).In addition, two-dimensional arrays allocated in the stack can also be passed through secondary pointers, but in this way arrays cannot be traversed directly by a[i][j], but only by *((int *)a + i *Col + j).

// 2.int ** Parameter type
void fun(int **a);

_The actual type of the array name a is int (*)[Col]. When using the array name a as a function argument, the type is forced to convert to int **, the de-reference *(*(a + i) + j) of a[i][j], which is actually equivalent to **((int *)a + i + j), and accessing an address with a value of a[i + j] causes a segment error.To solve this problem, you can convert a secondary pointer (int **) to an (int (*)[Col]) pointer before traversal, or store the first address of each row's subarray in a pointer array before arguments are passed in.

1.int (*)ptr[Col] = (int (*)[Col])a;
2.int *ptr[Row] = {0};
  for (int i = 0; i < Row; ++i) {
  		ptr[i] = a[i];
  }

Posted by shak123 on Tue, 07 Sep 2021 09:45:01 -0700