Prototype for variable-length arrays - c

I am trying to write a function that takes an array of an variable size in c.
void sort(int s, int e, int arr[*]){
...
}
It says that for variable length arrays, it needs to be bounded in the function declaration. What does that mean? I am using xcode 4.0, with the LLVM compiler 2.0.
Thanks for the help.

As I see that no one answers the real question, here I give mine.
In C99 you have variable length arrays (VLA) that are declare with a length that is evaluated at run time, and not only at compile time as for previous versions of C. But passing arrays to functions is a bit tricky.
A one dimensional array is always just passed as a pointer so
void sort(size_t n, int arr[n]) {
}
is equivalent to
void sort(size_t n, int *arr){
}
Higher dimensions are well passed through to the function
void toto(size_t n, size_t m, int arr[n][m]){
}
is equivalent to
void toto(size_t n, size_t m, int (*arr)[m]){
}
With such a definition in the inside of such a function you can access the elements with expressions as arr[i][j] and the compiler knows how to compute the correct element.
Now comes the syntax that you discovered which is only useful for prototypes that is places where you forward-declare the interface of the function
void toto(size_t, size_t, int arr[*][*]);
so here you may replace the array dimension by * as placeholders. But this is only usefull when you don't have the names of the dimensions at hand, and it is much clearer to use exactly the same version as for the definition.
void toto(size_t n, size_t m, int arr[n][m]);
In general for a consistent use of that it is just important that you have the dimensions first in the the parameter list. Otherwise they would not be known when the compiler parses the declaration of arr.

If you're not using the C99 variable length arrays (it appears you are, so see below), the usual solution is to pass in a pointer to the first element, along with any indexes you want to use for accessing the elements.
Here's a piece of code that prints out a range of an array, similar to what you're trying to do with your sort.
#include <stdio.h>
static void fn (int *arr, size_t start, size_t end) {
size_t idx;
for (idx = start; idx <= end; idx++) {
printf ("%d ", arr[idx]);
}
putchar ('\n');
}
int main (void) {
int my_array[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
fn (my_array, 4, 6);
return 0;
}
This outputs elements four through six inclusive (zero-based), giving:
5 4 3
A couple of points to note.
Using my_array in that function call to fn automatically "decays" the array into a pointer to its first element. This actually happens under most (not all) circumstances when you use arrays, so you don't have to explicitly state &(my_array[0]).
C already has a very good sort function built in to the standard library, called qsort. In many cases, that's what you should be using (unless either you have a specific algorithm you want to use for sorting, or you're doing a homework/self-education exercise).
If you are using real VLAs, you should be aware that the [*] construct is only valid in the function prototype, not in an actual definition of the function.
So, while:
void xyzzy(int, int[*]);
is valid, the following is not:
void xyzzy(int sz, int plugh[*]) { doSomething(); }
That's because, while you don't need the size parameter in the prototype, you do very much need it in the definition. And, since you have it, you should just use it:
void xyzzy(int sz, int plugh[sz]) { doSomething(); }
The gcc compiler actually has a reasonably clear error message for this, far better than the "needs to be bounded in the function declaration" one you saw:
error: ‘[*]’ not allowed in other than function prototype scope

What you want to do it make your argument an int *; pass in the length of the array (which the caller presumably knows, but this routine does not) as a separate argument. You can pass an array as such an argument.

The usage of * inside of array brackets for variable-length arrays is limited to prototypes, and serves merely as a placeholder. When the function is later defined, the array's size should be stored in a variable available at either file scope or as one of the parameters. Here's a simple example:
void foo(int, int[*]);
/* asterisk is placeholder */
void foo(int size, int array[size]) {
/* note size of array is specified now */
}

Related

Passing array as a parameter with its size inside brackets

