OK, I\'m having trouble understanding pointers to pointers vs pointers to arrays. Consider the following code:
char s[] = \"Hello, World\";
char (*p1)[] = &s
From what I understand, 's' is a pointer to the first element of the array
No, s is an array. It can be reduced to a pointer to an array, but until such time, it is an array. A pointer to an array becomes a pointer to the first element of the array. (yeah, it's kinda confusing.)
char (*p1)[] = &s;
This is allowed, it's a pointer to an array, assigned the address of an array. It points to the first element of s.
char **p2 = &s;
That makes a pointer to a pointer and assigns it the address of the array. You assign it a pointer to the first element of s (a char
), when it thinks it's a pointer to a pointer to one or more chars. Dereferencing this is undefined behavior. (segfault in your case)
The proof that they are different lies in sizeof(char[1000])
(returns size of 1000 chars, not the size of a pointer), and functions like this:
template<int length>
void function(char (&arr)[length]) {}
which will compile when given an array, but not a pointer.
Here's the sample that works, plus printouts of pointer addresses to make things simple to see:
#include <stdio.h>
char s[] = "Hello, World";
char (*p1)[] = &s;
char *p2 = (char*)&s;
int main(void)
{
printf("%x %x %x\n", s, p2, *p2);
printf("%x\n", &s); // Note that `s` and `&s` give the same value
printf("%x\n", &s[0]);
printf("%c\n", **p1);
printf("%c\n", *p2);
}
Your misunderstand lies in what s
is. It is not a pointer: it is an array.
Now in most contexts, s
evaluates to a pointer to the first element of the array: equivalent to &s[0]
, a pointer to that 'H'
. The important thing here though is that that pointer value you get when evaluating s
is a temporary, ephemeral value - just like &s[0]
.
Because that pointer isn't a permanent object (it's not actually what's stored in s
), you can't make a pointer-to-pointer point at it. To use a pointer-to-pointer, you must have a real pointer object to point to - for example, the following is OK:
char *p = s;
char **p2 = &p;
If you evaluate *p2
, you're telling the compiler to load the thing that p2
points to and treat it as a pointer-to-char. That's fine when p2
does actually point at a pointer-to-char; but when you do char **p2 = &s;
, the thing that p2
points to isn't a pointer at all - it's an array (in this case, it's a block of 13 char
s).