Reputation: 15
First code block (*arr[]
)
char *arr[] = {"abc", "def"};
int main(void) {
int arr_len = sizeof(arr) / sizeof(*arr);
printf("%d\n", arr_len);
return 0;
}
Second code block (**arr
)
char **arr = {"abc", "def"};
int main(void) {
int arr_len = sizeof(arr) / sizeof(*arr);
printf("%d\n", arr_len);
return 0;
}
Compiler warnings for second code block:
second.c:3:15: warning: initialization of ‘char **’ from incompatible pointer type ‘char *’ [-Wincompatible-pointer-types]
char **arr = {"abc", "def"};
^~~~~
second.c:3:15: note: (near initialization for ‘arr’)
second.c:3:22: warning: excess elements in scalar initializer
char **arr = {"abc", "def"};
^~~~~
second.c:3:22: note: (near initialization for ‘arr’)
For the first block, I get the expected output of 2
as there are only two strings in the array. For second block however, I get 1
as the output.
Since arrays decay into pointers, isn't **arr
the same?
Upvotes: 0
Views: 227
Reputation: 222763
char **arr = {"abc", "def"};
defines arr
to be a pointer to a pointer to a char
. Note that it is a pointer—just one. So it should be initialized with one pointer, and that should be a pointer to a pointer to char
.
{"abc", "def"}
is a list of two things, so it is wrong for initializing one thing.
"abc"
is a string literal. Used in this way, it is automatically converted to a pointer to its first element. That results in a pointer to char
, which is the wrong type to initialize a pointer to a pointer to char
.
You can provide a single pointer of the correct type by using a compound literal:
char **arr = (char *[]) { "abc", "def" };
That form, that looks like a cast (but is not) in front of a list, creates an object of the type given in parentheses and initializes it with the things inside braces. So the code above creates an array of char *
and initializes them with the string literals (which are converted to char *
). Then that array is automatically converted to a pointer to its first element, and that pointer initializes arr
.
Once you have done this, however, sizeof(arr) / sizeof(*arr);
will be the size of a char **
(because that is what arr
is) divided by a char *
(because that is what *arr
is).
In contrast, char *arr[] = {"abc", "def"};
defines an array of pointers to char
and initializes it with the two pointers that result from the string literals. That simpler definition is usually what one wants.
Since arrays decay into pointers, isn't **arr the same?
The fact that an array used in an expression (other than as the operand of sizeof
or unary &
) is converted to a pointer does not mean the array is a pointer. An array is an array. The address of the array is where the array is (the same, except for type, as the address of its first element)—it is not the address of a pointer.
Upvotes: 4