Variable length array with unknown size - c

In C, because of the framework I use and generate though a compiler, I am required to use global variable length array.
However, I can not know the size of its dimension until runtime (though argv for example).
For this reason, I would like to declare a global variable length array with unknown size and then define its size.
I have done it like that :
int (*a)[]; //global variable length array
int main(){
//defining it's size
a = (int(*)[2]) malloc(sizeof(int)*2*2);
for(int i=0;i<2; i++){
for(int j=0;j<2; j++){
a[i][j] = i*2 + j;
}
}
return 0;
}
However, this does not work : I get the invalid use of array with unspecified bounds error. I suspect it is because even if its size is defined, its original type does not define the size of the larger stride.
Does someone know how to solve this issue ? Using C99 (no C++) and it should be quite standard (working on gcc and icc at least).
EDIT: I may have forget something that matters. I am required to propose an array that is usable through the "static array interface", I mean by that the multiple square bracket (one per dimension).

First a is not an array but a pointer to an array of unspecified length. What you are trying to do is not possible. You can't have a global variable length array.
But with the present scenario you can use this to access the memory allocated to a
for(int i=0;i<2; i++){
int *ptr = *a + 2*i;
for(int j=0;j<2; j++){
ptr[j] = i*2 + j;
}
}

You cannot declare a global multi dimensional VLA, because even if you use pointers, all the dimensions except for the first one must be known at declaration time.
My best attempt would be to use a global void *. In C void * is a special pointer type that can be used to store a pointer to any type, and is often used for opaque pointers.
Here you could do:
void *a; // opaque (global variable length array) pointer
int main() {
//defining it's size
a = malloc(sizeof(int) * 2 * 2); // the global opaque pointer
int(*a22)[2] = a; // a local pointer to correct type
for (int i = 0; i<2; i++) {
for (int j = 0; j<2; j++) {
a22[i][j] = i * 2 + j;
}
}
return 0;
}
When you need to access the global VLA, you assign the value of the opaque global to a local VLA pointer, and can then use it normally. You will probably have to store the dimensions in global variables too...

Related

How do I correctly return an array from a function?

I tried this:
int* test()
{
static int states[2]= {4,7};
return states;
}
And called it like this:
int* values = test();
But it only seems to return the first value - 4 - and not the whole array.
I tried to do it exactly as I saw in other examples so I'm confused as to why it doesn't work. I'm using the STM32cubeIDE to write and compile, if that makes a difference.
Normal arrays can't be returned from a function because their lifetime ends when the function returns, the behavior for accessing one of these local arrays outside the scope of the function is undefined.
In your particular case this is possible because your array has static storage duration.
In C a function can only return one element, so to return an array you must return a pointer which can contain the address of the first element of that array. And that's what you're doing in your code. You can access both values by correctly indexing the returned pointer i.e. values[0] and values[1].
Unfortunately this is not without its issues, the size of the array is not known by the caller and you can't safely index it because you don't know its bounds.
There are ways solve this which are not all that complicated once you get used to them. Most notably defining a global size for the array1, using a structure containing the size of the array and a pointer to the array itself2, or passing pointers to the size and/or the array as arguments of the function3.
1. Using a global variable that stores its size:
#define SIZE 2
int *test()
{
static int states[SIZE] = {4, 7};
return states; //returns a pointer to the first element of the array
}
int main()
{
int* values = test(); // values is now pointing to the array
for(size_t i = 0; i < SIZE; i++){
printf("%d ", values[i]); //indexing is similar to a local array
}
}
2. Using a struct to store both the size and a pointer to the array:
typedef struct{ //structure to hold the data
int *array;
size_t size;
} array_struct;
array_struct test()
{
static int states[2] = {4, 7};
array_struct array = {.array = states, .size = 2}; //assing pointer and size
return array; //return the structure
}
int main()
{
array_struct values = test(); //assing the structure to a local
for(size_t i = 0; i < values.size; i++){ //use the size passed
printf("%d ", values.array[i]);
}
}
Output:
4 7
Option 3 is laid out in Bathsheba's answer.
You get back a pointer to the first element of the array due to the decay of the array type to a pointer type.
You obtain the other elements by pointer arithmetic.
Unfortunately though all size information is lost so you don't know at the call site how many elements you have. One way round that would be to change the function to
void test(int** array, size_t* length)
with *array = states and *length = sizeof(states) / sizeof(states[0]) in the function body.
How do I correctly return an array from a function?
You don't because you cannot. Read the C11 standard n1570.
(since as return values, arrays are decayed to pointers)
In practice, you could use a flexible array member in your struct and return some malloc-ed pointer to that struct. You then need a documented convention about who will free that pointer.
Read about C dynamic memory allocation. For more details and example code, see this answer.

