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

This question already has answers here:
Why use an asterisk "[*]" instead of an integer for a VLA array parameter of a function?
(2 answers)
Closed 6 years ago.
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.
What is its purpose, why was it added?
What's the difference with int[]?
What's the difference with int *?

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'.

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 *.

Related

Incompatible pointer array 2D

Im new with C and i have to do a program for school.
I have 3 classes:
lab11.c(main)
procs.c
procs.h
Im getting this error everytime:
error: conflicting types for 'transposarMatriu'|
\procs.h|171|note: previous declaration of 'transposarMatriu' was here|
My code (main):
char matriu_ori[T_DIM_MAX][T_DIM_MAX];
char matriu_dst[T_DIM_MAX][T_DIM_MAX]
transposarMatriu(matriu_ori, *matriu_dst, mida, mida);
Procs.h
extern void transposarMatriu(char matriu_ori[][T_DIM_MAX], char matriu_dst[][T_DIM_MAX], int nfiles, int ncols);
Procs.c
void transposarMatriu(char matriu_ori[][T_DIM_MAX], char *matriu_dst[][T_DIM_MAX], int nfiles, int ncols) {
int c,d;
for (c = 0; c < nfiles; c++) {
for( d = 0 ; d < ncols ; d++ ) {
*matriu_dst[d][c] = matriu_ori[c][d];
}
}
}
The problem comes from the discrepancy between the function definition in procs.c and its declaration in procs.h.
Procs.h
extern void transposarMatriu(char matriu_ori[][T_DIM_MAX], char matriu_dst[][T_DIM_MAX], int nfiles, int ncols);
The function signature must be identical, in this case is not, as you can see, in procs.c the second argument is of type char*, instead of char as in procs.h.
Procs.c
void transposarMatriu(char matriu_ori[][T_DIM_MAX], char *matriu_dst[][T_DIM_MAX], int nfiles, int ncols) {
...
TL;DR: remove the asterisk in lab11.c and procs.c: transposarMatriu([...] *matriu_dst [...])
The function definition for transposarMatriu in procs.c declares matriu_dst to be of type array of arrays of pointers to char (*matriu_dst[][]) (see C Right-Left Rule if you want to learn to decipher C declarations). Probably not what you intended and it's also a mismatch from the function declaration in procs.h.
I assume you intended matriu_dst to be "modifiable" like in call-by-reference, but there's no need to. Arrays are passed to functions by address, so they're "modifiable" by default.
By the same reasoning, there's no need to dereference matriu_dst in main.c (apply the * operator). In fact, doing so means you're passing the first element of the array to the function (an array of chars).

Function Prototypes with multi-dimensional arrays as a parameter

Brand new to C, I come from a Java background.
I am having an issue where I can't compile because the compiler wants to know at compile time the size of my array. For example, I want to print my array to the console. It won't allow me to declare a function prototype as such:
void printRoom(char[][], int, int); //not allowed
What am I supposed to do instead? Is there not a way around this? Online resources that I have found seem to indicate that I MUST know the dimensions if I want to use a function prototype. It appears that it also requires that the function header have the size of the array as well.
void printRoom(char room[][], int height, int width){ // not allowed, missing array bounds
Would a valid solution to this problem just be to say the array is of size 1000*1000 (the maximum array size I can expect)? That seems sloppy to me but I'm pretty sure it would work as long as I stayed within the bounds of what the array size is actually supposed to be.
I am NOT interested in pointers and malloc at this time.
If the compiler supports variable length arrays then you can declare the function the following way
void printRoom( int, int, char[*][*]);
or just
void printRoom( int, int, char[][*]);
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
void printRoom( int, int, char[*][*]);
void printRoom( int m, int n, char a[m][n] )
{
for ( int i = 0; i < m; i++ )
{
printf( "%3s ", a[i] );
putchar( ' ');
}
printf( "\n" );
}
int main(void)
{
const int M = 2;
const int N = 10;
char a[M][N];
strcpy( a[0], "Hello" ),
strcpy( a[1], "World" );
printRoom( M, N, a );
return 0;
}
Its output is
Hello World
If the compiler does not support VLAs then the number of columns has to be a constant. For example
#define N 100
//...
void printRoom(char[][N], int, int);
The C standard says in §6.7.6.3 Function declarators (including prototypes):
¶12 If the function declarator is not part of a definition of that function, parameters may have
incomplete type and may use the [*] notation in their sequences of declarator specifiers
to specify variable length array types.
That's standard-speak for: You can write a function declaration, but not the function definition, using a notation such as:
void printRoom(int, int, char [*][*]);
where the arguments are re-ordered in the declaration because in the function definition, you must specify the sizes before you specify the array:
void printRoom(int height, int width, char room[height][width])
{
…
}
You could reverse the order of height and width in the function, but normally in C you'd name the dimensions in the order they're used.
You're not obliged to specify the size of the leading dimension; all the others must have a size associated with them. That means you could write:
void printRoom(int, int, char [][*]);
and:
void printRoom(int height, int width, char room[][width])
{
…
}
The function still needs to know the height so that it can process the array accurately, but it doesn't have to be part of the array definition.
§6.9.1 Function definitions
¶10 On entry to the function, the size expressions of each variably modified parameter are
evaluated and the value of each argument expression is converted to the type of the
corresponding parameter as if by assignment. (Array expressions and function
designators as arguments were converted to pointers before the call.)
Your room is a variably-modified parameter.

Passing 2-D array to function in c [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Passing multidimensional arrays as function arguments in C
In C,
if I want a function to receive a 2-D array, can I use * notation for the function parameter
int (int my2dary[][10]); //This is what I do not want.
Yes, you pass a pointer to an array of int
int func(int (*my2dary)[10]);
and you call it
int a[5][10];
func(a);
Although, func doesn't know how many elements are in my2dary, so you must give a number too
int func(int n, int (*my2dary)[10]);
and call
int a[5][10];
func(5, a);
See How to interpret complex C/C++ declarations or The ``Clockwise/Spiral Rule''.
If your problem is that you don’t know the size of the array at compile time, you may want:
int func(int *array, int size)
{
int n,m;
...
array[m*size+n]; /* = array[m][n] if in the caller: int array[x][size]; */
}
Optionally (and very probably you need) you can pass a second size argument (x) to be able to test array boundary

Static hint in variable length arrays

I'm a bit confused at the difference here, in C99:
int myfunc (int array[n], int n) { ... }
will not compile. As far as I know you must always put the reference to the array size first, so it has to be written:
int myfunc (int n, int array[n]) { ... }
But if you supply the static keyword, this works absolutely fine:
int myfunc (int array[static 1], int n) { ... }
This order if far preferable to me, as I'm used to having arrays come first in a function call, but why is this possible?
Edit: Realising that the third example isn't actually a VLA helps...
For reference, this was the piece of code I was looking at that led to the question:
int sum_array(int n, int m, int a[n][m])
{
int i, j, sum = 0;
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
sum += a[i][j];
return sum;
}
The reason why
int myfunc (int n, int array[n]) { ... }
is valid and
int myfunc (int array[n], int n) { ... }
is not is due to the lexical scoping rules of C. An identifier cannot be used before it has been introduced in the scope. There are a few exceptions to this rule but this one is not one of them.
EDIT: here is the relevant paragraph of the C Standard:
(C99, 6.2.1p7) "Any other identifier has scope that begins just after the completion of its declarator."
This rule also applies to parameters declaration at function prototype scope.
The reason for error has already been explained to you: you have to declare n before you can use it in other declarations.
However, it is worth noting that none of these declarations actually declare variable length arrays, as you seem to believe.
It is true that syntax with [n] was first allowed in C99 and that it is formally a VLA declaration, but nevertheless in the given context all of these declarations declare array as a parameter of int * type, just like it has always been in C89/90. The [n] part is not a hint of any kind. The fact that you can use [n] in this declaration is indeed a side-effect of VLA support, but this is where any relationship with VLA ends. That [n] is simply ignored.
A "hint" declaration requires keyword static inside the []. So, your declaration with [static 1] is equivalent to classic int array[1] declaration (meaning that 1 is ignored and the parameter has type int *) except that it gives the compiler a hint that at least 1 element must exist at the memory location pointed by array.
It's because arrays must be declared with a constant value so you cannot create an array using a variable size and therefore cannot pass an array with a variable size. Also if it is just a single-dimension array you don't need to pass a value in at all, that is the point of passing in the second parameter to tell you the length of your array.
To get this to work properly just write the function header like this:
int myfunc (int myArray[], int n) {...}
The order shouldn't matter, but you cannot have the size of an array you are passing be variable it must be a constant value.
If you are using GCC and are willing to use some of their extensions, you can accomplish what you wish right here:
int myFunc (int len; /* notice the semicolon!! */ int data[len], int len)
{
}
The documentation for this extension (Variable Length Arrays) is here.
Please note that this extension is NOT available in clang for some reason, I'm not quite sure why, though.
EDIT: Derp, scope, of course.
My question is; why do you need to do it at all? You're really getting a pointer anyway (you can't pass arrays to a function in C, they degrade to a pointer, regardless of the function's signature). It helps to let the caller know the expected size of the input, but beyond that it is useless. Since they are already passing the size, just use...
int myfunc(int arr[], size_t size) {
// ...
}
Or
int myfunc(int *arr, size_t size) {
// ...
}

C Header file error: expected identifier or ‘(’ before ‘[’ token

I'm a complete c newb. I'm trying to define a few functions in a header file and then implement them in a separate file. But when I try running gcc runtime.c I get the following error:
In file included from runtime.c:1:
runtime.h:7: error: expected identifier or ‘(’ before ‘[’ token
Here's the contents of runtime.h:
#ifndef HEADER
#define HEADER
/*given two arrays of ints, add them
*/
int[] * _addInts(int[] *x, int[] *y);
#endif
What's the error? I tried browsing header files but they started adding things like "extern" and "intern" and crazy ifdef's. Thanks for your help, Kevin
You should just pass pointers (since if you pass arrays to a function, what;'s really passed is a pointer anyway). Also, you can't return an array - again, just return a pointer:
int* _addInts(int *x, int *y); // equivalent to: int* _addInts(int x[], int y[]);
You'll also have to arrange for the number of elements to be passed in somehow. Something like the following might work for you:
int* _addInts(int *x, int *y, size_t count);
Also - do not fall into the trap of trying to use sizeof on array parameters, since they're really pointers in C:
int* _addInts(int x[], int y[])
{
// the following will always print the size of a pointer (probably
// 4 or 8):
printf( "sizeof x: %u, sizeof y: %u\n", sizeof(x), sizeof(y));
}
That's one reason why I'd prefer having the parameters be declared as pointers rather than arrays - because they really will be pointers.
See Is there a standard function in C that would return the length of an array? for a macro that will return the number of elements in an array for actual arrays and will cause a compiler error (on most compilers) much of the time when you try to use it on pointers.
If your compiler is GCC, you can use Linux's trick: Equivalents to MSVC's _countof in other compilers?
Get rid of each "[]"
As an array is a pointer, you only need to pass the pointers, like so:
int* _addInts(int* x, int* y);
EDIT: Also pass the size.
Use:
int* addInts(int* x, int* y, int size);
You have the [] in the wrong locations. The syntax for declaring arrays in "C" has the [] coming after the item you want to be an array, not between the type declaration and the item (like Java and C# use). I am not sure what you are trying to declare, but here are some options:
If you are trying to declare that you will be using a function named "_addInts()" that returns a pointer to an int, and takes as its parameters two separate arrays of pointers to integers named x and y --
int * _addInts(int *x[], int *y[]);
If you want to declare a function that returns an array of integer pointers:
int * _addInts(int *x[], int *y[])[];
If _addInts is a function that takes two arrays of int (as opposed to arrays of int *):
int * _addInts(int x[], int y[]);
Note that the following are (nearly) equivalent, and can be used interchangeably in declarations such as you are attempting.
int *x
and
int x[]
as are:
int **x
and
int *x[]

Resources