What does "[*]" (star modifier) mean in C? [duplicate]

While trying to implement a C11 parser (for educational purposes), I found that in C11 (p. 470) but also in C99 (p. 412) (thanks Johannes!), the direct declarator is defined as:

(6.7.6) direct-declarator:  
    direct-declarator [ type-qualifier-list? * ]

At first, I thought this was an error in the grammar (the type list shouldn't be optional). However, when I tried this out in my reference compiler (clang), I got an rather unexpected error:

int array[*] = { 1, 2, 3 };
// error: star modifier used outside of function prototype

So apparently, (in clang) this is called the star modifier.

I quickly learned that they can only be used in function signatures:

void foobar(int array[*])

However, they can only be used in the declaration. Trying to use it in a function definition results in an error as well:

void foobar(int array[*]) {
    // variable length array must be bound in function definition
}

So as far as I can tell, the intended behaviour is to use [*] in the function declaration and then use a fixed number in the function definition.

// public header
void foobar(int array[*]);

// private implementation
void foobar(int array[5]) {

}

However, I have never seen it and I don't quite understand the purpose of it either.

  1. What is its purpose, why was it added?
  2. What's the difference with int[]?
  3. What's the difference with int *?

Solution 1:

What is its purpose, why was it added?

Purpose is seen when a variable length two dimentional array is used as a function parameter. The function

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

can be prototyped as any of the following

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

In case of two dimensional array, when used as function parameter, size of the second dimension can't be omitted. If the name of first variables in function prototype is omitted then it wouldn't be possible to specify the length (second dimension) of the array. The * gives the clue that the length of the array will be determined by the second parameter.

What's the difference with int[]?
What's the difference with int *?

In case of 1D array, for the function definition

int bar(int n, int a[n]} {...}  

any of the following prototype is valid

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

In this case neither * nor n is necessary as compiler will treat both of int [*] and int [n] as int *. So, with one dimensional array you can't see much difference.


NOTE: When using variable length array as a function parameter, order of parameter is important. Order of parameters for first four prototypes of bar can be switched, but in latter two first parameter must not be the array itself.

int bar (int a[n], int n);  //Wrong. Compiler has not yet seen 'n'.
  

Solution 2:

The C rationale document for C99 says

A function prototype can have parameters that have variable length array types (§6.7.5.2) using a special syntax as in

int minimum(int, int [*][*]);

This is consistent with other C prototypes where the name of the parameter need not be specified.


What's the difference with int[]

What's the difference with int *.

I think it's simply that those types in a function prototype means "pointer", while a [*] in a non-top position (int[*] still equals int[] I think, in a function prototype) actually is valid and means array

// not recommended though: it is now unclear what the parameters
// mean to human callers!
void f(int, int [][*]);

void f(int n, int x[][n]) {
    x[1][0] = 1;
}

int main() {
   int a[2][1];
   f(1, a);
   printf("%d\n", a[1][0]);
}

As for the purpose, when indexing the array in the function definition, the compiler needs to know how many integers of the next index to skip when giving the first index (x[i] skips i * n integers in f above). But this information is not needed in the non-defining prototype declaration, hence it can be left out and replaced by *.