Globally defining an array with unknown dimensions

I am trying to globally define a multidimensional array. The dimensions will ultimately depend on some other computations. Here I'll just consider n and B to be 5 but I place them inside function2 to stress that the dimensions are not known initially. At some point I'll also need to duplicate this array. The code below gives the error Subscripted value is not an array, pointer, or vector on the line where I'm printing the array2 entries. How can I fix this error and is there anything else I need to change to accomplish this?
int n,B;
double ** array;
double ** array2;
void function(){
double array[n][B][n];
for(int i = 1; i <= n; i++){
for(int j = 1; j <= B; j++){
for(int k = 1; k <= n; k++){
array[i-1][j-1][k-1] = i*j*k;
}
}
}
}
void function2(){
n=5;
B = 5;
function();
array2 = array;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= B; j++){
for(int k = 1; k <= n; k++){
printf("%lf",array2[i-1][j-1][k-1]);
}
}
}
}
int main(){
function2();
return 0;
}
Oops... I am trying to globally define a multidimensional array. The dimensions will ultimately depend on some other computations... Don't. At least do not try that in C language. Arrays are not first class citizens in C, not speaking of multi-dimensional ones. Said differently AFAIK, there is no way in C to declare a multi-dimensional array where all dimensions but the last one are not compile time constants.
But there are another problems in your code: double ** array; at global level declares a pointer to pointer (or a pointer to array) which is a totally different animal than a multi-dimensional array. And double array[n][B][n]; (wrongly) declares a totaly independant multi-dim. array, hiding the global symbol.
So my advice is:
avoid if possible globaly defined variables. There are indeed correct use cases but most of the time, it is cleaner to pass them as parameter of functions, possibly inside structs
make your choice between a multi-dimensional array and an array of pointers. The former is a consecutive containers where all dimensions but the last have to be constant, the latter if much more versatile, because each row could have a different size. But it is slightly more complex to declare and slightly less efficient.
int a1[5], a2[6], a3[7];
int **parray = {a1, a2, a3};
elt_i_j = parray[i][j];
do not forget about the good old idiom allowing to see a 1-D array as a multi-dim one:
size_t size1, size2, size3;
// compute the sizes...
int *array = malloc(size1, size2, size3);
elt_i_j_k = array[k + size2 * (j + size1 * i)]
Good luck in learning C arrays...
First note that in function2 :
function();
array2 = array;
array refers to the global variable, while function initialized its local variable array and not the global one. So array and array value NULL
Subscripted value is not an array, pointer, or vector
array2 is only known as double ** array2; so array2[i-1][j-1][k-1] cannot be resolved because it needs at least the last two dimensions. Note also it is strange to use a double pointer for a 3D array.
If you want to use array2 supposing it is in fact double array2[n][B][n] you can cast it as double (*)[B][n], but in your code array2 is NULL. Or of course you have array2 as a double * and you compute yourself the right offset to access the double you want
First thing, 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 columns there are?
So, you have to specify the rows and columns at the start.
However, you can have some workaround. Refer to this Initializing Arrays in C/C++ With Unknown Size
There are few issues in the code which you should have a look at:
functions() has a local declaration of array2. So,
double ** array2;
and
array2 = array;
are different.
You can't assign arrays in C. You can copy them with the memcpy() function, declared in string.h as follows:
memcpy(&array2, &array, sizeof array2);
array2 is declared as double ** array2; so array2[i-1][j-1][k-1] cannot be resolved.
Happy coding!

