While declaration was covered, perhaps differences in usage should also be pointed out:
char s[5][5]; --
s points to an area of allocated memory (heap if global, stack if local),
- you may safely write up to 25 char values at
s[0][0] .. s[4][4] (or at s[0] .. s[24]),
sizeof(s) == 25.
char *s[5]; --
s points to an area of allocated memory (heap if global, stack if local),
- you may safely write up to 5 pointer values at
s[0] .. s[4],
sizeof(s) == 40 (*).
char (*s)[5]; --
s does not point to any allocated memory -- it's merely an uninitialized pointer at this point,
- you may safely write one pointer value at
&s,
sizeof(s) == 8 (*).
(*) note: assuming a 64-bit architecture.