2

I know that when used as function parameter char* a[] is equivalent to char a[][].

When used as function parameter char* a[] is equivalent to char** a. Also known as Array to pointer conversion to some.

However when used in block scope they are not the same, and I'm confused as when I should prefer one over the other, or if I should skip char a[][], as I usually tend to see char* a[] in other people's code.

One argument against char a[][] is obviously that you have to give a fixed size for the C-strings it will contain, but does that affect performance in any way?

Should I prefer this:

char* a[] = {"hello", "world"};

Or this:

char a[][10] = {"hello", "world"};
hgiesel
  • 5,430
  • 2
  • 29
  • 56
  • 1
    Beware of any sentence that starts with "I know that"... – Kerrek SB Apr 15 '16 at 09:15
  • @KerrekSB What do you mean? – hgiesel Apr 15 '16 at 09:16
  • 4
    Your leading assertion is false. `char a[][]` is never allowed. What is equivalent as function parameter types is `char *a[]` and `char** a`. – Kerrek SB Apr 15 '16 at 09:17
  • 3
    The second one (`char a[][]`) is a (not allowed) array with incomplete element type – David Ranieri Apr 15 '16 at 09:19
  • 1
    The upshot here is that for every claim that you make following the words "I know that", or "it is widely known that", or "as we all know", you *really* need to have an existing, compiling program in front of you that verifies the claim before posting. – Kerrek SB Apr 15 '16 at 09:23
  • @KerrekSB yes you're right, I'll confess that was negligent – hgiesel Apr 15 '16 at 09:25
  • 2
    That's not a conversion, it is a type adjustment. – juanchopanza Apr 15 '16 at 09:31
  • Beware of cppreference.com, there's a lot of incorrect statements all over that site. The correct term is most definitely not conversion. Formally it would perhaps be called "array adjustment", informally it is called "array decay". – Lundin Apr 15 '16 at 09:33
  • Possible duplicate of [Should I use char\*\* argv or char\* argv\[\] in C?](http://stackoverflow.com/questions/779910/should-i-use-char-argv-or-char-argv-in-c) – Julien Lopez Apr 15 '16 at 09:38
  • @Lundin - is it still called "array decay" when used in a parameter declaration? I've only used that phrase when referring to an array decaying to a pointer in an expression. – Ian Abbott Apr 15 '16 at 09:50
  • `Should I prefer this:` This happens because you don't really know what a pointer and an Array is. same for Array of Pointers and Array of Arrays. Read a book. – Michi Apr 15 '16 at 09:50
  • The title is about `char* a[] vs char** a` and the Question is about `char* a[] = {"hello", "world"};` vs `char a[][10] = {"hello", "world"};` – Michi Apr 15 '16 at 09:52
  • 1
    @IanAbbott No, it isn't. See the comments to the answer. – juanchopanza Apr 15 '16 at 09:52
  • I really messed up on the title of this question, I'm very sorry. My question asked something different than the title. – hgiesel Apr 15 '16 at 09:58
  • 1
    @hgiesel Don't complicate things with array of array and array of pointers. Just stick to the Array and a Pointer first. The Pointer points to that literal string and you can not modify that string, because is hard coded in read only. But When you use an Array in fact that literal string will be copied inside and you can modify that string any time. Hope helps. I removed my down vote and I gave you a +1 – Michi Apr 15 '16 at 10:01

2 Answers2

8

The key to understanding the seemingly strange syntax cases of function parameters is to understand array decay. This is all about one rule in C that says, whenever you pass an array as parameter to a function, it decays into a pointer to the first element of that array (*).

So when you write something like

void func (int a[5]);

then at compile-time, the array gets replaced with a pointer to the first element, making the above equal to:

void func (int* a);

This rule of pointer decay applies recursively to multi-dimensional arrays. So if you pass a multi-dimensional array to a function:

void func (int a[5][3]);

it still decays to a pointer to the first element. Now as it happens, a 2D array is actually an array of arrays. The first element is therefore a one-dimensional array, with size 3 in this example. You get an array pointer to that array, the type int(*)[3]. Making the above equivalent to

void func (int (*a)[3]);

And this is actually the reason why we can omit the left-most dimension of the array parameter, and only that dimension. Upon doing so we make an array of incomplete type, which you normally wouldn't be able to use: for example you can't write code like int array[]; inside a function's body. But in the parameter case, it doesn't matter that the left-most dimension isn't specified, because that dimension will "decay away" anyway.


(*) Source, C11 6.7.6.3/7:

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, ...

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 3
    Isn't it *arguments* that decay? I'm pretty sure parameters are type adjusted. – juanchopanza Apr 15 '16 at 09:32
  • 1
    @juanchopanza Umm... argument and parameter are synonyms? – Lundin Apr 15 '16 at 09:35
  • The statement about incomplete types is a little vague. There *are* uses for incomplete types, e.g. you can use them in declarations: For example, `extern int a[];` is fine inside a function. – Kerrek SB Apr 15 '16 at 09:35
  • 5
    @Lundin: No. Parameters are part of a function, arguments are part of a function *call*. In other words, arguments are values, and parameters are part of a declaration. – Kerrek SB Apr 15 '16 at 09:35
  • Does that also work recursively? Does `int a[2][3][4]` decay to `int** a[4]` when used as a function argument? – hgiesel Apr 15 '16 at 09:36
  • 3
    @KerrekSB Yeah but you can't write `int array[];` exactly as I wrote it. And given your definition of parameter vs argument, it is the parameter that "decays", see the quoted C standard. – Lundin Apr 15 '16 at 09:37
  • 2
    @hgiesel No that's the catch, the decay only occurs once. Which is why you end up with an array pointer. – Lundin Apr 15 '16 at 09:38
  • 4
    @Lundin; Quoted text says about adjustment of parameter. – haccks Apr 15 '16 at 09:39
  • 4
    @Lundin The quote says the parameter "shall be adjusted", not anything about decaying. – juanchopanza Apr 15 '16 at 09:39
  • That's because there is no formal term called "array decay". Formally it would be "array adjustment" or some such. However, all programmers and literature call this "decay", so that's why I used that term. – Lundin Apr 15 '16 at 09:41
  • The C11 standard is clear about arguments and parameters. => `3.3` and `3.16` – Michi Apr 15 '16 at 09:43
  • 3
    The point is that decay is something that happens to *expressions*, not to types. When you say the expression `a`, then it decays from "array of int" to "pointer to int". The parameter type adjustment for function parameters is designed to mirror that so as to make function declaration and function call match stylistically, but nonetheless types don't decay. – Kerrek SB Apr 15 '16 at 09:43
  • ("Array decay" also refers to where an array name is used as part of an expression, although formally it is called a lvalue conversion then, see 6.3.2.1) – Lundin Apr 15 '16 at 09:43
  • 3
    Backing up @KerrekSB last comment: ***A reference to an object of type array-of-T which appears in an expression decays (with three exceptions) into a pointer to its first element**; the type of the resultant pointer is pointer-to-T.* ([C-faq](http://c-faq.com/aryptr/aryptrequiv.html)). – haccks Apr 15 '16 at 09:44
  • There is no formal definition of array decay, because it is not a formal term, simple as that. See [What is array decaying?](http://stackoverflow.com/questions/1461432/what-is-array-decaying). Plenty of programmers use the term for array parameters, whether you like it or not. – Lundin Apr 15 '16 at 10:40
  • There are formal definitions of parameters, arguments, types and expressions though. You seem to be ignoring those. – juanchopanza Apr 15 '16 at 13:45
  • @juanchopanza For very good reasons! I'm trying to teach beginners here, they don't give a **** about "the formal definition of type adjustment" or some other C standard gibberish. That being said, I see nothing in my answer that conflicts with the formal terms of the C standard either. – Lundin Apr 15 '16 at 13:54
2

Adjustment of array type to pointer type works only when it is declared as a parameter of a function.
As a function parameter char* a[] will be adjusted to char** a and char a[][10] to char (*a)[10]. Otherwise char* a[] declares a as an array of pointers to char while char a[][10] declares a an array of arrays of char.

Preference of

char* a[] = {"hello", "world"};  

over this

char a[][10] = {"hello", "world"};  

make sense when you want to save some bytes of memory. In latter case for each of a[0] and a[1] 10 bytes are allocated. Note that in case of char* a[], strings pointed by the elements of a are immutable.

If you want contiguous memory allocation then go with char a[][10].

haccks
  • 104,019
  • 25
  • 176
  • 264
  • The OPs Question is different from the Title. – Michi Apr 15 '16 at 09:54
  • Any way there is nothing really to discuss about `Array of Arrays` (or multi dim) vs `Array of Pointers`, which definitely are different things. – Michi Apr 15 '16 at 09:55
  • @Michi; Yeah. that's what I addressed in my answer. – haccks Apr 15 '16 at 09:56
  • I know:)) was a comment for the OP here . – Michi Apr 15 '16 at 09:56
  • It is different, but I'm never certain when to use which. For example I have a long contiguous string I want to parse into several seperate words. Take the `PATH` environment variable for example. – hgiesel Apr 15 '16 at 10:02
  • @Michi Yes I read it after I posted that comment. I think I got a much needed insight, thank you. – hgiesel Apr 15 '16 at 10:05
  • 1
    @hgiesel Please read again my comment under your Question. If that Array of Pointers has to be modified, then `malloc` call will be needed. So the Question is now `stack vs Heap` :D ...Question about =>> `char a[][] ` vs `char *a[]` vs `char **a` is non sens when you don't know the main difference between a Pointer and an Array – Michi Apr 15 '16 at 10:06
  • Yeah but I think I have an idea of that answer already, but I wasn't aware that pointers to char correlated to read only memory. – hgiesel Apr 15 '16 at 10:11
  • 1
    @hgiesel I was sure about that. Please read more about difference about Pointers and Arrays and you will have no problems . – Michi Apr 15 '16 at 10:13