I am assuming pointer size and integer size = $4$ Bytes.
/*
We know any ptr + k = value_of(ptr) + k * sizeof(*ptr);
Now,
b[2][3] = *(*(b+2)+3)
Type of b is int (*)[5]
The initial value of b is 1000 with type int (*)[5]
b + 2 = 1040 with Type int (*)[5]
*(b + 2) = 1040 with Type int *
*(b + 2) + 3 = 1052 with type int *
*(*(b + 2) + 3) = [1052] = scan 4 bytes from 1052
and get the value which is an int
int *a[5];
a[2][3] = *(*(a+2)+3)
Type of a is int **
The initial value of a is 2000 with Type int **
a + 2 = 2008 with Type int **
*(a + 2) = [2008] scan 4 bytes from 2008
and get the value which is an int *
= 1040 of Type int *
*(a + 2) + 3 = 1052 with type int *
*(*(a + 2) + 3) = [1052] = scan 4 bytes from 1052
and get the value which is an int
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main() {
srand(time(NULL));
int b[5][5],i,j;
int *a[5];
for(i = 0;i<5;i++) {
for(j = 0;j<5;j++) {
b[i][j] = rand()%100;
}
}
printf("Array b : \n \n");
// printing the original b[][] array
for(i = 0;i<5;i++) {
printf("\t");
for(j = 0;j<5;j++) {
printf("%3d ",b[i][j]);
}
printf("\n\n");
}
// int *a[5] : a is an array of 5 integer pointers
// assign these pointers with starting addresses of rows of b
// Type of b[i] = int *
for(i = 0;i<5;i++) {
a[i] = b[i];
}
printf("a[2][3] = b[2][3] = %d\n",a[2][3]);
}
/*
//output
Array b :
43 98 68 87 90
67 34 49 51 35
41 33 25 91 96
86 53 8 16 93
68 21 43 20 24
a[2][3] = b[2][3] = 91
*/
a can be used for other purposes as well other than accessing a $2D$ array elements