Can a two-dimensional array in C be initialized without explicit size? - c

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.

Related

Passing [CONST][] array to C function?

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.

c macro, array definition as parameter

I have this method
foo_l(int *array, size_t l)
{
/*
code
*/
}
and I wrote this macro
#define foo(X) foo_l(X,sizeof(X)/sizeof(int))
So I can use them as follows
int main()
{
int a[]={1,2,3};
foo(a);
return 0;
}
and avoid writing the length of the array every time.
My question is, can I extend my macro so it can handle something like
foo_l((int[]){1,2,3}, 3);
with an array declared in the function parameter field?
Because foo((int[]){1,2,3}) doesn't work! I think that the problem is that the macro see (int[]){1,2,3} as a list of parameters and not as a unique parameter. Any Idea?
P.S. I'm pretty new to the macro world and I usually use c99.
When being passed to the preprocessor, the macro foo((int[]){1,2,3}) fails because the preprocessor believes it provided 3 parameters instead of 1:
foo((int[]){1,2,3});
// is believed to be:
// Start of macro: foo(
// Parameter 1: (int[]){1,
// Parameter 2: 2,
// Parameter 3: 3}
// End of macro: );
So it doesn't compile and gives something like:
a.c: In function ‘main’:
a.c:15:23: error: macro "foo" passed 3 arguments, but takes just 1
foo((int[]){1,2,3});
Adding another pair of parenthesis solves the problem:
// This shall work
foo(((int[]){1,2,3}));
EDITED:
Yes I guess this may not be a good design, since people like average programmers may be very likely to pass a pointer instead of an array type to your macro foo, and it would fail as #DwayneTowell points out.
Please be careful about this.
:)
What you have suggested is not a good idea, because it will fail in cases like the following:
int a[] = {1,2,3,4};
int *b = a;
foo(b); // becomes foo_l(b,sizeof(b)/(sizeof(int));
// probably becomes foo_l(b,1)
In general the size parameter will be wrong if the first parameter is a pointer to an array instead of the array itself. Usually the expression will evaluate to 1, when sizeof(int *)==sizeof(int), which is very common but required by the standard.

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;
}

Constant size global arrays in C

I'm trying to figure out there best way to define a global array with a constant size and I've come to the following options, all with their own flaws.
// 1:
#define ASIZE 10
int array[ASIZE];
// 2:
enum {ASIZE = 10};
int array[ASIZE];
// 3:
#define ASIZE_DEF 10
static const int ASIZE = ASIZE_DEF;
int array[ASIZE_DEF];
The problem with the first two is that I can't get the value of ASIZE from GDB. I guess the third option is best because I can still dump the value of the const, but it also leaks in another macro. I can undef the macro after defining the array and const but if the #define and the const are in a separate file from the array declaration, then it gets a bit hairy.
Is there a better way?
Doing something for the sake of the debugger is wrong. Incidentally, gdb knows about this if you compile your code right.
Some languages, such as C and C++, provide a way to define and invoke
“preprocessor macros” which expand into strings of tokens. gdb can
evaluate expressions containing macro invocations, show the result of
macro expansion, and show a macro's definition, including where it was
defined.
Version 3.1 and later of gcc, the gnu C compiler, provides macro
information if you specify the options -gdwarf-2 and -g3; the former
option requests debugging information in the Dwarf 2 format, and the
latter requests “extra information”.
You are dealing with a GDB issue, not a C issue. You can also do #4, which is arguably better than #3.
enum {ASIZE = 10};
static const int ASIZE_FOR_GDB = ASIZE;
int array[ASIZE];
My understanding is that you are defining a constant, using it later to size one or more arrays, and also want that constant to be a symbol, preferably without a messy namespace. (If it were a matter of exporting the size of a single array, I would instead suggest sizeof(array) / sizeof(*array) as missingno did.)
static const int ASIZE = 10;
#define ASIZE 10
int array[ASIZE];
Here, there is a variable with the desired value which will be in the object file, but the preprocessor macro shadows it with the value itself, so the array definition also succeeds.
However, you may find the need to duplicate the value expression ugly. Wouldn't it be nice if we could define the variable in terms of the macro?
static const int ASIZE =
#define ASIZE 10
ASIZE;
int array[ASIZE];
I'm not sure whether this is actually a better idea maintainability-wise than the above, but it works (and I couldn't get gcc to be offended by it) and it contains no duplication other than of the identifier. And it's amusing.
Since you know array is a global array (and not just a pointer) you can find its length using
sizeof(array) / sizeof(*array)
without needing to set an extra variable for that.

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