1.
As the other answers and comments said, the expression "char *exStr[]" means "array of pointers to char".
a) How to read it
The best way to read it (as well as other more complex C declarations) is to start at the thing's name (in this case "exStr") and work your way towards the extremities of the declaration, like this:
- First go right, adding each encountered meaningful symbol(s) to the meaning of the expression
- Stop going right at the first closing paranthesis ")", or when the expression ends
- When you cannot go right anymore, resume where you started and go left, again adding each encountered symbol to the meaning of the expression
- Stop going left at the paranthesis "(" that corresponds to the ")" that stopped you on the right, or at the beginning of the expression
- When stopped going left at a "(" paranthethis and you haven't reached the beginning of the expression, resume going right immediately after the ")" that corresponds to it
- Keep going right and left until you reach the margins of the expression both ways
In your case, you would go like that:
- start at exStr: that's the variable's name
- go right: []: exStr is an array
- go right: stop: there's nothing there, the "=" sign stops us
- go left: *: exStr is an array of pointers
- go left: char: exStr is an array of pointers to char
- go left: stop: there's nothing there, the "=" sign stops us
b) Why are you seeing that each array element occupies a different amount of bytes
When you have a value like "Zorro", it's a C string.
A C string is an array of bytes that starts at a given address in memory and ends with 0. In case of "Zorro" it will occupy 6 bytes: 5 for the string, the 6th for the 0.
You have several ways of creating C strings. A few common ones are:
A) use it literally, such as:
printf("Zorro");
B) use it literraly but store it in a variable:
char *x = "Zorro";
C) allocate it dynamically and copy data into it
size_t n = 2;
char *p = malloc((n+1) * sizeof(char));
char c = getch(); // read a character from the console
p[0] = c;
p[1] = 0;
// do something with p...
free(p);
Whenever you're putting a string value like "Zorro" in your program, the compiler will reserve memory for just enough to hold this string plus the 0 terminator. It will initialize this memory with whatever you provided inside "", it will add the 0, and secretly keep a pointer to that memory. It will prevent you from modifying that memory (you cannot change that string).
In your code sample, it did this for every string that appeared in the exStr initialization.
That's why you see each array element occupying a different amount of memory. If you look closer to your debugger output, you'll see that the compiler reserved memory for a string immediately after the preceding one, and each string occupies its length in bytes plus the 0 terminator. E.g. "Zorro" starts at 02f, and occupies positions 02f - 034, which are 6 bytes (5 for Zorro and 1 for the 0 terminator). Then "Alex" starts at 035, occupies 5 bytes: 035 - 039, and so on.
2.
To create a similar array programmatically:
If all you have are some static strings like in your example, then your code sample is good enough.
Otherwise if you plan to put dynamic values into your array (or if you plan to change the original strings in the program), you would do something like:
#define COUNT 5
char *strings[COUNT];
int i;
for (i = 0; i < COUNT; i++) {
int n = 32; // or some other suitable maximum value, or even a computed value
strings[i] = malloc((n+1) * sizeof(char));
// put up to 32 arbitrary characters into strings[i], e.g. read from a file or from console; don't forget to add the 0 terminator
}
// use strings...
// free memory for the strings when done
for (i = 0; i < COUNT; i++) {
free(strings[i]);
}
char *exStr[]: an array of pointers to chars. Each pointer points to the first char in each null-terminated strings.