I have been messing a bit with C lately and i have come across some "weird" behavior
#include <stdio.h>
int main(int argc, char **argv) {
printf("&argv=%d\n&argv[0]=%d\n", &argv, &(argv[0]));
return 0;
}
the pointer to argv is completely different from the pointer of argv[0] as C arrays are contiguous shouldn't the pointer to the argv be the same to the start of the first C string? in my head the argv should look something like this
char **argv = {char *, char *, char *};
where the start of the argv array be the same as the start of the first string how is this structured and why aren't the two pointers the same?
CodePudding user response:
printf
requires that you use the format specifier that matches with the type of the argument that you pass. %d
does not match with the type of the arguments that you pass (it requires int
or similar), and therefore the behaviour of the program is undefined.
I recommend avoiding printf
in general (Edit: question used to be tagged [c ]), but if you must use it, then you can use %p
format specifier for void*
. You must convert the pointer arguments to void*
.
Once you've fixed the program, you'll find that the addresses are indeed different. The explanation is that argv
is a pointer that doesn't point to itself. Hence its value is different from where it is stored. It points to another object stored elsewhere.
... the argv array ...
argv
is not an array. Function arguments cannot be arrays. argv
is a pointer.
You can create an analogous structure like this:
char args[] = "./a.out\0example\0argument";
char* ptrs[] = {
args 0,
args 8,
args 16,
0,
};
int argc = 3;
char** argv = ptrs;
// argv == &ptrs[0]
// argv != &argv
CodePudding user response:
C arrays are contiguous, but on the one hand you took the address of the array, and on the other hand you took the addresses in the array.
This is perhaps more obvious if you print out the argv[i]
values for all values of i
like this:
$ cat pointer.c
#include <stdio.h>
int main(int argc, char** argv) {
int i;
for (i = 0; i < argc; i) {
printf("&argv=%p\targv=%p\t&argv[%d]=%p\n", &argv, argv, i, &(argv[i]));
}
return 0;
}
$ gcc pointer.c
$ ./a.out 1 2 3
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[0]=0x7ff7b37167e0
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[1]=0x7ff7b37167e8
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[2]=0x7ff7b37167f0
&argv=0x7ff7b3716690 argv=0x7ff7b37167e0 &argv[3]=0x7ff7b37167f8
While %p
is a better format specifier, your %d
would have worked too, if you were printing out the address of the first element of the array (which is just argv
) instead of a pointer to the address of the first element of the array (which is &argv
and not what you meant).
CodePudding user response:
as C arrays are contiguous shouldn't the pointer to the argv be the same to the start of the first C string?
The address of an array is indeed the same as the address of its 1st element, yes. But argv
is not an array, it is a pointer to an array. &argv
is the address of the pointer itself, not the address of the array that it is pointing at. Evaluating argv
by itself will return the address of the array. And as such, &(argv[0])
is the address of the 1st element of the array.
Try this instead, and you will see that argv
and &argv
are two different addresses:
printf("&argv=%p\nargv=%p\n&argv[0]=%p\n", &argv, argv, &(argv[0]));
CodePudding user response:
For starters you shall use the conversion specifier %p
to output pointers using the function printf
.
Function parameters are local variables of the function.
You can imagine the function main the following way
int main( /*int argc, char** argv */) {
int argc = some_argument expression;
char **argv = some_argument_expression;
//...
Thus the expression &argv
gives the address of the local variable argv
The expression argv[0]
is the first element of the array pointed to by the local variable argv
that has the type char **
. And the expression &argv[0]
gives the address of the first element of the pointed array.
So &argv
is the address of the local variable argv
that is defined in main as its parameter. While &argv[0]
is the address of the first element of an array that is defined outside the function main.
To make it more clear consider a very simple program.
#include <stdio.h>
int main* void )
{
int a[] = { 1, 2, 3, 4, 5 };
int *p = a;
printf( "&p = %p, &p[0] = %p\n", ( void * )&p, ( void * )&p[0] );
}
As you see the expression &
p yields the address of the variable p
that occupies its own extent of memory while the expression &p[0]
yields the address of the first element of the array a
that occupies a separate extent of memory.