Trouble working with 2d array passed by reference C

So I am working on an assignment and I am having trouble figuring out how to use this 2d array which was passed by reference.
What I am given is this
int main(){
//cap and flow initialized
maximum_flow(1000, &(cap[0][0]), &(flow[0][0]));
}
So I wanted to copy the contents of cap over to another 2d array I dynamically allocated, but after hitting an error I decided to print out the values I have in cap2 and capacity, I'm not getting back all the values that I should.
void maximum_flow(int n, int *capacity, int *flow){
int **cap2;
cap2 = (int**) malloc(sizeof(int *)*n);
for (i = 0; i < n; i++)
{
cap2[i] = (int*) malloc(sizeof(int)*n);
}
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
cap2[i][j] = (*(capacity + i*n + j));
(*(flow + i*n + j)) = 0;
}
}
}
This isn't going to be a terribly useful answer, since your code doesn't actually show the problem described; based on what's presented, I see no obvious reason why cap and cap2 shouldn't have the same contents by the end of the maximum_flow function. But I'd like to offer some background and a suggestion.
I'm going to assume cap and flow are declared as n by n arrays of int in main, where n is known at compile time.
The reason your instructor is using this interface is that passing multidimensional arrays as function arguments is problematic in C. Remember that unless it's the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaraiton, 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.
So, assuming a declaration like
int cap[10][10];
int flow[10][10];
the expressions cap and flow will each "decay" to type int (*)[10] (pointer to 10-element array of int). So if you wrote your function call as
maximum_flow( 1000, cap, flow );
then the function definition would have to be written as
void maximum_flow( int n, int (*cap)[10], int (*flow)[10] ) { ... }
or
void maximum_flow( int n, int cap[][10], int flow[][10] ) { ... }
In the context of a function parameter declaration, T a[][N] and T (*a)[N] mean the same thing.
The size of the outer dimension has to be specified in the array pointer declaration, and the problem is that a pointer to a 10-element array is a different, incompatible type from a pointer to an any-value-other-than-10-element array; thus, maximum_flow could only ever be used for N x 10-element arrays, limiting its usefulness. One way around this problem is to have the function receive an explicit pointer to the first element, and treat that pointer as a 1D array of size N * M.
Long story short, since you're treating your input parameters as 1D arrays, you are probably better off creating cap2 as a 1D array as well:
int *cap2 = malloc( sizeof *cap2 * n * n );
...
cap2[i * n + j] = capacity[i * n + j]; // use array subscript notation instead
flow[i * n + j] = 0; // of explicit dereferences
From the code you've posted, it's not clear what maximum_flow is supposed to do, nor why you need cap2. Note also that at some point you need to free the memory allocated to cap2, otherwise you have a memory leak.
If you're using a C99 or later compiler, you should be able to use a variable-length array instead of malloc:
int cap2[n * n]; // or int cap2[n][n], but like I said above, if you're
// treating your inputs as 1D arrays, you should also treat
// cap2 as a 1D array.
The advantage of a VLA is that you don't need to know the size at compile time, and it's treated like any other auto variable, meaning the memory for it will be released when the function exits.
The disadvantage of a VLA is that you can't use it as anything but a local variable; you can't have a VLA as a struct or union member, nor can you declare one static or at file scope. Neither can you explicitly initialize a VLA.

C modifying array unexpected behaviour

