6

Possible Duplicate:
argc and argv in main

I'm having difficulty understanding the notation used for the general main function declaration, i.e. int main(int argc, char *argv[]). I understand that what is actually passed to the main function is a pointer to a pointer to char, but I find the notation difficult. For instance:

Why does **argv point to the first char and not the whole string? Likewise, why does *argv[0] point to the same thing as the previous example.

Why does *argv point to the whole first string, instead of the first char like the previous example?

This is a little unrelated, but why does *argv + 1 point a string 'minus the first char' instead of pointing to the next string in the array?

Community
  • 1
  • 1
hcaulfield57
  • 431
  • 1
  • 5
  • 10
  • argv as array of strings: `char* argv[]` `arv[0]` is the first string, `argv[0][0]` is the first byte of the first string etc. – Alex F Nov 13 '12 at 15:11
  • 1
    There are no "strings" in C, just arrays of characters. Perhaps you're confused about what "pointing to the whole string" means. – Kerrek SB Nov 13 '12 at 15:13
  • You need to understand two unrelated pieces of basic C syntax: 1) in function arguments, `T[]` is the same as `T*`. 2) For a pointer `p`, `p[i]` is identical to `*(p + i)`, and also `&*p` is identical to `p`. Use that to reflect on your question. – Kerrek SB Nov 13 '12 at 15:16
  • Sounds like you're having some issues understanding pointers vs. arrays. Take a look at [this Q&A](http://stackoverflow.com/questions/12676402/why-cant-i-treat-an-array-like-a-pointer-in-c) to see if it helps clear that up at least. – Mike Nov 13 '12 at 15:20
  • I think much of why I'm getting thrown off with this is misunderstanding regarding order of operations. – hcaulfield57 Nov 13 '12 at 20:18

4 Answers4

11

Consider a program with argc == 3.

   argv
     |
     v
+---------+         +----------------+
| argv[0] |-------->| program name\0 |
+---------+         +-------------+--+
| argv[1] |-------->| argument1\0 |
+---------+         +-------------+
| argv[2] |-------->| argument2\0 |
+---------+         +-------------+
|    0    |
+---------+

The variable argv points to the start of an array of pointers. argv[0] is the first pointer. It points at the program name (or, if the system cannot determine the program name, then the string for argv[0] will be an empty string; argv[0][0] == '\0'). argv[1] points to the first argument, argv[2] points to the second argument, and argv[3] == 0 (equivalently argv[argc] == 0).

The other detail you need to know, of course, is that array[i] == *(array + i) for any array.

You ask specifically:

  • Why does **argv point to the first char and not the whole string?

*argv is equivalent to *(argv + 0) and hence argv[0]. It is a char *. When you dereference a char *, you get the 'first' character in the string. And **argv is therefore equivalent to *(argv[0]) or *(argv[0] + 0) or argv[0][0].

(It can be legitimately argued that **argv is a character, not a pointer, so it doesn't 'point to the first char'. It is simply another name for the 'p' of "program name\0".)

  • Likewise, why does *argv[0] point to the same thing as the previous example.

As noted before, argv[0] is a pointer to the string; therefore *argv[0] must be the first character in the string.

  • Why does *argv point to the whole first string, instead of the first char like the previous example?

This is a question of convention. *argv points at the first character of the first string. If you interpret it as a pointer to a string, it points to 'the whole string', in the same way that char *pqr = "Hello world\n"; points at 'the whole string'. If you interpret it as a pointer to a single character, it points to the first character of the string. Think of it as like wave-particle duality, only here it is character-string duality.

  • Why does *argv + 1 point a string 'minus the first char' instead of pointing to the next string in the array?

*argv + 1 is (*argv) + 1. As already discussed, *argv points at the first character of the first string. If you add 1 to a pointer, it points at the next item; since *argv points at a character, *argv+1 points to the next character.

*(argv + 1) points to the (first character of the) next string.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • This is _very_ helpful, thank you for the response. You've helped a lot with my understanding, at least I think so. So the reason why the whole string gets printed out in say printf with `*argv` is because printf takes `char *`, so it prints out the whole string? – hcaulfield57 Nov 13 '12 at 20:21
  • Yes. If you use a `%s` format string, then `printf("%s\n", *argv);` prints the whole string. If you use `printf("%p\n", (void *)*argv);`, then you'll get just the address printed. (I should apologize that I'm not sure whether 'first' is used consistently; it usually means 'subscript 0'.) – Jonathan Leffler Nov 13 '12 at 21:14
  • Okay, thanks again for the effort put into your answer! – hcaulfield57 Nov 13 '12 at 22:22
