Let’s look at a simpler example. Suppose you say
int *ip;
ip[0] = 5;
ip
is a pointer to one or more int
s — but it’s not initialized, so it points nowhere, so ip[0]
isn’t a valid memory location, so we can’t store the value 5 there.
In the same way, when you said
char **p;
p
is a pointer that points nowhere. If it did point somewhere, it would point to another pointer. But it doesn’t point anywhere, so
p[0] = strdup("hello");
blows up.
To fix this, you need to make p
point somewhere, and specifically to memory allocated to hold one or more pointers. There are many ways to do this:
char *q;
p = &q; /* way 1 */
char *a[10];
p = a; /* way 2 */
p = malloc(10 * sizeof(char *)); /* way 3 */
or instead of using a pointer, use an array to start with:
char *p[10]; /* way 4 */
After any of those, p[0] = strdup("hello")
should work.
For way 3, we would also need to check that malloc
succeeded (that it dd not return a null pointer).
For ways 2 through 4, we could also set p[1]
through p[9]
. But for way 1, only p[0]
is valid.
See also this answer to a different question for more discussion about trying to use uninitialized pointers.
There is declared an uninitialized pointer that has an indeterminate value.
char **p;
so dereferencing the pointer in this expression p[0]
(that is equivalent to the expression *p
) used in this statement
p[0] = strdup("hello");
invokes undefined behavior because there is an attempt to write to memory using an incorrect pointer value of the expression p[0]
.
You could write either for example
char *s;
char **p = &s;
p[0] = strdup("hello");
Or
char **p = malloc( sizeof( char * ) );
p[0] = strdup("hello");
That is the pointer to pointer p
must point to a valid object. Thus dereferencing the pointer you will get a valid object of the type char *
that will be assigned by the value returned by the call of strdup
..