Home > OS >  Why is the address to argv different from the address of argv[0]?
Why is the address to argv different from the address of argv[0]?

Time:03-09

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.

  •  Tags:  
  • c
  • Related