This might be a bit of a basic question, but what is the difference between writing char * [] and char **? For example, in main,I can have a char * argv[]. Alternatively I can use char ** argv. I assume there's got to be some kind of difference between the two notations.
- 2It's all just syntactic sugar.Paul Tomblin– Paul Tomblin2010-11-17 19:44:25 +00:00Commented Nov 17, 2010 at 19:44
- Sure, but I think there's a difference in the meaning. For example, I can declare char ** something. but cannot declare char * something[].user472875– user4728752010-11-17 19:46:12 +00:00Commented Nov 17, 2010 at 19:46
- 2It's certainly NOT syntactic sugar, for understanding the differences I suggest the very nice book "Expert C Programming" by Peter van der Linden, it has a whole section on the difference between the two.steabert– steabert2010-11-17 20:11:13 +00:00Commented Nov 17, 2010 at 20:11
- 1I found a similar explanation on this page: lysator.liu.se/c/c-faq/c-2.htmlsteabert– steabert2010-11-18 06:34:09 +00:00Commented Nov 18, 2010 at 6:34
8 Answers
Under the circumstances, there's no difference at all. If you try to use an array type as a function parameter, the compiler will "adjust" that to a pointer type instead (i.e., T a[x] as a function parameter means exactly the same thing as: T *a).
Under the right circumstances (i.e., not as a function parameter), there can be a difference between using array and pointer notation though. One common one is in an extern declaration. For example, let's assume we have one file that contains something like:
char a[20]; and we want to make that visible in another file. This will work:
extern char a[]; but this will not:
extern char *a; If we make it an array of pointers instead:
char *a[20]; ...the same remains true -- declaring an extern array works fine, but declaring an extern pointer does not:
extern char *a[]; // works extern char **a; // doesn't work 3 Comments
extern behaviour?T is an incomplete type then T a[x] is not permitted as parameter, but T *a is.Depends on context.
As a function parameter, they mean the same thing (to the compiler), but writing it char *argv[] might help make it obvious to programmers that the char** being passed points to the first element of an array of char*.
As a variable declaration, they mean different things. One is a pointer to a pointer, the other is an array of pointers, and the array is of unspecified size. So you can do:
char * foo[] = {0, 0, 0}; And get an array of 3 null pointers. Three char*s is a completely different thing from a pointer to a char*.
4 Comments
char* argv[] ?[] form strongly suggests it's intended that an array be passed. I disagree, though, that char** means it's not intended to be used as an array, since there are a lot of C programmers (me included) who can't be bothered with it. char* doesn't usually mean "just one character" - it's commonly used for strings. I don't see why char** should mean "just one char*". So I'd say that char ** means "check the docs", whereas char *[] means "check the docs" ;-)char** I agree it's context-specific. If that's a function param I read it as "a string that the function can change". That said, I am mostly C++ these days so I'll defer to your expertise (and the docs of course).You can use cdecl.org to convert them to English:
char *argv[]= declareargvas array of pointer to charchar **argv= declareargvas pointer to pointer to char
Comments
I think this is a little bit more than syntactic sugar, it also offers a way to express semantic information about the (voluntary) contract implied by each type of declaration.
With char*[] you are saying that this is intended to be used as an array.
With char**, you are saying that you CAN use this as an array but that's not the way it's intended to be used.
Comments
As it was mentioned in the other answers, char*[] declares an array of pointers to char, char** declares a pointer to a pointer to char (which can be used as array).
One difference is that the array is constant, whereas the pointer is not.
Example:
int main() { char** ppc = NULL; char* apc[] = {NULL}; ppc++; apc++; /* this won't compile*/ return 0; } 2 Comments
a declared as char * const a will get you a "increment of read-only value" error, while increasing b declared as char b[1] will produce an "lvalue required as increment operand".const are actually non-const arrays with const elements). The reason apc++ doesn't compile is because the ++ operator is defined as only being applicable to pointers and non-complex numeric types, and arrays are not pointers.This really depends on the context of where the declarations occur.
Outside of a function parameter definition, the declaration
T a[]; declares a as an unknown-sized array of T; the array type is incomplete, so unless a is defined elsewhere (either in this translation unit or another translation unit that gets linked) then no storage is set aside for it (and you will probably get an "undefined reference" error if you attempt to link, although I think gcc's default behavior is to define the array with 1 element) . It cannot be used as an operand to the sizeof operator. It can be used as an operand of the & operator.
For example:
/** * module1.c */ extern char *a[]; /* non-defining declaration of a */ void foo() { size_t i = 0; for (i = 0; a[i] != NULL; i++) printf("a[%lu] = %s\n", (unsigned long) i, a[i++]); } module1.c uses a non-defining declaration of a to introduce the name so that it can be used in the function foo, but since no size is specified, no storage is set aside for it in this translation unit. Most importantly, the expression a is not a pointer type; it is an incomplete array type. It will be converted to a pointer type in the call to printf by the usual rules.
/** * module2.c */ char *a[] = {"foo", "bar", "bletch", "blurga", NULL}; /* defining declaration of a */ int main(void) { void foo(); foo(); return 0; } module2.c contains a defining declaration for a (the size of the array is computed from the number of elements in the initializer), which causes storage to be allocated for the array.
Style note: please don't ever write code like this.
In the context of a function parameter declaration, T a[] is synonymous with T *a; in both cases, a is a pointer type. This is only true in the context of a function parameter declaration.
1 Comment
T a[]; is called a tentative definition. It's not a gcc extension; the Standard behaviour is that if the type is not completed by the end of the translation unit, then it's as if a line is added to the end of the TU saying T a[1];.As Paul said in the comment above, it's syntactic sugar. Both char* and char[] are the same data type. In memory, they will both contain the address of a char.
The array/index notation is equivalent to the pointer notation, both in declaration and in access, but sometimes much more intuitive. If you are creating an array of char pointers, you may want to write it one way or another to clarify your intention.
Edit: didn't consider the case Jerry mentioned in the other answer. Take a look at that.
1 Comment
char *[] just decays to char ** in function declarations, since you can't pass an actual array.