so I'm asked to make the following function:
int **multiplyM(int MA[][], int MB[][], int n, int m)
Which will multiply two matrices. The first one (MA) with dimensions n, n, and the second one (MB) with dimensions n, m. I have everything done with the program, but I get an error caused by the function itself, which says:
"array type has incomplete element type"
I know I can fix it by changing stuff in the function (like changing it to **MA and **MB), but the thing is, I'm not supposed to do that, because I'm supposed to make my program based on this function that was given to me.
So my question is: Is there a way to make this work WITHOUT changing the function?
The second dimension must be given for MA and MB
So,
#define SIZE_M 5 //Any constant
#define SIZE_N 6
int **multiplyM(int MA[][SIZE_M], int MB[][SIZE_N], int n, int m)
//Fix -> ^^^ ^^^
You cannot pass a multidimensional array to a function as you are doing. You need to specify the size of the the second dimension (and any further dimension) when declaring the function. Specifying the size here is important. If it were not mandatory, the compiler won't be able to deal with expression such Array[2][3]. The value used as array dimension must be a constant for ANSI C an other versions, but it can be a variable for C99 and successive versions. The C99 standard introduced the variable-length arrays feature, which allows to determine the size of an array at run-time.
So:
#define N 10
#define M 5
int **multiplyM(int MA[][N], int MB[][M], int n, int m)
I know I can fix it by changing stuff in the function (like changing
it to **MA and **MB), but the thing is, I'm not supposed to do that,
because I'm supposed to make my program based on this function that
was given to me.
Without modifying at least the declaration of the function, you are not going to solve this problem.
Related
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.
I have a question regarding two-dimensional arrays in C. I know now (from direct compiler experience) that I can't initialize such an array analogously to one-dimensional arrays like this:
int multi_array[][] = {
{1,2,3,4,5},
{10,20,30,40,50},
{100,200,300,400,500}
};
> compiler output:
gcc -o arrays arrays.c
arrays.c: In function ‘main’:
arrays.c:8:9: error: array type has incomplete element type
The closest solution that works is to provide the number of columns explicitly like this:
int multi_array[][5] = {
{1,2,3,4,5},
{10,20,30,40,50},
{100,200,300,400,500}
};
My question is: can it be done neatly without supplying the number explicitly (which after all the compiler should be able to infer itself)? I'm not talking about manually constructing it with malloc or something but rather something close to what I tried.
Also, can someone knowledgeable about C compilers explain from a low-level perspective why my initial attempt does not work?
I used plain gcc with no non-standard options to compile the code.
Thanks
2D arrays in C are stored in contiguous memory locations. So if you do not provide the number of rows or the number of columns, how will the compiler know how many rows and column there are?
For a row major matrix, rows contents are at contiguous memory positions. So you need to specify at least the number of columns. Similarly for a column major matrix, you need to specify at least the number of rows. Whether it is row major or column major is defined by architecture. It seems that what you have is a row major architecture.
You can do this using the C99 compound literal feature.
A partial idea is that the length of an initializer list can be determined like this:
sizeof (int[]){ 1, 2, 3, 4, 5 } / sizeof(int)
We need a workaround for the fact that the only way you can pass an argument containing a comma to a macro is to put parentheses around (part of) the argument:
#define ROW(...) { __VA_ARGS__ }
Then the following macro deduces the second dimension from the first row:
#define MAGIC_2DARRAY(type, ident, row1, ...) \
type ident[][sizeof (type[])row1 / sizeof (type)] = { \
row1, __VA_ARGS__ \
}
It only works if there are at least two rows.
Example:
MAGIC_2DARRAY(int, arr, ROW(7, 8, 9), ROW(4, 5, 6));
You probably do not want to use this in a real program, but it is possible.
For passing this kind of array to functions, the C99 variable length array feature is useful, with a function like:
void printarr(int rows, int columns, int array[rows][columns]) { ... }
called as:
printarr(sizeof arr / sizeof arr[0], sizeof arr[0] / sizeof arr[0][0], arr);
Not a direct answer to those questions in the original post, I just want to point out that what the asker propose may be not such a good or useful idea.
The compiler indeed can infer from
int multi_array[][] = {
{1,2,3,4,5},
{10,20,30,40,50},
{100,200,300,400,500}
};
the structure of multi_array.
But when you want to declare and define a function (this declaration and definition could be in another compilation unit or source file) that supposes to accept multi_array as one of its argument, you still need to do something like
int foo(..., int multi_array[][COL], ...) { }
Compiler needs this COL to do proper pointer arithmetic in foo().
Usually, we define COL as a macro that will be replaced by an integer in a header file, and use it in the definitions of multi_array and foo():
int multi_array[][COL] = { ... };
int foo(..., int multi_array[][COL], ...) { }
By doing this, it is easy to make sure they are the same. And let compiler to infer the structure of multi_array according to its initialization, when you give it a wrong initialization, you actually introduce a bug in your code.
No you can't do it. If you even don't initialize, you can't define an int array[][];
Create a structure with 1d arrays. However, if you follow this method you can create new arrays but it will be a function call to change sizes and values. A dynamic matrix approach could come close to solving your issue.
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;
}
This is the declaration of the function and the compiler gives: "error: array type has incomplete element type" in both the declaration and definition. I don't see the error.
void calculate(float matrM[][], int origMatr[][]);
C doesn't have very powerful arrays, especially not when calling functions. Basically, the only data that gets sent to the function at run-time is the address of the first element. This means that the dimensions must be known in all directions except the topmost, in order for the compiler to be able to generate indexing code. Thus, you can't have two unknown dimensions, that makes indexing impossible and thus isn't allowed.
You can't declare an "any size" array like that, you must specify all dimensions except one, otherwise there's no way to compute the address of a random element in the array.
It's often better to break it down as:
void calculate(float *out, const float *in, size_t width, size_t height);
which will let you treat any memory block as float arrays, but requires you to specify the size, and the write the indexing manually:
out[y * width + x] = in[y * width + x];
Your "inner" dimensions must have a size, e.g.:
void calculate(float matrM[][5], int origMatr[][7]);
Otherwise, the compiler wouldn't know how to generate indexing code to access a particular element. Note also that these sizes must be compile-time constant expressions.
For more details, see How do I write functions which accept two-dimensional arrays when the width is not known at compile time? from the C FAQ.
If you have a modern C compiler (C99 would do) you can have the "extra" dimensions as expressions of other function parameters that precede
void calculate(size_t n, float matrM[][n], int origMatr[][n]);
you'd just have to be careful that you'd have equivalent parameters in your declaration (the one I gave) and the definition (the one that provides the implementation of the function).
You only get one "free" dimension (the first one) when you're passing an array to a function. The correct declaration will look more like:
void calculate(float matrM[][N], int origMatr[][M]);
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.