3

It all falls down to pointer arithmetic.

*argv[0] = *(*(argv + 0)) = **argv

Since [] has higher precedence than unary *.

On the other hand, *argv gives the first cell in the array, an array containing pointers. What does this pointer point to? Why a char array, a string, of course.

*argv + 1 gives what it gives because + has lower precedence than unary *, so first we get a pointer to a string, and than we add 1 to it, thus getting a pointer the the second character in the string.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
3

I understand that what is actually passed to the main function is a pointer to a pointer to char

No, what's passed is an array of char pointers (an array of character strings). Think of it like this, if I give this at the command prompt:

>> ./program hello 456

My program's main will get:

argc == 3

argv[0] == program (the name of the program as a string)
argv[1] == hello   (the first parameter as a string)
argv[2] == 456     (the second parameter as a string)

Why does **argv point to the first char and not the whole string?

char *argv[]  //an array of character pointers
*argv         // an array decays to a pointer, so this is functionally equivalent to
              // argv[0]
**argv        // Now the argv[0] decays to a pointer and this is functionally
              // equivalent to (argv[0])[0]

Likewise, why does *argv[0] point to the same thing as the previous example.

See above.

Why does *argv point to the whole first string, instead of the first char like the previous example?

See above.

Mike
  • 47,263
  • 29
  • 113
  • 177
  • 1
    My Stack Overflow Rule of Thumb #3: "If the question starts with 'I understand', they don't." – Kerrek SB Nov 13 '12 at 15:41
  • @KerrekSB - That is a very wise rule. :) – Mike Nov 13 '12 at 15:44
  • The last example holds true, because strings are actually arrays? – hcaulfield57 Nov 13 '12 at 20:25
  • @hcaulfield57 - Exactly. `argv` is an array of "strings". `*argv` is the first of those "strings". `**argv` is the first character of the first "string". A "string" being a character array in C. – Mike Nov 13 '12 at 21:05
0

This is all because an array is also a pointer to the first element in the array in c. **argv dereferences our pointer to pointer to char twice, giving us a char. *argv[0] is basically saying 'dereference that address, and return the first element in the array described by the address we just got from dereferencing,' which happens to be the same thing. *argv only dereferences once, so we still have a pointer to char, or a char array. *argv + 1 dereferences once, giving us the first character string, and then adds 1 to the address, giving us the address of the second element. Because pointers are also arrays, we can say that this is the array *argv minus the first element.

Zistack
  • 516
  • 3
  • 10
  • 1
    An array is **not** a pointer. Arrays are arrays, and pointers are pointers. – Kerrek SB Nov 13 '12 at 15:41
  • Please revise. Arrays and pointers are different. – Mike Nov 13 '12 at 15:53
  • 1
    I beg to differ. If you declare an array like this: `int a[];` it is exactly the same as saying this: `int* a;`. Fundamentally, an array is just a pointer to a bunch of data arranged consecutively in memory. – Zistack Nov 13 '12 at 18:37
  • How do you figure? `int a[];` won't compile since there's no array size. If you have `int c = 3;` you can assign it's address to a pointer such as `int *b = &c;`. If you try that with an array `int a[1]; a = &c;` you get `error: incompatible types` because you can't assign an array any address you want as you can a pointer. Because it's not a pointer. Arrays don't "point". – Mike Nov 13 '12 at 21:18
  • 1
    Then try compiling this: `int a[3] = {0,1,2}; int b = *a; int c = *(a+2); int* d = a; int e = d[1];` You will find it compiles just fine. I realize that you can't declare an array with no size, but if you declare one with a size, you can treat it as a pointer in every sense except assignment. This is because the array is fixed in memory location, and thus the array actually has a type of `const int *`. However, you can assign a random pointer to an array, and manipulate the array through the pointer just like the pointer is an array, because they are essentially the same thing. – Zistack Nov 13 '12 at 23:56