This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 6 years ago.
I'm trying to create a function that concatenates 2 arrays and then returns the sum array back.
I've been using the following code:
#include "stdio.h";
struct array {
int length;
int *array;
};
struct array add(struct array a, struct array b) {
int length = a.length + b.length;
int sum[length];
for (int i = 0; i < length; ++i) {
if (i < a.length) {
sum[i] = a.array[i];
} else {
sum[i] = b.array[i - a.length];
}
}
struct array c;
c.length = length;
c.array = sum;
return c;
}
int main() {
int a[] = {1, 2, 3};
struct array s1;
s1.array = a;
s1.length = sizeof(a) / sizeof(a[0]);
int b[] = {4, 5, 6};
struct array s2;
s2.array = b;
s2.length = sizeof(b) / sizeof(b[0]);
struct array sum = add(s1, s2);
for (int i = 0; i < sum.length; ++i) {
printf("%d\n", sum.array[i]);
}
return 0;
}
The output is:
1,
17,
6356568,
1959414740,
1,
1959661600
What am I doing wrong?
These three lines are very problematic:
int sum[length];
...
c.array = sum;
return c;
In the first you declare the local variable sum. In the second you make c.array point to the local variable. And in the third line you return the pointer while the local variable goes out of scope.
Since the local variable goes out of scope it no longer exists, and the pointer to it is no longer valid. Using the pointer will lead to undefined behavior.
To solve this you need to allocate memory dynamically with e.g. malloc.
sum is a local variable to the add function. When you set c.array = sum;, then the pointer c.array points to this local variable.
After the function returns, local variables are destroyed. So this pointer is now a dangling pointer. But in main you then read through this pointer.
To fix this you'll need to make a fundamental change to the design of your program. For example, use dynamic allocation in all cases for a struct array.
Arrays in C simply are a contiguous area of memory, with a pointer to their start*. So merging them involves:
Find the length of the arrays A and B, (you will probably need to know the number of elements and the sizeof each element)
Allocating (malloc) a new array C that is the size of A + B.
Copy (memcpy) the memory from A to C,
Copy the memory from B to C + the length of A (see 1).
You might want also to de-allocate (free) the memory of A and B.
Example code snippet:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define ARRAY_CONCAT(TYPE, A, An, B, Bn) \
(TYPE *)array_concat((const void *)(A), (An), (const void *)(B), (Bn), sizeof(TYPE));
void *array_concat(const void *a, size_t an,const void *b, size_t bn, size_t s)
{
char *p = malloc(s * (an + bn));
memcpy(p, a, an*s);
memcpy(p + an*s, b, bn*s);
return p;
}
// testing
const int a[] = { 1, 1, 1, 1 };
const int b[] = { 2, 2, 2, 2 };
int main(void)
{
unsigned int i;
int *total = ARRAY_CONCAT(int, a, 4, b, 4);
for(i = 0; i < 8; i++)
printf("%d\n", total[i]);
free(total);
return EXIT_SUCCCESS;
}
Try this - corrected add function:
#include <stdlib.h>
struct array add(struct array a, struct array b) {
int length = a.length + b.length;
int * sum = (int*)calloc(length, sizeof(int));
for (int i = 0; i < length; ++i) {
if (i < a.length) {
sum[i] = a.array[i];
}
else {
sum[i] = b.array[i - a.length];
}
}
struct array c;
c.length = length;
c.array = sum;
return c;
}
stdlib is required to use calloc function.
That function allocate memory for length values of int type. To be sure that memory is allocated successfully, it is recommended to check value of pointer sum after allocation, e.g.:
int * sum = (int*)calloc(length, sizeof(int));
if( sum != NULL )
{
// use memory and return result
}
else
{
// do not use pointer (report about error and stop operation)
}
As Joachim mentioned, you are returning a local variable int sum[length]; This is a bad idea. The variable sum is returned to the stack after the function exits and can be overwritten by other stack variables.
One of the ways around that is to not declare an array inside the sum function in the first place. The sum_str is declared in main. You can pass the pointer to this structure to the sum function.
The updated code is below.
#include <stdio.h>
struct array {
int length;
int *array;
};
void add(struct array a, struct array b, struct array *sum_str) {
sum_str->length = a.length + b.length;
for (int i = 0; i < sum_str->length; ++i) {
if (i < a.length) {
sum_str->array[i] = a.array[i];
} else {
sum_str->array[i] = b.array[i - a.length];
}
}
}
int main() {
int a[] = {1, 2, 3};
struct array s1;
s1.array = a;
s1.length = sizeof(a) / sizeof(a[0]);
int b[] = {4, 5, 6};
struct array s2;
s2.array = b;
s2.length = sizeof(b) / sizeof(b[0]);
struct array sum_str;
int sum_a[6];
sum_str.array = sum_a;
add(s1, s2, &sum_str);
for (int i = 0; i < sum_str.length; ++i) {
printf("%d\n", sum_str.array[i]);
}
return 0;
}
Another way is to use dynamic memory allocation as described by other answers.
Related
How can I return an array from a function, I am trying to perform (3*3)*(3*1) matrix multiplication using this translation function and how can i get an array out of it.
#include <stdio.h>
#include <math.h>
int* translation(int x, int y, int tx, int ty) {
static int res[3][1] = {0}, xy[3][1] = {{x},{y},{1}};
int tm[3][3] = {{1,0, tx}, {0,1,ty}, {0,0,1}};
for (int i = 0; i<3; i++) {
for (int j = 0; j<3; j++) {
res[i][0] += tm[i][j]*xy[j][0];
}
}
return res;
}
int main()
{
int *arr[3][1];
arr = translation(5, 5);
printf("%d %d %d", arr[0][0], arr[0][1], arr[0][2]);
return 0;
}
"How can I return an array from a function"
You can't.
The language has no such concept.
You'll have to return something including the length to give the user of the function the information. In C the idiomatic approach is to supply a pointer to the function and to get a value (via that pointer) in return:
size_t no_idea;
void function(void *data, &no_idea);
As a user of this function you'd have to read no_idea before judging.
you question is missing a lot of information like what you want to do with your code, the variable named xy isn't defined anywhere in your code, and so on...
but for clarification, if your result matrix is of unknown size, you can wrap your array into a struct, if you don't know what is the struct, you can refer to this small tutorial about struct in c, so your struct maybe look like something like this:
typedef struct Array_t{
size_t arrSize_x;
size_t arrSize_y;
int **arr;
}Array_t;
where arr is your matrix of unknown size which will be created dynamically and arrSize_x, arrSize_y are your matrix dimensions.
so in order to create a matrix of unknow size at compile time , you should create it dynamically in the heap memory using functions like calloc or malloc, although in C99, it allowed created arrays statically of unknown size during compile time but it's not the case with struct as the struct once defined, your array is created and you cannot do something like this:
typedef struct Array_t{
size_t arrSize_x;
size_t arrSize_y;
int arr[arrSize_x][arrSize_y];
}Array_t;
but if the size of the array is known you can do something like this:
typedef struct Array_t{
int arr[3][1];
}Array_t;
to create a dynamic array, you will find in the next example code something like this:
// rows are stored in heap memory and initiated with zeros
res.arr = (int**) calloc(res.arrSize_x, sizeof(int));
// columns are also stored in heap memory and initiated with zeros
for (int i = 0; i < res.arrSize_x; ++i) {
res.arr[i] = (int *) calloc(res.arrSize_y, sizeof(int));
}
where res.arr is a pointer pointing to an array of pointers and the next diagram may simplify my explanation where the next graph expresses the created matrix in heap memory for arr of size 3 x 1:
while if the size is known, so the explanation diagram may look like this:
and when you return, you can either return by value or by reference, but if you are going to return a struct by reference then you should declare it as static.
so you can do something like this (for clarification purposes, size of matrix is unknown):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct Array_t{
size_t arrSize_x;
size_t arrSize_y;
int **arr;
}Array_t;
Array_t translation(int x, int y, int tx, int ty) {
// create a struct holding the array
Array_t res;
res.arrSize_x = 3;
res.arrSize_y = 1;
// rows are stored in heap memory and initiated with zeros
res.arr = (int**) calloc(res.arrSize_x, sizeof(int));
// columns are also stored in heap memory and initiated with zeros
for (int i = 0; i < res.arrSize_x; ++i) {
res.arr[i] = (int *) calloc(res.arrSize_y, sizeof(int));
}
res.arr[0][0] = 1;
res.arr[1][0] = 2;
res.arr[2][0] = 3;
return res;
}
int main()
{
Array_t array;
// 1, 2, 3, 4 are dummy parameters
array = translation(1, 2, 3, 4);
printf("elements are :\n");
for (int i = 0; i < array.arrSize_x; ++i) {
for (int j = 0; j < array.arrSize_y; ++j) {
printf("%d\t", array.arr[i][j]);
}
printf("\n");
}
return 0;
}
and this is the output:
elements are :
1
2
3
but if size of matrix is known then you can do something like this (for clarification purposes, size of matrix is known):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct Array_t{
int arr[3][1];
}Array_t;
Array_t translation(int x, int y, int tx, int ty) {
// create a struct holding the array
Array_t res;
res.arr[0][0] = 1;
res.arr[1][0] = 2;
res.arr[2][0] = 3;
return res;
}
int main()
{
Array_t array;
// 1, 2, 3, 4 are dummy parameters
array = translation(1, 2, 3, 4);
printf("elements are :\n");
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 1; ++j) {
printf("%d\t", array.arr[i][j]);
}
printf("\n");
}
return 0;
}
and this is the ouput:
elements are :
1
2
3
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X** a, int size){
for (int i = 0;i < size; i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container = (struct X*)malloc(sizeof(struct X) * n);
read_record(&container, n);
}
I created a 1D array of size n, then I passed it by reference to the function read_record. However, when I execute the program, there is a segmentation fault. What is the problem?
EDIT:
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. That's why I want to send the array as a reference. If I did it in main then I would write:
container = realloc(container, (n + 10) * sizeof(Struct X));
How can I do this in the function?
container is already a pointer, you don't need to pass the address-of the pointer, instead:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
void read_record(struct X *a, size_t size)
{
for (size_t i = 0; i < size; i++) {
a[i].deg = 0;
}
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
read_record(container, n);
}
also, prefer size_t to store the number of allocated objects.
Nitpick: read_record doesn't seem a good name for a function that modifies the contents of the records.
EDIT: As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
Same approach but returning a reallocated container:
#include <stdio.h>
#include <stdlib.h>
struct X {
char surname[30];
int deg;
};
struct X *read_record(struct X *a, size_t size)
{
struct X *new = realloc(a, sizeof(struct X) * size);
if (new != NULL)
{
for (size_t i = 0; i < size; i++) {
new[i].deg = 0;
}
}
return new;
}
int main(void)
{
size_t n = 10;
struct X *container = malloc(sizeof(struct X) * n);
container = read_record(container, n * 2);
if (container == NULL)
{
fprintf(stderr, "Can't read record\n");
exit(EXIT_FAILURE);
}
}
As a next step, I want to reallocate the array of 10 elements in the function with size of 20. (in the function). That's why I want to send the array as a reference.
The pointer is passed by value, so to save the changes and have them usable outside the function scope, after the function ends, i.e. in main, a pointer to pointer must be the argument, and the address of the pointer must be passed, your overall assessment is correct.
Your implementation, however, is not correct, here's how you shoud do it:
Live demo
void read_record(struct X **a, int size) //double pointer
{
*a = realloc(*a, sizeof **a * (size + 10)); //reallocate memory for 20 ints
if (*a == NULL)
{
perror("malloc");
}
for (int i = 0; i < size + 10; i++) //assing new values
{
(*a)[i].deg = 1;
}
}
int main()
{
int n = 10;
struct X *container = malloc(sizeof *container * n); //original allocation
//the pointer now has space for 10 ints
if (container == NULL)
{ //check allocation errors
perror("malloc");
}
for (int i = 0; i < n; i++) //assign values
{
container[i].deg = 0;
}
read_record(&container, n); //pass by reference
//the pointer now has space for 20 ints
}
Alternatively you can return the pointer instead, refering to David Ranieri's answer.
The first function parameter has the pointer to pointer type struct X**. So dereferencing the parameter a you will get a pointer of the type struct X*. Now you may apply the subscript operator that yields lvalue of the type struct X..
That is the function definition will look like
void read_record(struct X** a,int size){
for (int i=0;i<size;i++){
( *a )[i].deg = 0;
}
}
Or this statement
( *a )[i].deg = 0;
may be substituted for this statement
a[0][i].deg = 0;
On the other hand, there is no great sense to declare the first parameter as having the type struct X**. The function can look simpler as for example
void read_record(struct X* a,int size){
for (int i=0;i<size;i++){
a[i].deg = 0;
}
}
and be called like
read_record( container, n );
When you call read_record you pass a pointer to a pointer to the first element of an array of X structures.
But inside the read_record you treat it as a pointer to the first element of an array of pointers to X structures (i.e. as an array of pointers to X). There's a subtle but very important difference here.
If you want to emulate pass-by-reference for the pointer variable, you need to dereference it inside the read_record to get the original pointer (and remember that then you have an array of objects, not pointers):
(*a)[i].deg = 0;
Double pointer is the problem. The code should be:
void read_record(struct X* a,int size){ // Check the change
for (int i=0;i<size;i++){
a[i]->deg = 0;
}
}
int main(){
int n = 10;
struct X *container=(struct X*)malloc(sizeof(struct X)*n);
read_record(container,n); // Check the change
}
I have been trying to pass my array address to print array values in main function. But it is not working as it gives "Count by X.exe has stopped working". It also shows a warning message which says "function is returning address of local variables". I am not able to find the problems. It would be helpful if anyone finds pointer related problem of my code which is given below.
#include<stdio.h>
int * countBy(int x, int n)
{
int arr[n];
int count = x;
for(int i = 0; i < n; i++)
{
arr[i] = count;
count = count + x;
}
return arr;
}
int main()
{
int x = 2, n = 10;
int * prr;
prr = countBy(x, n);
for(int i = 0; i < 10; i++)
{
printf("%d ", prr[i]);
}
return 0;
}
You cannot return arrays in C. You would either need to create the array in the main function and pass it to the function or use dynamic allocation.
Passing an output array:
void countBy(int x, int n, int *arr)
{
int count = x;
for(int i = 0; i < n; i++) {
arr[i] = count;
count = count + x;
}
}
int main(void)
{
int x = 2, n = 10;
int arr[n];
countBy(x, n, arr);
}
Dynamic allocation:
int * countBy(int x, int n)
{
int *arr = malloc(n * sizeof(*arr));
int count = x;
for(int i = 0; i < n; i++) {
arr[i] = count;
count = count + x;
}
return arr;
}
int main(void)
{
int x = 2, n = 10;
int *prr;
prr = countBy(x, n);
free(prr); // Remember to use free to not cause memory leaks
}
The local variables have a lifetime which extends only inside the block in which it is defined. The moment the control goes outside the block in which the local variable is defined, the storage for the variable is no more allocated (not guaranteed). Therefore, using the memory address of the variable outside the lifetime area of the variable will be undefined behaviour.
On the other hand you can do the following, replace the int arr[n] with a static array but the size of the array must be declared.
...
static int arr[10];
...
This will fix the problem but you couldnt change the size of the array if the user inputs the wanted size of it.
Let's say I have to create an array of structs that is allocated on the heap and return a pointer that points to this array of structs.
typedef struct Pair {
int x;
int y;
} Pair;
Pair** foo(int n, int m, int length)
{
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return &arr;
}
When I compile a program containing this function, it warns me that I am returning the address of a local variable. I assume this is because the pointer is initialised within the function (i.e. on the stack), therefore it counts as a local variable.
When I compile it, ignoring this warning, and run it anyway, the program crashes when the returned pointer is accessed.
I have tried allocating the pointer dynamically:
Pair** ptr = malloc(sizeof(**ptr));
ptr = &arr;
...
return ptr;
but the program still crashes when this pointer is accessed. How can I create this array within a function and return a pointer to this array so that it can be safely accessed?
This array is initialized on the stack but the pointer (arr) is a local variable, so the caller, main, cannot access it. You do not need to use the address of the pointer. You can access the array with the pointer itself.
Pair* foo(int n, int m, int length)
{
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return arr;
}
If you want an array of structs, the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x;
int y;
} Pair;
static Pair* foo(int n, int m, int length) {
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return arr;
}
int main(void) {
Pair *z = foo(111, 222, 3);
for (int i = 0; i < 3; ++i)
printf("z[%d]= { %d, %d }\n", i, z[i].x, z[i].y);
free(z);
return 0;
}
gives the output:
z[0]= { 111, 222 }
z[1]= { 112, 223 }
z[2]= { 113, 224 }
If you want an pointer to an array of structs, you can change your function signature from Pair** to be Pair*.
If you still want an pointer to an array of pointers, then allocate memory for a Pair struct for each index of arr.
for(int i = 0; i < length; ++i){
arr[i] = malloc(sizeof(Pair));
...
}
Instead of returning &arr, you can declare arr as
Pair** arr = malloc(sizeof(Pair*) * length);
Because arr is a local variable, it will be free when foo end. So you don't have access for arr after. To solve this you should declare array pointer in heap:
Pair** foo(int n, int m, int length)
{
Pair ** arr = (Pair**)malloc(sizeof(Pair*));
*arr = malloc(sizeof(Pair) * length);
for (int i = 0; i < length; ++i) {
(*arr)[i].x = n++;
(*arr)[i].y = m++;
}
return arr;
}
What is the best way to return a multidimensional array from a function in c ?
Say we need to generate a multidimensional array in a function and call it in main, is it best to wrap it in a struct or just return a pointer to memory on the heap ?
int *create_array(int rows, int columns){
int array[rows][columns] = {0};
return array;
}
int main(){
int row = 10;
int columns = 2;
create_array(row,columns);
}
The code above, is just to sketch out the basic program I have in mind.
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.
What is the best way to return a multidimensional array from a function in c ?
My recommendation is to avoid doing that, and avoid multidimensional arrays in C (they are unreadable and troublesome).
I would recommend making your matrix type your proper abstract data type, represented by some struct ending with a flexible array member:
struct mymatrix_st {
unsigned nbrows, nbcolumns;
int values[];
};
Here is the creation function (returning a properly initialized pointer to dynamic memory):
struct mymatrix_st*
create_matrix(unsigned mnbrows, unsigned mnbcolumns) {
if (mnbrows > UINT_MAX/4 || mnbcolumns > UINT_MAX/4
||(unsigned long)mnbrows * (unsigned long)mnbcolums
> UINT_MAX) {
fprintf(stderr, "too big matrix\n");
exit(EXIT_FAILURE);
};
size_t sz = sizeof(struct mymatrix_st)+(mnbrows*mnbcolumns*sizeof(int));
struct mymatrix_st*m = malloc(sz);
if (!m) {
perror("malloc mymatrix"); exit(EXIT_FAILURE); };
m->nbrows = mnbrows;
m->nbcolumns = mnbcolumns;
for (unsigned long ix=(unsigned long)mnbrows * (unsigned long)mnbcolumns-1;
ix>=0; ix--)
m->values[ix] = 0;
return m;;
} /*end create_matrix*/
It is on purpose that struct mymatrix_st don't contain any interior pointer. You can and should use free to destroy it.
Here is the accessor function; make it a static inline function and define it in the same header declaring struct mymatrix_st and create_matrix, e.g.
static inline int getmatrix(struct mymatrix_st*m, unsigned row, unsigned col) {
if (!m) {
fprintf(stderr, "getmatrix with no matrix\n");
exit(EXIT_FAILURE);
};
if (row >= m->nbrows || col >= m->nbcolumns){
fprintf(stderr, "getmatrix out of bounds\n");
exit(EXIT_FAILURE);
};
return m->values[row*m->nbcolumns + col];
}
I leave up to you to define and implement the other operations on your abstract struct mymatrix_st type.
(you could adapt the code, perhaps removing the out of bound check, but I don't recommend unsafe code)
int** create_array(int rows, int columns){
int** array = malloc(rows * sizeof(int*));
int i;
for (i=0; i<rows; i++)
array[i] = malloc(columns * sizeof(int));
return array;
}
should do the trick. If you use int array[rows][columns]; then it's dead as soon as the functiom returns, and you get a UB. You should at least use dynamic memory allocation.
You can't return an array, but you can return a regular pointer and document that the callee may treat it as a pointer to a multidimensional array of the dimensions that it had passed to the caller.
(Note that the returned pointer must point to dynamic or static, but not automatic memory--don't return pointers to local variables!)
It takes some slightly wordy casts and possibly a macro but it's doable:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void*
multi(int R, int C)
{
return calloc ( 1, sizeof(int[R][C]) ); //or sizeof(int)*R*C
}
int main()
{
int (*r_)[3][4] = multi(3,4);
if(!r_) return EXIT_FAILURE;
#define r (*r_)
//emulate C++ a reference -- r now behaves as an `int r[3][4];`
//Test that addresses advance as they would in a multi-d array
int local[3][4];
assert(&local[1][0]-&local[0][0] == 4); //base example
assert(&r[1][0]-&r[0][0] == 4); //"returned" multi-d array
free(r); //or free(&r) or free(r_) -- here it shouldn't matter
#undef r
return 0;
}
Note that an array of pointers is not the same thing as a multi-d array.
A true multi-d array is one contiguous block, whereas an array of pointers (though usable with the same indexing syntax) has much worse locality of reference, so this might be preferable over returning pointers to pointers if you want better performance.