36

When using variable-Length Array as parameter in function

int sum(int n, int a[n]);

it is easy to understand first parameter(n) specifies the length of the second parameter(a). But encountered with another prototype used for VLAs as parameter

int sum(int n, int a[*]);

is really difficult to understand why * is used instead of n inside []?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
haccks
  • 104,019
  • 25
  • 176
  • 264
  • Did you checked `int sum(int n, int a[]);` – Midhun MP Jun 28 '13 at 18:53
  • @aaronman surprised me too, but it did compile. – Kevin Jun 28 '13 at 18:53
  • 2
    y@aaronman; yes. its c99 feature. – haccks Jun 28 '13 at 18:54
  • 2
    So... int a\[*\] is an array of pointers or a variable-length array? It's not simple to understand just seeing code...? I mean... is "int a\[*\]" the same as "int *a\[\]" or just "int a\[\]"? – Alejandro Iván Jun 28 '13 at 18:54
  • @MidhunMP; yes it also worked. – haccks Jun 28 '13 at 18:54
  • 4
    [Related/Duplicate question](http://stackoverflow.com/questions/7225358/variable-length-arrays-in-c). See answer by Jens Gustedt. – ajp15243 Jun 28 '13 at 19:03
  • @ajp15243; Its different. – haccks Jun 28 '13 at 19:07
  • For extra fun with VLA syntax, predict what the following will print: `#include `, `void foo(int a[printf("Hello\n")][printf("World\n")]) {}`, `int main(void) { foo(0); }`. Emphasis on the **predict**, no compiling. – Eric Postpischil Jun 28 '13 at 19:09
  • 2
    @haccks If you read the end of his answer, he essentially explains what AndreyT explains below, which is that `[*]` is useful if you don't name your preceeding length parameters in your function prototypes. – ajp15243 Jun 28 '13 at 19:11
  • @EricPostpischil: the abuse is strong with this one. – user7116 Jun 28 '13 at 19:11
  • @EricPostpischil To my surprise, the gcc-compiled programme (gcc-4.7.2) printed out first "World\n", and then "Hello\n". The clang-compiled programme, only "World\n". Is gcc's behaviour allowed? – Daniel Fischer Jun 28 '13 at 19:46
  • @DanielFischer: The array parameter should be adjusted to be a pointer (C 2011 N1570 6.7.6.3 7), so the expression inside the first `[]` must vanish. Right? – Eric Postpischil Jun 28 '13 at 19:58
  • @EricPostpischil That's what I think. But my legalese is not so strong, I thought I'd confirm. – Daniel Fischer Jun 28 '13 at 20:00

2 Answers2

55

The [*] syntax is intended to be used when declaring function prototypes. The key detail here is that in function prototypes you are not required to name your parameters, you just have to specify the type of each parameter.

In your example, if you leave the first parameter unnamed, then obviously you won't be able to use n in your second (array) parameter declaration. Yet, in many cases you have to tell the compiler that some parameter is a VLA. This is when the [*] syntax comes to the rescue.

In your case, if you omit the parameter names, the prototype might look as

int sum(int, int [*]);

However, it is important to note that in your specific example this syntax is legal, but it is not exactly necessary. Just like with non-VLA arrays, an int [n] parameter is still equivalent to int * parameter (even for non-constant n). This means that you can simply prototype your function as

int sum(int, int []);

or as

int sum(int, int *);

and the prototype will still serve its purpose, i.e. it will properly match the function definition. In other words, VLA properties of a parameter declared as an 1D array are completely inconsequential and the [*] feature is not really needed with such VLA arrays.

The [*] becomes important in situations when the "variable arrayness" of the type is not lost, as would be the case with 2D VLA (or a pointer to a VLA). E.g. a function defined as

int sum2d(int n, int m, int a[n][m])
{
  ...
}

might be prototyped as any of the following

int sum2d(int, int, int a[*][*]);
int sum2d(int n, int, int a[n][*]);
int sum2d(int, int m, int a[*][m]);
int sum2d(int n, int m, int a[n][m]);

All of the above prototypes properly match the function definition.

Of course, if you have the habit of always naming all parameters in function prototypes, then you'll never need this [*] syntax, since you will be able to use the last prototype in the above list.

P.S. Again, as is the case with all arrays in parameter declarations, the first [] is always inconsequential and always decays to a pointer, meaning that the following are also valid equivalent prototype declarations for the above sum2d

    int sum2d(int, int, int a[][*]);
    int sum2d(int, int, int (*a)[*]);
    int sum2d(int n, int m, int (*a)[m]);

It is the second [] that really matters and has to be declared as "variable length".

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 3
    Sometimes you cannot easily name the parameters in prototypes. When writing a library header, you want to avoid names that might collide with names the users of your library are using in preprocessor macros. So you must omit names or step into the reserved name space (in cooperation with the implementation) or have the library reserve part of the name space (as with a prefix such as “MyLibrary_”). The latter two can get ugly. – Eric Postpischil Jun 28 '13 at 19:21
  • @AndreyT; Please elobrate your statement `The [*] becomes important in situations when the "variable arrayness" of the type is not lost, as would be the case with 2D VLA. ` in your answer. – haccks Jun 28 '13 at 19:34
  • @EricPostpischil; It bounds over head :( – haccks Jun 28 '13 at 19:35
  • 2
    @haccks: I'm referring to the fact that the first `[]` in array parameter declaration in always lost. The parameter decays to a pointer. That applies to all array parameter declarations, regardless of whether they are VLA or not. (I stated this in the answer). The only way to "inject" permanent non-disappearing arrayness" into a type in C is to make it a pointer to an array, like `int (*p)[5]` or `int (*p)[n]`. In parameter declarations this is equivalent to 2D array declaration. – AnT stands with Russia Jun 28 '13 at 19:44
  • @haccks In the case of a variable array, like `int arr[n][m]`, the compiler needs to know the size `m` because in the case of an array access like `arr[2][3]`, it has to internally convert it to something like `*(arr + 2 * m + 3)` (Notice the `m` in the expression). In ANSI C, your only option would be to pass `int *arr` and do the `*(arr + 1 * m + 1)` part manually, but in C99, you can have the compiler handle it for you, therefore the new syntax. The first size (in this case `n`) is never needed, since it's element are always right next to each-other (`sizeof int` bytes in this case). – yyny Jul 19 '20 at 13:06
4

When you put the star in an actual function it gives this error test.c:3: error: ‘[*]’ not allowed in other than function prototype scope. After some research this is actually a way to declare a VLA in a function prototype, with the * in place of the variable name. VLA.
The issue at hand here is that if you put a variable instead of the star for a VLA, it will tell you that it is undeclared, so the star is a way that c99 built in to get around that.

aaronman
  • 18,343
  • 7
  • 63
  • 78
  • @AlejandroIván Nah, that's a different syntax. –  Jun 28 '13 at 18:58
  • 1
    Weird... seems like C99 allows variable-length arrays declared this way. – Alejandro Iván Jun 28 '13 at 18:59
  • @AlejandroIván look at new post – aaronman Jun 28 '13 at 19:03
  • @H2CO3; Which syntax is this? Its too confusing man. If you know please give an answer. – haccks Jun 28 '13 at 19:04
  • 2
    @haccks Array of `int`s: `int arr[N];` array of pointers-to-int: `int *arr[N];` - pointer-to-array-of-`int`s: `int (*ptr)[N]`, variable length array: `int arr[];` - VLA in function argument list: the same or `int arg[*];` –  Jun 28 '13 at 19:32