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;
}
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.
Hey I'm working on a problem and here is what I have to do:-
Write a function called initarray that takes an array of pointers to int and an int representing the size of the array, as arguments. The function should initialize the array with pointers to ints (use malloc) that have a value corresponding to the array indices at which a pointer to them are stored (the pointer stored at array index 2 should point to an integer with a value of 2).
So far I've written this, but It's giving me an error "[Error] variable-sized object may not be initialized"
Can you tell me what I'm doing wrong here?
#include<stdio.h>
void initArray(int **a, int sz){
int i;
for (i = 0; i < sz; i++) {
a[i] = calloc (1, sizeof **a);
*a[i] = i;
}
}
int main(){
const int Var = 10;
int *array[Var] = {NULL};
initArray(array,3);
}
For historical reasons, the value of a const variable is never considered a constant expression in C.
So if you use it as an array dimension, then the array is a variable-length array, and variable-length arrays are not allowed to have initializers.
One solution not mentioned yet is to use enum. Enumerators are in fact constant expressions, and they don't suffer from the same "bigger hammer" issue as preprocessor macros:
int main()
{
enum { Var = 10 };
int *array[Var] = {NULL};
initArray(array,3);
}
C has no symbolic constants with user-defined type. You encountered one of the differences to C++.
The const qualifier just is a guarantee you give to the compiler you will not change the variable(!) Var.
Arrays with initialiser and global arrays require a constant expressing which can be evaluated at compile-time. As Var is semantically still a variable, you cannot use it.
The C-way to emulate symbolic constants are macros:
#define ARRAY_SIZE 10
...
// in your function:
int *array[ARRAY_SIZE] = ...
Macros are handled by the preprocessor and are a textual replacement before the actual compiler sees the code.
Note I changed the name to a more self-explanatory one. The macro should also be at the file-level, typically near the beginning to allow easier modifications. Using the integer constant 10 directly in the code is a bad idea. Such magic numbers are often cause of errors when a modification is required.
The error would suggest that you can't use an initializer (the = {NULL} in your main function) on a variable-sized object. While it looks like it isn't variable (because of the const on Var, and because 10 is a constant) it sees it as variable because you're accessing it through a variable. If you use:
int *array[10] = {NULL}
I think your snippet will work fine.
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.
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.
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 */
}