These
int a[3][5];
int *b[3][5];
(I think you mean indeed int *b[3][5] instead of int *b[3][3] as it is written in your question)
two declarations of two-dimensional arrays.
Elements of the first array have type int.
Elements of the second array have type int *.
To access elements of the arrays you can use for example subscripting like
a[i][j] or b[i][j] where i is an index in the range [0,3) and j is an index in the range [0, 5).
For the second array to access objects pointed to by the elements of the array you can use expressions like *b[i][j]
sizeof( a ) is equal to 3 * sizeof( int[5] ) that in turn is equal to 3 * 5 * sizeof( int ).
sizeof( b ) is equal to 3 * sizeof( int *[5] ) that in turn is equal to 3 * 5 * sizeof( int *).
This
int (*c)[3][5];
is a declaration of a pointer to a two-dimensional array of the type int[3][5].
You can write for example
int (*c)[3][5] = &a;
where a is the two-dimensional array declared above.
To access elements of the pointed array you can use this syntax
( *c )[i][j]
This
int *(d[3][5]);
a declaration of a two-dimensional array elements of which have type int *.
This declaration is equivalent to the declaration shown above that is to
int *b[3][5];
You may enclose declarators in parentheses. So you could even write the declaration of the array d like
int * (((d)[3])[5]);
This
int (*e[3])[5];
is a declaration of an array with 3 elements of pointers to arrays of the type int[5].
Using the typedef
typedef int T[5];
the array declaration can be rewritten like
T * e[3];
Here a demonstrative program that shows how elements of the array e can be accessed.
#include <stdio.h>
int main( void )
{
int a1[5] = { 1, 2, 3, 4, 5 };
int a2[5] = { 10, 20, 30, 40, 50 };
int a3[5] = { 100, 200, 300, 400, 500 };
int(*e[3])[5] = { &a1, &a2, &a3 };
for (size_t i = 0; i < sizeof( e ) / sizeof( *e ); i++)
{
for (int j = 0; j < sizeof(*e[i]) / sizeof(**e[i]); j++)
{
printf( "%3d ", ( *e[i] )[j] );
}
putchar( '\n' );
}
return 0;
}
The program output is
1 2 3 4 5
10 20 30 40 50
100 200 300 400 500
rowsnumber of 1D arrays.int *b[3][3]is a 2D array of pointers to typeint.int (*c)[3][5]is a pointer to a 3x5 array ofintint *(d[3][5]);is the same as*d[3][5]andint (*e[3])[5];is an *array of pointers to 3int(5 of them)dis the same as b (except for the 3 vs. 5) - the parentheses have no effect, andeis an array of 3 pointers, which point to arrays of 5 ints. In particular, sizeof(e) is 3*8 = 24.