Based on my understanding of pointer to pointer to an array of characters,
% ./pointer one two
argv
+----+ +----+
| . | ---> | .
Because argv
is a pointer to pointer to char
, it follows that argv[1]
is a pointer to char
. The printf()
format %s
expects a pointer to char argument and prints the null-terminated array of characters that the argument points to. Since argv[1]
is not a null pointer, there is no problem.
(*argv)[1]
is also valid C, but (*argv)
is equivalent to argv[0]
and is a pointer to char
, so (*argv)[1]
is the second character of argv[0]
, which is /
in your example.
Indexing a pointer as an array implicitly dereferences it. p[0]
is *p
, p[1]
is *(p + 1)
, etc.
It's more convenient to think of []
as an operator for pointers rather than arrays; it's used with both, but since arrays decay to pointers array indexing still makes sense if it's looked at this way. So essentially it offsets, then dereferences, a pointer.
So with argv[1]
, what you've really got is *(argv + 1)
expressed with more convenient syntax. This gives you the second char *
in the block of memory pointed at by argv
, since char *
is the type argv
points to, and [1]
offsets argv
by sizeof(char *)
bytes then dereferences the result.
(*argv)[1]
would dereference argv
first with *
to get the first pointer to char
, then offset that by 1 * sizeof(char)
bytes, then dereferences that to get a char
. This gives the second character in the first string of the group of strings pointed at by argv
, which is obviously not the same thing as argv[1]
.
So think of an indexed array variable as a pointer being operated on by an "offset then dereference a pointer" operator.