问题
I have argv[] defined as a char *. Using the following printf statements:
printf("%s\n",argv[1]); // prints out the entire string
printf("%p\n",&argv[1]); // & -> gets the address
printf("%c\n",argv[1][0]);// prints out the first char of second var
printf("%c\n",*argv[1]); //
It's this last one I don't understand. What does it mean to print *argv[1]
? why isn't that the same as *argv[1][0]
and how come you can't print out printf("%s\n",*argv[1]);
. Also, why is &*argv[1]
a different address then &argv[1]
?
回答1:
The array subscript operation a[i]
is defined as *(a + i)
- given the address a
, offset i
elements (not bytes) from that address and dereference the result. Thus, given a pointer p
, *p
is equivalent to *(p + 0)
, which is equivalent to p[0]
.
The type of argv
is char **
; given that, all of the following are true:
Expression Type Value
---------- ---- -----
argv char ** Pointer to a sequence of strings
*argv char * Equivalent to argv[0]
**argv char Equivalent to argv[0][0]
argv[i] char * Pointer to a single string
*argv[i] char Same as argv[i][0]
argv[i][j] char j'th character of i'th string
&argv[i] char ** Address of the pointer to the i'th string
Since the type of argv[i][j]
is char
, *argv[i][j]
is not a valid expression.
Here's a bad visualization of the argv
sequence:
+---+ +---+ +---+
argv | | ---> argv[0] | | ---------------------------> argv[0][0] | |
+---+ +---+ +---+ +---+
argv[1] | | -------> argv[1][0] | | argv[0][1] | |
+---+ +---+ +---+
... argv[1][1] | | ...
+---+ +---+ +---+
argv[argc] | | ---||| ... argv[0][n-1] | |
+---+ +---+ +---+
argv[1][m-1] | |
+---+
This may help explain the results of different expressions.
回答2:
char *argv[]
argv
is array(1) of char pointers. So it is normal array just each element of the array is a pointer. argv[0]
is a pointer, argv[1]
, etc.
argv[0]
- first element in the array. Since each element in the array is char pointer, value of this is also a char pointer (as we already mentioned above).
*argv[1]
- Now here argv[1]
is second element in the above array, but argv[1]
is also a char pointer. Applying *
just dereferences the pointer and you get the first character in the string to which argv[1]
points to.
You should use %c
to print it as this is just a character.
argv[1][0]
is already first character of second string in the array - so no more room for dereferencing. This is essentially same as previous.
(1) as highlighted strictly saying it is pointer to pointer, but maybe you can "think" of it as array of pointers. Anyway more info about it here: https://stackoverflow.com/a/39096006/3963067
回答3:
If argv[1]
is a pointer to char
, then *argv[1]
dereferences that pointer and gets you the first character of the string at argv[1]
, so it's the same as argv[1][0]
and is printed with the "%c"
format specifier.
argv[1][0]
is a char
itself, not a pointer, so it's not dereferensable.
回答4:
- This is not specific to
char *
. - You can simplify by what is the difference between *ptr and ptr[0].
- There are no difference because ptr[0] is a sugar for *(ptr + 0) or *ptr because
+ 0
is useless.
// printf("%p\n", &argv[1]); is wrong you must cast to (void *)
printf("%p\n", (void *)&argv[1]);
Because %p
specifier expect a void *
, in normal case C auto promote your pointer into void *
but printf()
use variable argument list. There are a lot of rule about this, I let you read the doc if you want. But char *
wiil not be promote to void *
and like I say printf()
except void *
so you have a undefined behavior if you don't cast it yourself.
回答5:
The last line printf("%c\n",*argv[1]);
is both dereferencing argv
and accessing array index 1
. In other words, this is doing argv[1][0]
, just like the previous line, because the array subscript access [1]
has a higher precedence than the dereference operator (*
).
However, if you were to parenthesize the expression in the last line to make the dereference operator be processed first, you would do this:
printf("%c\n", (*argv)[1]);
Now, when you run the program, the last line of output would be argv[0][1]
instead of [1][0]
, i.e. the second character in the command line you use to execute the program.
来源:https://stackoverflow.com/questions/41664392/understanding-the-dereference-address-of-and-array-subscript-operators-in-c