Return a 2D Array from a Function

How to return a 2D array from a function in C?

Thank you all for your answers and more specifically for the detailed explanation of the array-pointer relationship.

I encapsulated the array in a structure

 struct point_group1 {
float x[3];
float y[3];
};

struct point_group1 pixels(){
struct point_group1 temp;

temp.x[0] = 0.0;
temp.x[1] = 1.0;
temp.x[2] = -1.0;

temp.y[0] = 0.0;
temp.y[1] = 1.0;
temp.y[2] = 1.0;

return temp;
}



struct point_group1 points1 = pixels();
axPoly(points1.x, points1.y ,3, 0.0);

correct way to return two dimensional array from a function c

A struct is one approach:

struct t_thing { int a[3][3]; };

then just return the struct by value.

Full example:

struct t_thing {
int a[3][3];
};

struct t_thing retArr() {
struct t_thing thing = {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
};

return thing;
}

int main(int argc, const char* argv[]) {
struct t_thing thing = retArr();
...
return 0;
}

The typical problem you face is that int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; in your example refers to memory which is reclaimed after the function returns. That means it is not safe for your caller to read (Undefined Behaviour).

Other approaches involve passing the array (which the caller owns) as a parameter to the function, or creating a new allocation (e.g. using malloc). The struct is nice because it can eliminate many pitfalls, but it's not ideal for every scenario. You would avoid using a struct by value when the size of the struct is not constant or very large.

return 2D array in C++

If you're new to c++ you should read about the concepts of heap and stack, and about stack frames. There are a ton of good resources for that.

In short, when you declare a C-style array (such as yj), it is created in the stack frame of the function, and therefore there are no guarantees about it once you exit the frame, and your program invokes undefined behavior when it references that returned array.

There are 3 options:

  1. Pass the array to the function as an output parameter (very C-style and not recommended).
  2. Wrap the array in a class (like std::array already does for you), in which case it remains on the stack and is copied to the calling frame when returned, but then its size has to be known at compile time.
  3. Allocate the array on the heap and return it, which seems to me to best suit your case. std::vector does that for you:
std::vector<std::vector<double>> psiinit(int L, int n, double alpha){
std::vector<std::vector<double>> yj;
for (int j = 0; j < n; j++)
{
std::vector<double> xi;
for (int i = 0; i < n; i++)
{
const int value = exp(-(pow((i-(L/4)), 2) + (pow((j-(L/4)), 2)))/alpha) / (sqrt(2)*3.14159*alpha);
xi.push_back(value);
}

yj.push_back(xi);
}
return yj;
}

If you're concerned with performance and all of your inner vectors are of a fixed size N, it might be better to use std::vector<std::array<double, N>>.

How to return matrix (2D array) from function? (C)

Someone has to own the memory of that board somewhere, and more importantly, that ownership must extend back to the caller of this function. Without dynamic allocation, your only other real alternative is to send it into the function as in in/out parameter.

void generateBoard(size_t N, size_t M, int board[N][M])
{
int i, j , fillNum;
Boolean exists = True;
// initilize seed
srand(time(NULL));
// fill up..
for(i = 0; i < N; ++i) {
for(j = 0; j < M; ++j) {
exists = True;
while(exists) {
fillNum = rand()%MAX_RANGE + 1; // limit up to MAX_RANGE
if(beenAdded(board, fillNum) == Exist) {
continue;
} else {
board[i][j] = fillNum;
exists = False;
}
}
}
}
}

and invoke like this from your caller:

int main()
{
const size_t N = 10;
const size_t M = 10;
int board[N][M];

generateBoard(N,M,board);

...
}

I would also consider relocatting the srand() call to the startup code in main(). It should ideally never be in some potentially repeat-callable function, and should be guaranteed to only be executed once per process execution. (note: I honestly can't remember if it is once per thread execution, but at this point in your coding learning curve I'm guessing multi-threading is not on the radar yet).

Finally, your random-fill loop is needlessly repetitious. There are better alternatives generating what you're apparently trying to do: create a random permutation of an existing set of numbers. As written you could spin for some time trying to fill those last few slots, depending on how much larger MAX_RANGE is compared to (N*M).

Returning multidimensional arrays from a function in C

This is wrong:

int *create_array(int rows, int columns){
int array[rows][columns] = {0};
return array;
}

and should produce a warning like this:

prog.c:2:6: note: (near initialization for 'array')
prog.c:3:13: warning: return from incompatible pointer type [-Wincompatible-pointer-types]
return array;
^~~~~
prog.c:3:13: warning: function returns address of local variable [-Wreturn-local-addr]

since you are returning the address of an automatic variable; its lifetime ends when its corresponding function terminates.


You should either declare a double pointer in main(), pass it through the function, dynamically allocate memory for it and return that pointer. Or you could create the array in main() and pass the double pointer to the function.


I want to know ways to allocate multidimensional arrays on the heap and pass them around

For allocating memory on the heap you could use one of these two methods, which involve pointers:

#include <stdio.h>
#include <stdlib.h>

// We return the pointer
int **get(int N, int M) /* Allocate the array */
{
/* Check if allocation succeeded. (check for NULL pointer) */
int i, **array;
array = malloc(N*sizeof(int *));
for(i = 0 ; i < N ; i++)
array[i] = malloc( M*sizeof(int) );
return array;
}

// We don't return the pointer
void getNoReturn(int*** array, int N, int M) {
/* Check if allocation succeeded. (check for NULL pointer) */
int i;
*array = malloc(N*sizeof(int *));
for(i = 0 ; i < N ; i++)
(*array)[i] = malloc( M*sizeof(int) );
}

void fill(int** p, int N, int M) {
int i, j;
for(i = 0 ; i < N ; i++)
for(j = 0 ; j < M ; j++)
p[i][j] = j;
}

void print(int** p, int N, int M) {
int i, j;
for(i = 0 ; i < N ; i++)
for(j = 0 ; j < M ; j++)
printf("array[%d][%d] = %d\n", i, j, p[i][j]);
}

void freeArray(int** p, int N) {
int i;
for(i = 0 ; i < N ; i++)
free(p[i]);
free(p);
}

int main(void)
{
int **p;
//getNoReturn(&p, 2, 5);
p = get(2, 5);
fill(p ,2, 5);
print(p, 2, 5);
freeArray(p ,2);
return 0;
}

Pick whichever suits best your style.



Related Topics



Leave a reply



Submit