views:

3158

answers:

10

I'm just learning C and was wondering which one of these I should use in my main method. Is there any difference?

Edit: So which one is more common to use?

+7  A: 

You can use either of the two forms, as in C arrays and pointers are interchangeable in function parameter lists. See http://en.wikipedia.org/wiki/C_(programming_language)#Array-pointer_interchangeability.

lothar
+3  A: 

It doesn't really make a difference, but the latter is more readable. What you are given is an array of char pointers, like the second version says. It can be implicitly converted to a double char pointer like in the first version however.

jalf
+5  A: 

It doesn't make a difference, but I use char *argv[] because it shows that is a fixed size array of variable length strings (which are usually char *).

Zifre
A: 

char ** → pointer to character pointer and char *argv [] means array of character pointers. As we can use pointer instead of an array, both can be used.

Alphaneo
+5  A: 

You could use either, it depends how you want to use it. char* argv[] is (mostly) equivalent to char ** argv. Both forms are pointer to pointers to char, the only difference is that with char *argv[] you are informing the compiler that the value of argv won't change (though the values it points to still can). Actually, I'm wrong, they're completely equivalent. See litb's comments and his answer.

It really depends how you want to use it (and you could use either in any case):

// echo-with-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char **argv)
{
  while (--argc > 0)
  {
    printf("%s ", *++argv);
  }
  printf("\n");
  return 0;
}

// echo-without-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char *argv[])
{
  int i;
  for (i=1; i<argc; i++)
  {
    printf("%s ", argv[i]);
  }
  printf("\n");
  return 0;
}

As for which is more common - it doesn't matter. Any experienced C programmer reading your code will see both as interchangeable (under the right conditions). Just like an experienced English speaker reads "they're" and "they are" equally easily.

More important is that you learn to read them and recognize how similar they are. You'll be reading more code than you write, and you'll need to be equally comfortable with both.

rampion
char* argv[] is 100% equivalent to char** argv when used as a parameter type of a function. no "const" involved, also not implicitly. Both are pointers to pointers to characters. It's different in regard to what you declare. But the compiler adjust the type of the parameter to be a pointer to a pointer, even though you said it's an array. Thus, the followings are all the same: void f(char *p[100]); void f(char *p[]); void f(char **p);
Johannes Schaub - litb
In C89 (which most people use) there is also no way to make benefit of the fact that you *declared* it as an array (so semantically it doesn't matter whether you declared a pointer or an array there - both will be taken as a pointer). Starting with C99, you can benefit from declaring it as an array. The following says: "p is always non-null and points to a region with at least 100bytes": void f(char p[static 100]); Note that type-wise, however, p is *still* a pointer.
Johannes Schaub - litb
Johannes Schaub - litb
Good points! Thanks for educating me!
rampion
A: 

If you'll need a varying or dynamic number of strings, char** might be easier to work with. If you're number of string is fixed though, char* var[] would be preferred.

samoz
A: 

The question is largely moot because in the real world, you're just not writing a main() function very often. Plus, as others have pointed out, both forms are equivalent.

Dan
+19  A: 

As you are just learning C, i recommend you to really try to understand the differences between arrays and pointers first instead of the common things.

In the area of parameters and arrays, there are a few confusing rules that should be clear before going on. First, what you declare in a parameter list is treated special. There are such situations where things don't make sense as a function parameter in C. These are

  • Functions as parameters
  • Arrays as parameters

Arrays as parameters

The second maybe is not immediately clear. But it becomes clear when you consider that the size of an array dimension is part of the type in C (and an array whose dimension size isn't given has an incomplete type). So, if you would create a function that takes an array by-value (receives a copy), then it could do so only for one size! In addition, arrays can become large, and C tries to be as fast as possible.

In C, for these reasons, array-values are not existent. If you want to get the value of an array, what you get instead is a pointer to the first element of that array. And herein actually already lies the solution. Instead of drawing an array parameter invalid up-front, a C compiler will transform the type of the respective parameter to be a pointer. Remember this, it's very important. The parameter won't be an array, but instead it will be a pointer to the respective element type.

Now, if you try to pass an array, what is passed instead is a pointer to the arrays' first element.

Excursion: Functions as parameters

For completion, and because i think this will help you better understand the matter, let's look what the state of affairs is when you try to have a function as a parameter. Indeed, first it won't make any sense. How can a parameter be a function? Huh, we want a variable at that place, of course! So what the compiler does when that happens is, again, to transform the function into a function pointer. Trying to pass a function will pass a pointer to that respective function instead. So, the following are the same (analogous to the array example):

void f(void g(void));
void f(void (*g)(void));

Note that parentheses around *g is needed. Otherwise, it would specify a function returning void*, instead of a pointer to a function returning void.

Back to arrays

Now, i said at the beginning that arrays can have an incomplete type - which happens if you don't give a size yet. Since we already figured that an array parameter is not existant but instead any array parameter is a pointer, the array's size doesn't matter. That means, the compiler will translate all of the following, and all are the same thing:

int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);

Of course, it doesn't make much sense to be able to put any size in it, and it's just thrown away. For that reason, C99 came up with a new meaning for those numbers, and allows other things to appear betweenthe brackets:

// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory. 
int main(int c, char *argv[static 5]);

// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);

// says the same as the previous one
int main(int c, char ** const argv);

The last two lines say that you won't be able to change "argv" within the function - it has become a const pointer. Only few C compilers support those C99 features though. But these features make it clear that the "array" isn't actually one. It's a pointer.

A word of Warning

Note that all i said above is true only when you have got an array as a parameter of a function. If you work with local arrays, an array won't be a pointer. It will behave as a pointer, because as explained earlier an array will be converted to a pointer when its value is read. But it should not be confused with pointers.

One classic example is the following:

char c[10]; 
char **c = &c; // does not work.

typedef char array[10];
array *pc = &c; // *does* work.

// same without typedef. Parens needed, because [...] has 
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;
Johannes Schaub - litb
Wonderful answer. Thank you.
Frank V
A: 

I see no special merit of using either approach instead of the other -- use the convention that is most in line with the rest of your code.

Christoffer
A: 

wuts the different between "char** blah" and "char **blah"

To the compiler, none. To the human, the first is confusing in some circumstances. Now then, you better delete your answer before you lose your only rep point.
Joshua
@Joshua: Answer? I thought this was a question.
Lucas McCoy