If a char* array is defined with at least one value, the first value can be indexed via "arr[0]" and printed successfully with the format specifier "%s". However, if a char** is defined, it will segfault if the first element is attempted to be printed with printf or similar functions (with string format specifier).
Below is a block of code that demonstrates how this works:
char* s = "test";
char** sa = { s };
char* arr[] = { s };
// Prints pointers of each variable
puts("\nTest 1:");
puts("----------------------------------------");
printf("s:\t%p\n", s);
printf("sa:\t%p\n\n", sa);
// Dereferences pointers, prints as pointers (even though *s is a char)
puts("Test 2:");
puts("----------------------------------------");
printf("s:\t%p\n", *s);
printf("sa:\t%p\n\n", *sa);
// Prints strings of each variable
puts("Test 3:");
puts("----------------------------------------");
printf("s:\t%s\n", s);
printf("sa:\t%s\n\n", sa);
// Prints first element of array (works unlike *(char**), which I would think are the same)
puts("Test 4:");
puts("----------------------------------------");
printf("arr:\t%s\n", arr[0]);
printf("arr:\t%s\n\n", *arr);
// Prints strings of dereferenced pointers (segfault for sa)
puts("Test 5:");
puts("----------------------------------------");
printf("s:\t%s\n", *s);
printf("sa:\t%s\n\n", *sa);
This is the potential output:
Test 1:
----------------------------------------
s: 0x10013bf2c
sa: 0x10013bf2c
Test 2:
----------------------------------------
s: 0x74
sa: 0x65540a0074736574
Test 3:
----------------------------------------
s: test
sa: test
Test 4:
----------------------------------------
arr: test
arr: test
Test 5:
----------------------------------------
zsh: segmentation fault ./test2
I understand that dereferencing variable s returns the ASCII value for the first character, which is "t" in this case. However, I’m confused on why variable sa doesn’t dereference to the first string in the array? Shouldn’t dereferencing the double pointer return the pointer to s?
I’ve tried returning strings from the pointer sa returns, but it only segfaults, meaning that the pointer for sa under Test 2 has no meaning or association with the string bounded to s.
>Solution :
For starters you do not have an array. In this declaration
char** sa = { s };
you declared a pointer of the type char ** that is initialized by the value of the variable s of the type char *.
char* s = "test";
char** sa = { s };
The compiler should issue a message that there is no implicit conversion between these two pointer types.
The difference between these two outputs
printf("s:\t%p\n", *s);
printf("sa:\t%p\n\n", *sa);
is that in the first case the expression *s has the type char that is promoted to the type int. That is only the first byte of the string literal is read as a value.
In the second case the expression *sa is considered as an expression of the pointer type char *. So the function reads the memory occupied by the expression as a memory storing a pointer of the size 4 or 8 bytes depending on the used system without any promotions as in the first case.
As for your comment to my answer
Also, when the char* version of sa (when sa is dereferenced) is
attempted to be printed as a string using the format specifier "%s", a
segfault occurs. This is the main source of what I’m a bit
confused
about
When the pointer sa is dereferenced then its value is the value composed by characters stored in the string literal and this value is interpreted as a pointer when the conversion specifier %s is used. That of course results in undefined behavior.
See the output of the code you showed in your question
sa: 0x65540a0074736574
This part of the outputted value 74736574 represents the word "test" written in the reverse order "tset".
You could write instead
char* s = "test";
char** sa = { &s };
and then
printf( "%s\n", *sa );
In this case the pointer sa will contain the address of the declared pointer s and the expression *sa yields the value stored in the pointer s that is the address of the first character of the string literal "test".