I understand it is not possible to pass an array to a function in C and modify it without using sending a reference to that array, so how is the chess method initialising the array, and it is being printed correctly in main?
int chess(int rows, int cols, int array[rows][cols])
{
/* Go through the rows and colums in the array */
for (int i = 0; i < rows;i++)
{
for (int j = 0; j < cols; j++)
{
/* If the location is even, then print a 0, else print a 1. */
if (((i + j) % 2) ==0)
{
array[i][j] = 0;
}
else
{
array[i][j] = 1;
}
}
}
/* return */
return 0;
}
int main(void)
{
int arrayDimensions;
int noOfTests = 7;
/* run the program for the given amount of tests */
/*for (arrayDimensions = 0; arrayDimensions <= noOfTests; arrayDimensions++)*/
{
/* Declare an array for each dimension */
int array[6][5];
/* call the chess method passing it the arguments specified. */
chess(6, 5, array);
/* Print out the array according to the size of the array. */
for (int i = 0; i < 6; i++)
{
printf("\n");
for (int j = 0; j < 5; j++)
{
printf("%d", array[i][j]);
}
}
/* Create a new line after each row */
printf("\n");
}
}
Though you probably already know most of this, the latter part is relevant, so stay with this for a moment.
What you probably know
C is a pass-by-value language. This means when you do this:
void foo(int x)
{
x = 5;
}
called as
int n = 1;
foo(n);
printf("%d\n", n); // n is still 1
the caller passes a value and the parameter x receives it. But changing x has no effect on the caller. If you want to modify a caller's data variable, you must do so by-address. You do this by declaring the formal parameter to be a pointer-to-type, dereference the pointer to modify the pointed-to data, and finally, pass the address of the variable to modify:
void foo(int *p)
{
*p = 5;
}
called as:
int n = 1;
foo(&n);
printf("%d\n", n); // n is now 5
Why do you care?
So what does any of this have to do with your array? Arrays in C are a contiguous sequence of data of the underlying type of the array, and an array's expression value is the address of its first element.
Chew on that last sentence for a minute. That means the same way an int variable has a value of the int stored within, an array variables has the address of its first element as its "value". By now you know that pointers hold addresses. Knowing that and the previous description means this:
int ar[10];
int *p = ar;
is legal. The "value" of ar is its first-element address, and we're assigning that address to p, a pointer.
Ok then, So the language specifically defined arrays as parameters as simply pointers to their first elements. Therefore both of these are equivalent:
void foo(int *p)
{
*p = 5;
}
void bar(int ar[])
{
ar[0] = 5;
}
And the caller side:
int ar[10];
foo(ar); // legal, ar's "value" is its first element address
bar(ar); // legal, identical to the above.
A phrase I often use when explaining the fundamentals of pointers and arrays is simply this:
A pointer is a variable that holds an address; an array is a variable that is an address.
So whats with this whacky syntax?
int chess(int rows, int cols, int array[rows][cols])
Ah. There is something interesting. Your compiler supports VLA s (variable length arrays). When compiling the code for this function the compiler generates the proper logic to perform the proper access to the passed array. I.e. it knows that this:
array[1][0]
is cols many int values past the beginning of the array. Without the feature of VLAs (and some C compilers don't have them), you would have to do this row-by-column math yourself by hand. Not impossible, but tedious none-the-lesss. And i only briefly mention that C++ doesn't support VLA's; one of the few features C has that C++ does not.
Summary
Arrays are passed by address because when it comes to their "value", that is all they really are: an address.
Note: I worked very hard to avoid using the word "decay" or the phrase "decays to a pointer" in this description precisely because that verb implies some mystical functional operation when in-fact none exists. Arrays don't "decay" to anything. They simply are; Their "value", per the C standard, is the address of their first element. Period. What you do with that address is another matter. And as an address, a pointer can hold their "value" and dereference to access said-same (such as a function parameter).
Personal: I once asked on this forum how long that term (decay) has been buzzed about in C-engineer vernacular, since in the 600+ pages of the C standard it appears exactly ZERO times. The farthest back anyone found was 1988 in the annals of some conspicuous online journal. I'm always curious to note who started it an where, and said-quest continues to elude me.
Anyway, I hope this helps, even a little.
when dealing with arrays you are dealing with an address so if you pass an array into a function and you changed the array in the function, the real array will change.
In other words, if you know pointers an array is a pointer.
I didn't read the code but you have a clear misunderstanding of passing an array to a function.
An array reference IS an address (it's a misnomer to say it's a pointer, but it will behave as such). It works because the function is declared to accept a type of int[][], which allows the function to interact with the array reference as if you'd passed a pointer to the function.
From a reference manual:
When a function parameter is declared as an array, the compiler treats
the declaration as a pointer to the first element of the array. For
example, if x is a parameter and is intended to represent an array of
integers, it can be declared as any one of the following declarations:
int x[]; int *x; int x[10];
So you are passing a reference. The compiler turns your declaration into a pointer reference with also some sizing constraints.

Returning a two-dimensional array in C?

I recently started programming C just for fun. I'm a very skilled programmer in C# .NET and Java within the desktop realm, but this is turning out to be a bit too much of a challenge for me.
I am trying to do something as "simple" as returning a two-dimensional array from a function. I've tried researching on the web for this, but it was hard for me to find something that worked.
Here's what I have so far. It doesn't quite return the array, it just populates one. But even that won't compile (I am sure the reasons must be obvious to you, if you're a skilled C programmer).
void new_array (int x[n][n]) {
int i,o;
for (i=0; i<n; i++) {
for (o=0; o<n; o++) {
x[i][o]=(rand() % n)-n/2;
}
}
return x;
}
And usage:
int x[n][n];
new_array(x);
What am I doing wrong? It should be mentioned that n is a constant that has the value 3.
Edit: Here's a compiler error when trying to define the constant: http://i.imgur.com/sa4JkXs.png
C does not treat arrays like most languages; you'll need to understand the following concepts if you want to work with arrays in C.
Except when it is the operand of the sizeof or unary & operator, 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. This result is not an lvalue; it cannot be the target of an assignment, nor can it be an operand to the ++ or -- operators.
This is why you can't define a function to return an array type; the array expression will be converted to a pointer type as part of the return statement, and besides, there's no way to assign the result to another array expression anyway.
Believe it or not, there's a solid technical reason for this; when he was initially developing C, Dennis Ritchie borrowed a lot of concepts from the B programming language. B was a "typeless" language; everything was stored as an unsigned word, or "cell". Memory was seen as a linear array of "cells". When you declared an array as
auto arr[N];
B would set aside N "cells" for the array contents, along with an additional cell bound to arr to store the offset to the first element (basically a pointer, but without any type semantics). Array accesses were defined as *(arr+i); you offset i cells from the address stored in a and dereferenced the result. This worked great for C, until Ritchie started adding struct types to the language. He wanted the contents of the struct to not only describe the data in abstract terms, but to physically represent the bits. The example he used was something like
struct {
int node;
char name[14];
};
He wanted to set aside 2 bytes for the node, immediately followed by 14 bytes for the name element. And he wanted an array of such structures to be laid out such that you had 2 bytes followed by 14 bytes followed by 2 bytes followed by 14 bytes, etc. He couldn't figure out a good way to deal with the array pointer, so he got rid of it entirely. Rather than setting aside storage for the pointer, C simply calculates it from the array expression itself. This is why you can't assign anything to an array expression; there's nothing to assign the value to.
So, how do you return a 2D array from a function?
You don't. You can return a pointer to a 2D array, such as:
T (*func1(int rows))[N]
{
T (*ap)[N] = malloc( sizeof *ap * rows );
return ap;
}
The downside to this approach is that N must be known at compile time.
If you're using a C99 compiler or a C2011 compiler that supports variable-length arrays, you could do something like the following:
void func2( size_t rows, size_t cols, int (**app)[cols] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...; // the parens are necessary
...
}
If you don't have variable-length arrays available, then at least the column dimension must be a compile-time constant:
#define COLS ...
...
void func3( size_t rows, int (**app)[COLS] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...;
}
You can allocate memory piecemeal into something that acts like a 2D array, but the rows won't necessarily be contiguous:
int **func4( size_t rows, size_t cols )
{
int **p = malloc( sizeof *p * rows );
if ( p )
{
for ( size_t i = 0; i < rows; i++ )
{
p[i] = malloc( sizeof *p[i] * cols );
}
}
return p;
}
p is not an array; it points to a series of pointers to int. For all practical purposes, you can use this as though it were a 2D array:
int **arr = foo( rows, cols );
...
arr[i][j] = ...;
printf( "value = %d\n", arr[k][l] );
Note that C doesn't have any garbage collection; you're responsible for cleaning up your own messes. In the first three cases, it's simple:
int (*arr1)[N] = func(rows);
// use arr[i][j];
...
free( arr1 );
int (*arr2)[cols];
func2( rows, cols, &arr2 );
...
free( arr2 );
int (*arr3)[N];
func3( rows, &arr3 );
...
free( arr3 );
In the last case, since you did a two-step allocation, you need to do a two-step deallocation:
int **arr4 = func4( rows, cols );
...
for (i = 0; i < rows; i++ )
free( arr4[i] )
free( arr4)
Your function return void, so the return x; line is superfluous. Aside from that, your code looks fine. That is, assuming you have #define n 3 someplace and not something like const int n = 3;.
You can't return an array in C, multidimensional or otherwise.
The main reason for this is that the language says you can't. Another reason would be that generally local arrays are allocated on the stack, and consequently deallocated when the function returns, so it wouldn't make sense to return them.
Passing a pointer to the array in and modifying it is generally the way to go.
To return (a pointer to) a newly-created array of dimensions known at compile time, you can do this:
#define n 10 // Or other size.
int (*new_array(void))[n]
{
int (*x)[n] = malloc(n * sizeof *x);
if (!result)
HandleErrorHere;
for (int i = 0; i < n; ++i)
for (int o = 0; i < n; ++o)
x[i][o] = InitialValues;
return x;
}
…
// In the calling function:
int (*x)[n] = new_array();
…
// When done with the array:
free(x);
If the size is not known at compile time, you cannot even return a pointer to an array. C does support variable-length arrays but not in the return types of functions. You could instead return a pointer to a variable-length array through a parameter. That requires using a parameter that is a pointer to a pointer to an array of variable length, so it gets somewhat messy.
Also, the preferred choices between allocating an array in the caller dynamically, allocating an array in the caller automatically, allocating an array in the called function dynamically and using variable-lengths arrays or fixed-length arrays or even one-dimensional arrays with manual indexing depend on context, including what how large the array might be, how long it will live, and what operations you intend to use it for. So you would need to provide additional guidance before a specific recommendation could be made.
In C there's only pass/return by value (no pass by reference). Thus the only way of passing the array (by value) is to pass its address to the function, so that it can manipulate it through a pointer.
However, returning by value an array's address isn't possible, since by the time control reaches the caller, the function goes out of scope and its automatic variables go down with it too. Hence if you really have to, you can dynamically allocate the array, populate and return it, but the preferred method is passing the array and leaving the onus of maintaining the array to the caller.
As for the error, the only warning I get in GCC for this is warning: 'return' with a value, in function returning void which is simply meaning that you shouldn't return anything from a void function.
void new_array (int x[n][n]); what you're really doing here is taking a pointer to an array of n integers; the decayed type is int (*x)[n]. This happens because arrays decay into pointers generally. If you know n at compile time, perhaps the best way to pass is:
#define n 3
void new_array (int (*x)[n][n]) {
int i,o;
for (i=0; i<n; i++) {
for (o=0; o<n; o++) {
x[i][o]=(rand() % n)-n/2;
}
}
}
And call it as
int arr[n][n];
new_array(&arr);
You can pass around arbitrarily dimensions arrays like any another variable if you wrap them up in a struct:
#include <stdio.h>
#define n 3
struct S {
int a[n][n];
};
static struct S make_s(void)
{
struct S s;
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
s.a[i][j] = i + j;
}
return s;
}
static void print_s(struct S s)
{
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
printf(" %d", s.a[i][j]);
printf("\n");
}
}
int main(void) {
struct S s;
s = make_s();
print_s(s);
return 0;
}
You are probably declaring n as a constant integer:
const int n = 3;
Instead, you should define n as a preprocessor definition:
#define n 3

Resources