I cannot understand this unexpected C behavior where printing argv[0] prints ./a.out instead of the actual content of argv[0] which should be a memory address because argv is an array of pointers.
If I create an array called char name[] = "hello" then I would expect to see h at name[0] and if char * argv[] holds, for example 3 pointers (memory addresses) then logically argv[0] should be a memory address.
My reasoning is that if I wanted to access the actual content of the memory address that argv[0] points to I should need to do *(argv[0]). What is happening here? Is C doing some kind of magic here?
------ ------ ------ --- --- ----
| h | e | l | l | o | \0 |
------ ------ ------ --- --- ----
^---- name[0] = h
------ ------ ------
| 0xA7 | 0xCE | 0xC4 |
------ ------ ------
^---- argv[0] = should be 0XA7 (the value of `argv[0]`,
not the value it points to
#include <stdio.h>
int main(int argc, char * argv[]) {
char name[] = "hello";
printf("%c \n", name[0]); // expected h
printf("%s \n", argv[0]); // expected 0xA7 (but got ./a.out instead)
}
$ gcc main.c
$ ./a.out arg1 arg2 arg3
CodePudding user response:
My reasoning is that if I wanted to access the actual content of the memory address that argv[0] points to I should need to do *(argv[0]). What is happening here?
printf is doing the dereferencing. printf( "%s", argv[0] ) tells uses printf to print *(argv[0]), *(argv[0] 1), *(argv[0] 2), etc until a NUL (zero) is encountered.
printf could not be written to accept *(argv[0]). That would simply pass . instead of an address, so printf would be unable to determine which character came next.
CodePudding user response:
For an array declared like
char name[] = "hello";
the expression name[0] has the type char and by using the conversion specifier c in the call of printf
printf("%c \n", name[0]);
the first element of the array is outputted as a character.
This declaration of an array
char * argv[]
that is used as a parameter declaration is adjusted by the compiler to the declaration
char **argv
and the expression argv[0] has type char *.
The conversion specifier s is designed to output strings pointed to by corresponding arguments like this
printf("%s \n", argv[0]);
argv[0] points to a string that contains the name of the program that runs.
If you want to output the expression as an address you need to write
printf("%p \n", ( void * )argv[0]);
To make it more clear consider this statement
printf( "%s\n", "Hello" );
Its output as I think you are expecting is
Hello
The string literal has the type char[6]. But using as an expression in the call of printf it is implicitly converted to pointer to its first element of the type char *.
So the second argument of the call of printf has the type char * the same way as in the call
printf("%s \n", argv[0]);
where teh second expression also has the type char *.
