In C, an array of strings is typically stored in memory as a sequence of pointers to the individual strings. The individual strings themselves are stored in contiguous blocks of memory with the final character being a null terminator ('\0'), and each pointer in the array points to the start of one of these blocks.

For example:

char *strings[] = {"hello", "world", "!"};

Let’s assume that the array of pointers strings is stored at 0x100 and that each string is stored in memory at the following locations:

"hello" -> 0x200
"world" -> 0x300
"goodbye" -> 0x400

The array of pointers strings would be stored in memory as:

address     value
0x100       0x200
0x104       0x300
0x108       0x400

The memory contents of the strings themselves would be stored in memory as:

address     value    character
0x200       104      h
0x201       101      e
0x202       108      l
0x203       108      l
0x204       111      o
0x205       0        \0

0x300       119      w
0x301       111      o
0x302       114      r
0x303       108      l
0x304       100      d
0x305       0        \0

0x400       41       !
0x401       0        \0

The expression strings[0] would return a pointer to the first character of the first string in the array of strings. In the example, strings[0] would return the memory address 0x100, which is the address of the character 'h'.

The expression *strings[0] would return the character pointed to by the first element of the strings array, which is a pointer to a string. The * operator dereferences the pointer, so the expression would return the first character of the first string in the array: 'h'.