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.
Related
This is a theoretical question, there is no need to show code.
So, I would like to know how to return the result of a sum function, which will add two arrays using pointers.
First, should matrices be declared as a pointer right at the beginning?
So, in the function we will have
void sumMatrix (int ** m) (?)
From here, how to proceed to return the result of this sum, since the matrix itself cannot be returned
Options include:
Pass the function a pointer to where you want the result matrix stored.
Write code in the function to allocate space for the result matrix and return a pointer to that space.
Create a structure type to hold the result matrix and have the function return that structure by value.
Write the results into one of the input matrices.
It is impossible to pass arrays of any dimension to functions in C. It is impossible even to express the concept, because in most circumstances, including function-call expressions, values of array type are automatically converted to pointers. Thus,
Your function has no alternative but to receive its arguments in the form of pointers.
However, you should give some thought to the specific pointer types. C multidimensional arrays (e.g. int arr[3][4]) are structured as arrays of arrays, and the aforementioned automatic conversions yield pointers to arrays (int (*p)[4]), not pointers to pointers. On the other hand, you can construct arrays of pointers (int *arr[3]) and use the same syntax to access them as one does with multidimensional arrays. The automatic conversion of these to pointers does yield double pointers (int **p). Despite the matching access syntax, these alternatives very different in terms of memory layout and access efficiency.
It depends. Ignoring the for the moment the question of returning the sum, you have at least three good alternatives:
void sumMatrix(int r, int c, int **m1, int **m2); This is appropriate for array of pointers data layout. You an express the same thing as
void sumMatrix(int r, int c, int *m1[], int *m2[]);, and I would probably be inclined to do that myself.
void sumMatrix(int r, int c, int m1[r][c], int m2[r][c]); This is equivalent to
void sumMatrix(int r, int c, int m1[][c], int m2[][c]); and to
void sumMatrix(int r, int c, int (*m1)[c], int (*m2)[c]);
These rely on the variable-length array feature added to C in C99, and it is worth knowing that this feature became optional in C11. It assumes compact, efficient array-of-array data layout.
void sumMatrix(int r, int c, int *m1, int *m2); or, equivalently,
void sumMatrix(int r, int c, int m1[], int m2[]); This supposes the same array-of-array data layout as the previous, but requires you to perform the index calculations manually (x * c + y). It is useful if you want to have array-of-array layout with variable array dimensions, without depending on VLAs.
Personally, I would be inclined to choose array-of-arrays layout and one of the variations on the second signature option.
From here, how to proceed to return the result of this sum, since the matrix itself cannot be returned
You again have multiple options, but I would be inclined to add a fifth parameter, of the same type as the third and fourth, representing the result matrix. Because, again, it is necessarily a pointer, the data written into the pointed-to object by the function will be visible to the caller. The caller will then be responsible for passing a pointer to an existing object, which is convenient because it allows (but does not require) using an automatically allocated object.
Thus one complete possibility would be
void sumMatrix(int r, int c, int m1[r][c], int m2[r][c], int result[r][c]) {
// ...
}
which could be called like this:
int a[3][4], b[3][4], c[3][4];
// ... fill arrays a and b ...
summMatrix(3, 4, a, b, c);
// the result is in matrix c
Compelled to use the variable length array feature for my auxiliary function that prints square matrices, I defined it as follows:
void print_matrix(M, dim)
unsigned dim;
int M[dim][dim];
{
/* Print the matrix here. */
...
The good news is, the code works and has its parameters in the order I'd like them to be.
The bad news is, I had to use the "old-style" function declaration syntax in order to reference the yet-to-be-declared argument dim in the declaration of M, which is apparently considered obsolete and dangerous.
Is there a straightforward way to do the same with the "new-style" function declarations WITHOUT changing the order of the parameters? (And if not, is it considered acceptable use of the old-style syntax in this particular situation?)
In portable (standard) C, you can't do what you show. You have to specify the dimension before the matrix. The original code in the question was:
void print_matrix(M, dim)
unsigned dim;
int (*M)[dim][dim];
{
and that can't be directly translated — it needs a prototype like this, with the dimension before the matrix:
void print_matrix(unsigned dim, int (*M)[dim][dim]);
This allows you to call the function with a 3D array. Or, with the revised notation in the question, you can print a 2D array:
void print_matrix(unsigned dim, int M[dim][dim]);
GCC provides an extension to assist. Quoting the manual:
If you want to pass the array first and the length afterward, you can use a forward declaration in the parameter list—another GNU extension.
struct entry
tester (int len; char data[len][len], int len)
{
/* … */
}
You can write any number of such parameter forward declarations in the parameter list. They can be separated by commas or semicolons, but the last one must end with a semicolon, which is followed by the “real” parameter declarations. Each forward declaration must match a “real” declaration in parameter name and data type. ISO C99 does not support parameter forward declarations.
An old-style declaration which is preceded by a prototype is syntactically ugly, but is no more dangerous than a new style declaration.
void print_matrix(int M[*][*], unsigned dim);
void print_matrix(M, dim)
unsigned dim;
int M[dim][dim];
{
...
}
The authors of the Standard recognized that the old-style declarations were a valid, useful, and sufficient means of accomplishing the task, and decided that writing rules to allow with new-style declarations would be too much work, so they didn't want to bother. The combination of a prototype and old-style declaration is thus the only way to achieve the appropriate semantics.
I am designing a C function interface which involves a 2d array.
The problem is, row dimension is constant, and column one should be user defined.
#define ROWS (65)
void init(int columns, float array[ROWS?][columns?])
{
...
}
void main()
{
float array1[ROWS][30];
float array2[ROWS][50];
init(30, array1);
init(50, array2);
}
How do I design an interface to be able to pass this kind of array down to function?
p.s.
Can't do it the other way around, where columns would be constant, because must use some 3rd pary libraries that want it this way.
Simply do as you wrote in your example
void init (size_t rows, size_t columns, float array[rows][columns])
Then you can pass compile-time constants or run-time variables to the function as you please. You'll also need to have C compiler from the current millennium (C99 or later).
You mentioned c99 in a comment. So it shouldn't be too difficult to approximate what you want. In fact, you are almost there yourself. It can look like this:
#define ROWS 65
void init(int columns, float array[static ROWS][columns])
{
}
Now array is of a variably modified type, and columns is user defined. static ROWS means callers must pass in an array of at least 65 rows, or undefined behavior will ensue. That's pretty much as close to forcing them to pass 65 as you can.
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.
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 */
}