Is defining a function this way legal or helpful in any way?
void f(int arr[ARR_SIZE])
It's legal (assuming that ARR_SIZE is a positive integral type), and is perhaps a useful annotation, although confusing as it seems to make a false promise. On balance I wouldn't use it.
It doesn't mean that arr is an array of that size: arr is still an int* (due to pointer decay) and all size information is lost.
Far better then to write
void f(int* arr, size_t n)
with f(arr, ARR_SIZE) at the calling site, or f(arr, sizeof(arr)/sizeof(arr[0])) if the non-decayed type of arr is available.
I see one place where passing the (minimum) size can be useful:
void bar(int myArray[static 10]){...}
This tells the compiler that it should assume that the array passed to bar has at least 10 elements and can emit a warning if it is not the case:
int a[9];
bar(a);
returns:
warning: array argument is too small; contains 9 elements, callee requires at least 10 [-Warray-bounds]
bar(a);
^ ~
More info
Legal - yes. Helpful? Not really. Look at this:
#define ARR_SIZE 4
int arr[ARR_SIZE], arr2[345];
f(arr); //works
f(arr2); //also works, compiler doesn't care about what size you specified in the []
This means that you still need to pass the size as a separate parameter:
void f2(int arr[ARR_SIZE], int size);
You can then call this function like this:
f2(arr, ARR_SIZE); //works
f2(arr2, 345); //works
So, don't use this syntax. The recommended prototypes are:
int f(int arr[], int size);
int f(int* arr, int size);
arr in this function is a pointer, for bounds check better pass size of the array as another parameter.
int fun(int *arr, int siz_arr) //function definition
{
//.....
}
fun(arr,sizeof(arr)/sizeof(arr[0])); //function call for
In
void f(int arr[ARR_SIZE]);, ARR_SIZE is practically as good as a comment except the compiler will also verify that ARR_SIZE is either empty or a positive (>=0) integer constant.
Then it's 100% equivalent to void f(int *arr);.
C11 has void f(int arr[static ARR_SIZE]); where you can effectively require that the function only be passed pointers to the first element of arrays that have at least ARR_SIZE members (where ARR_SIZE must be a positive integer constant). E.g., void take_nonnull(int arr[static 1]); or void take_at_least2(int arr[static 2]);. Compilers may or may not issue diagnostics about subsequent calls to f that violate such a requirement (clang routinely does, gcc doesn't).
Yes, but ARR_SIZE must be defined at compile time, like this: #define ARR_SIZE 3
void f(int arr[ARR_SIZE]){}

Why use "[*]" instead of "[]" in function prototype?

Here is what is it written as rationale for adding the fancy * star syntax for declaring array types inside function prototypes - just for clarification before we get into the question:
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.
But I'm pretty confident that we can have the same effect by simply using only ordinary arrays with unspecified size like this (here re-writing the function example named minimum given above in the quote with what I believe exactly the same functionality (except for using size_t instead of int as first parameter which isn't that important in the case)):
#include <stdio.h>
int minimum(size_t, int (*)[]);
int (main)()
{
size_t sz;
scanf("%zu", &sz);
int vla[sz];
for(size_t i = 0; i < sz; ++i)
vla[i] = i;
minimum(sizeof(vla) / sizeof(*vla), &vla);
int a[] = { 5, 4, 3, 2, 1, 0 };
minimum(sizeof(a) / sizeof(*a), &a);
}
int minimum(size_t a, int (*b)[a])
{
for(size_t i = 0; i < sizeof(*b) / sizeof(**b); ++i)
printf("%d ", (*b)[i]);
return printf("\n");
}
Because I'm pretty sure that there was some place in the standard stating that 2 arrays are compatible only if their size are equal and no-matter if they are variable or not.
My point is also confirmed by the fact that the minimum definition wouldn't complain for "conflicting types" as it would if some of it's parameters had incompatible types (which I don't think is the case as both of those arrays have size which is unspecified at compile-time - I refer to the second parameter of minimum).
OK besides - can you point me 1 single use-case for [*] that can not be replaced using ordinary unspecified size arrays?
The above code compiles without any warnings using both clang and gcc. It also produces the expected output.
For anyone who doesn't know C (or anyone who thinks that he/she knows it) - function parameter of type array is implicitly transformed to "pointer to its elements type". So this:
int minimum(int,int [*][*]);
Gets adjusted to:
int minimum(int,int (*)[*]);
And then I'm arguing that it could be also written as:
int minimum(int,int (*)[]);
Without any consequences and with the same behavior as the 2 forms above. Thus making the [*] form obsolete.
OK besides - can you point me 1 single use-case for [*] that can not
be replaced using ordinary unspecified size arrays?
This would be the case, when you pass three-dimensional VLA array:
int minimum(size_t, int [*][*][*]);
This can be written as:
int minimum(size_t, int (*)[*][*]);
or even using an array of unspecified size:
int minimum(size_t, int (*)[][*]);
But you have no possibility to omit nor get around of the last indice, thus it has to stay as [*] in a such declaration.
[] can only be used as the leftmost "dimension specifier" of a multidimensional array, whereas [*] can be used anywhere.
In function parameter declarations, the leftmost (only!) [...] is adjusted to (*) anyway, so one could use (*) in that position at the expense of some clarity.
One can omit the dimension in the next-to-leftmost [...], leaving the empty brackets. This will leave the array element type incomplete. This is not a big deal, as one can complete it close to the point of use (e.g. in the function definition).
The next [...] needs a number or * inside which cannot be omitted. These declarations
int foo (int [*][*][*]);
int foo (int (*)[*][*]);
int foo (int (*)[ ][*]);
are all compatible, but there isn't one compatible with them that doesn't specify the third dimension as either * or a number. If the third dimension is indeed variable, * is the only option.
Thus, [*] is necessary at least for dimensions 3 and up.

Array lengths in array parameters

I am reading C Programming: A Modern Approach by K.N.King to learn the C programing language and the current chapter tells about functions, and also array parameters. It is explained that one can use constructs like these to express the length of array parameters:
1.
void myfunc(int a, int b, int[a], int[b], int[*]); /* prototype */
void myfunc(int a, int b, int n[a], int m[b], int c[a+b+other_func()]) {
... /* body */
}
2.
void myfunc(int[static 5]); /* prototype */
void myfunc(int a[static 5]) {
... /* body */
}
So the question(s) are:
a. Are the constructs in example 1 purely cosmetic or do they have an effect on the compiler?
b. Is the static modifier in this context only of cosmetic nature? what exactly does it mean and do?
c. Is it also possible to declare an array parameter like this; and is it as cosmetic as example 1 is?
void myfunc(int[4]);
void myfunc(int a[4]) { ... }
The innermost dimension of function array parameters is always rewritten to a pointer, so the values that you give there don't have much importance, unfortunately. This changes for multidimensional arrays: starting from the second dimension these are then used by the compiler to compute things like A[i][j].
The static in that context means that a caller has to provide at least as many elements. Most compilers ignore the value itself. Some recent compilers deduce from it that a null pointer is not allowed as an argument and warn you accordingly, if possible.
Also observe that the prototype may have * so clearly the value isn't important there. In case of multidimensional arrays the concrete value is the one computed with the expression for the definition.

Make an array accessible to any subunit included using #include "unit.c"?

How do I make sure a function from unit.c called from my main.c that needs an array declared in main.c functions properly?
Is there any way to declare variables globally across .c files? Is there a smart way to do it without using global variables?
Example:
#include <stdio.h>
#include "sub.c"
int main(void)
{
int matrix[5][5];
matrix[5][1] = 5;
Range();
}
Now for sub.c:
int Range()
{
printf("Your Range is: %i",Matrix[5][1])
}
Now the problem occuring is that now upon compiling there will be errors saying that
"In file included from main.c:
"sub.c:3:15: Error: Matrix not declared"
Or something along those lines.
So, several things:
Don't #include .c files (that is, source code); this is a bad habit to get into. For a small, simple program like this it's not a big deal, but as your programs become bigger and more complex, it will cause build and maintenance headaches. What you want to do instead is define a header file that only includes the declaration of your function, rather than the definition (body) of it, something like the following:/**
* sub.h - declaration for Range function
*/
#ifndef SUB_H // include guards; prevents this file from being processed
#define SUB_H // more than once for the same translation unit
/**
* Changing the type of Range to void since you aren't returning anything, and you
* aren't using the result of the function in your main function
*/
void Range( /* parameter declarations, which we'll get into below */ );
#endif
You'd then #include this file as #include <stdio.h>
#include "sub.h"
int main( void )
{
int Matrix[5][5];
Matrix[5][1] = 5; // this is an error; your array dimensions only go from 0 to 4
Range( /* parameters, including Matrix, which we'll get into below */ );
}
and compile your sub.c separately and link the resulting object files together.
Don't use global variables if you can help it; ideally, functions and their callers should communicate exclusively through parameters, return values, and exceptions (in languages which support exceptions, anyway, which C doesn't). You should pass Matrix as a parameter to your Range function, along with parameters for the array's size, and any additional information required by the function to do its job. Since you want to print the value of a single element, you should pass the row and column number of that element as well.
Now, here's where things get headachy - C's treatment of array expressions is a little non-intuitive. Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
If you pass the array as a parameter like so:Range(Matrix);
then type of the expression Matrix is "5-element array of 5-element array of int". Since this expression is not the operand of the sizeof or unary & operators, it is converted to an expression of type "pointer to 5-element array of int", and the value is the address of the first row of the array (which is the same as the address of the array itself). That means your Range function would be declared as something likevoid Range( int m[][5] )
orvoid Range( int (*m)[5] ) (the parentheses in the second declaration matter; without them, m would be declared as an array of pointers to int, which is not what we want).
In the context of a function parameter declaration, T a[] and T a[N] are both interpreted as T *a; that is, a is declared as a pointer to T, not an array of T.
Note that, since you passed the address of the array to the function, any changes the function makes to the array will be reflected in the caller; that is, if Range changes the value of m[4][0], you'll see that changed value in Matrix[4][0].
Since we only specify the number of columns in the declaration for m, we want to pass an additional parameter specifying the number of rows. C doesn't do any bounds checking on array accesses, meaning you can write something likex = m[20][1]; without getting a warning at compile time or guaranteeing a crash at runtime. So you need to do that bounds checking yourself, meaning you need to know how many rows the array has, in addition to the number of columns. You would pass a separate parameter for the number of rows:code>Range(Matrix, 5);
meaning your function declaration would look something likevoid Range(int m[][5], size_t rows);
One flaw with the above approach is that the number of columns in m is fixed at 5; this function won't be able to work on matrices of other sizes. If you're
working with a compiler that supports variable-length arrays1, you can use a variable to specify the array dimensions, rather than a compile-time constant. Since the variable needs to be declared before it can be used in an array declaration, you'd have to write the prototype asvoid Range( size_t rows, size_t cols, int m[][cols] );
and call the function asRange(5, 5, Matrix);
This will allow you to use the Range function on matrices of different sizes, such as:int M1[5][5];
int M2[9][9];
int M3[20][20];
...
Range(5, 5, M1);
Range(9, 9, M2);
Range(20, 20, M3);
Now, if you only intend for this function to work with 5x5 matrices, then hardcoding the dimension isn't a problem; it's only an issue if you intend to use this function for any sized matrix.
If you are using a compiler that doesn't support VLAs, you'll need a different approach. Instead of passing the array expression as a parameter, we pass a pointer to the first element of the array. We'll treat this pointer as though it were a 1-d array instead of a 2-d array, like so:void Range( int *m, size_t rows, size_t cols )
{
printf("Your range is: %d\n", m[4 * cols + 1]);
}
and you would call it asRange(&Matrix[0][0], 5, 5);
You're assuming the presence of an element at Matrix[5][1]; however, arrays in C are 0-origin, meaning that both dimensions are indexed from 0 to 4. So to access the 1st element of the 5th row, you'd refer to Matrix[4][0]. Matrix[5][1] is outside the bounds of your array.
This also brings up the question of whether you're ever going to want to check an element other than m[4][0]. If you want the function to access any arbitrary element of the array, you will want to pass the row and column number as separate parameters; this, combined with passing the array's dimensions as parameters, gives you a way to make sure you aren't trying to access an element outside of the array's bounds. So, your Range function would look something likevoid Range(int m[][5] size_t rows, size_t i, size_t j)
{
if ( i < rows && j < 5 )
printf("Your range is: %d\n", m[i][j];
}
and you would call it asRange(Matrix, 5, 4, 0);
Which brings us to our last item (finally); don't use "magic numbers" in your code. Instead of splashing the literal 5 all over the place, define symbolic constants (preprocessor macros) to represent the number of rows and columns in your matrix. For one thing, if you decide to change the array dimensions, you only need to update the constant definitions, rather than chase down every occurrence of the literal 5 and determining whether it's being used to check your array access. Putting all of the above together (and assuming you're okay with Range only working with arrays of a specific size), we get:/**
* sub.h - declaration for Range function
*/
#ifndef SUB_H // include guards; prevents this file from being processed
#define SUB_H // more than once for the same translation unit
/**
* Since these macros are going to be used by both the main function
* and the Range function, it makes sense to define them in the
* sub.h file, as it will be included in both main.c and sub.c
*/
#define ROWS 5
#define COLS 5
/**
* Prints the value at index i,j of m; if i or j are out of
* range, prints nothing.
*/
void Range( int m[][COLS], size_t rows, size_t i, size_t j );
#endif
/**
* sub.c - implementation of Range function
*/
#include <stdio.h>
#include "sub.h"
void Range( int m[][COLS], size_t rows, size_t i, size_t j )
{
if ( i < rows && j < COLS )
printf("Your range is: %d\n", m[i][j]);
}
/**
* main.c
*/
#include <stdio.h>
#include "sub.h"
int main( void )
{
int Matrix[ROWS][COLS];
Matrix[4][0] = 5; // assumes we know 4 and 0 are within
Range( Matrix, ROWS, 4, 0 ); // the array bounds.
}
So, are you thoroughly confused yet?
1. A C99 compiler, or a C2011 compiler where the macro __STDC_NO_VLA__ is either undefined or 0. Some C89 compilers may support VLAs as an extension.
You should have a header file which have the prototype of the function you need to call and include it. I don't think you include the .c file
You also need to pass parameter to the function.
If you need to access variables across files, you need to use extern variable.
Good programming practices dictate to use them as parameters, so the option'd be:
#include <stdio.h>
#include "sub.h"
int main(void)
{
int matrix[5][5];
matrix[5][1] = 5;
Range(matrix);
}
Where sub.h includes only the prototype of the funcion.
Now for sub.c:
int Range(int matrix[][5])
{
printf("Your Range is: %i",matrix[5][1]);
return 0;
}

Not able to understand this function definition

How to interpret this function definition? How should I pass arguments to it?
void matmul(float (*A)[N],int BlockX, int BlockY)
The first argument is a pointer to an array of N elements:
float a[N];
matmul(&a, 2, 3);
(Note that N has to be a compile-time constant in C89 and C++; in C89 it would essentially have to be #defined as some literal value. In C99 you have variable-length arrays.)
Since arrays decay to pointers, you can also feed it an array:
float b[M][N];
matmul(b, 2, 3);
Another way of writing the same prototype would be
void matmul(float A[][N],int BlockX, int BlockY)
which better shows what this usually supposed to receive, a two dimensional array, for which N is
a compile time integer constant (not a const variable!) if you only have C89
any integer expression which can be evaluated at the point of the definition if you have modern C99
The other dimension is not specified and you have to know or transmit it somehow.
It looks to me that this interface is an oldish one, since it seems to use int parameters to pass size information. The modern way to do this (and avoid 32/64 bit problems and stuff like that) would be to use size_t for such quantities.
If by chance the two parameters would correspond to the "real" matrix dimension, in modern C your definition should look like
void matmul(size_t m, size_t n, float A[m][n]) {
...
}
where it is important that m and n come before A, such that they are already known, there.

Resources