0

I have the following function :

int** myfunc() {
   int array[2][2];

   // operation on the array

   return array;
}

And the following error from the compiler :

 cannot convert 'int (*)[2]' to 'int**' in return

So my question is : how can I return my array ?

Lucas Willems
  • 6,673
  • 4
  • 28
  • 45
  • The clue is in the error: `cannot convert 'int (*)[2]' to 'int**' in return`... **int (*)[2]** – OMGtechy Apr 06 '14 at 09:40
  • Yes. I understand where I'm wrong. But I don't know what should be the type of the function return. – Lucas Willems Apr 06 '14 at 09:42
  • Try changing your return type to `int *` – OMGtechy Apr 06 '14 at 09:43
  • Also, make sure you use `new` when allocating your array, otherwise it'll go out of scope as soon as the function ends. – OMGtechy Apr 06 '14 at 09:44
  • 1
    @OMGtechy: the question is tagged `c`, not `c++`. C doesn't have `new`. – DCoder Apr 06 '14 at 09:46
  • (1) You cannot return an array from a function, you can only return a pointer, and that pointer cannot point to a function's local variable. (2) `int[2][2]` is not `int**`, they are not related in any way, they cannot be converted to each other, there is no reason on earth why it would be a valid idea to even consider such a possibility. – n. m. could be an AI Apr 06 '14 at 09:50
  • @DCoder sorry, missed that – OMGtechy Apr 06 '14 at 10:02

4 Answers4

4

So my question is : how can I return my array ?

You cannot. The array named array has function scope and goes out of scope when the function myfunc returns. This means the array no longer exists and trying to access it will invoke undefined behaviour. Also, the return type of myfunc is int **. In the return statement

 return array;

the array named array is implicitly converted to a pointer to its element. int array[2][2]; defines array to be an array of 2 elements of type int[2], i.e., an array of 2 integers. Therefore, array in the return statement is implicitly converted to type int (*)[2], i.e., a pointer to an array of 2 integers. This explains the error message.

If you want to return an array from a function, you should allocate it dynamically using malloc which should later be freed in the caller after its use.

// you should change function signature to take the array size.
// and change return type to (int *) to return a pointer to the
// first element of the dynamically allocated array 
int *myfunc(int len) {
   int *array = malloc(len * sizeof *array);
   if(array == NULL) {
       printf("error in memory allocation\n");
       return NULL;
       // handle it
   }

   // operation on the array

   return array;
}

Please note that an array type object is a contiguously allocated nonempty set of objects with a particular member object type, called the element type. Therefore, a 2-D array is not a new type. It's just an array type where the elements of the array are themselves arrays. This mean we have the following equivalence -

// an automatic array of 200 elements allocated on the stack
int auto_array[10][20]; 

// a dynamic array of 200 elements allocated on the heap
int *dynamic_array = malloc((10 * 20) * sizeof *array); 

printf("%d\n", auto_array[4][8];)  // prints element in the 5th row, 9th column
printf("%d\n", dynamic_array[4*10 + 8]);  // prints element in the 5th row, 9th column
ajay
  • 9,402
  • 8
  • 44
  • 71
1

This only fixes the compiler error

The compiler is already giving you the correct type to return, you just need to give the type a name to return it easily:

typedef int (*myArrayPtr)[2];

myArrayPtr myFunc() {
    int foo[2][2];
    return foo;    //Compiles, BUT DON'T USE IT (see below)
}

Alternatively, you can write the function declaration like this (but please don't, this should only be done in code that tries to win the International Obfuscated C Code Contest):

int (*myFunc())[2] {
    int foo[2][2];
    return foo;    //Compiles, BUT DON'T USE IT (see below)
}

This approach actually works

The code above returns a pointer to a local variable, which is automatically deallocated when myFunc() returns. If the calling function uses the returned pointer in any way, anything might happen. To return a 2D array correctly, you need to malloc() it:

typedef int myArray[2];

myArray* myFunc() {
    myArray* foo = malloc(2*sizeof(*foo));
    foo[1][1] = 7;
    return foo;
}

Note, that one of the two dimensions is encoded in the array type, while the other one is implicit in the pointer. That is why the sizeof of *foo must be multiplied by the size of the first dimension. Of course, you can also encode both dimensions in the array type, but that requires you to write an additional dereference when you access its elements:

typedef int myArray[2][2];

myArray* myFunc() {
    myArray* foo = malloc(sizeof(*foo));
    (*foo)[1][1] = 7;
    return foo;
}
cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
0

Arrays and pointers, while deceptively similar, are not the same thing in C.

You're trying to return a local variable, memory for which is allocated on the stack. The local variable will be popped off the stack as soon as your function exits, which is why most compilers give you a warning when you try to return the address of a local variable. The returned address points to a value that is gone.

What you need to do, is declare an int** & return it. You can allocate memory dynamically using malloc() present in the malloc.h header. Something like the following should work.

#include <stdio.h>
#include <malloc.h>

int** myfunc()
{
    // Allocate memory so array can hold two int *
    int** array = malloc(sizeof(int *) * 2);

    // Allocate memory for each of the pointers that the array holds
    // We want to reserve space for two integers in each slot.
    array[0] = malloc(sizeof(int) * 2);
    array[1] = malloc(sizeof(int) * 2);

    array[0][0] = 0;
    array[0][1] = 1;
    array[1][0] = 2;
    array[1][1] = 3;

    return array;
}

int main(void)
{
    int i, j;
    int **x;
    x = myfunc();

    for (i = 0; i < 2; ++i) {
        for (j = 0; j < 2; ++j) {
            printf("%d", x[i][j]);
        }
    }

    return 0;
}

Don't forget to free() the contents of the array when you're done with it.

Prajjwal
  • 1,055
  • 2
  • 10
  • 17
  • 2
    The problem with this is that it does not guarantee that the allocated blocks are contiguous and ordered in memory, so it is semantically different that a two dimensional array. The simple solution to that is to allocate a single `int* block = malloc(sizeof(int) * 2 * 2)`, then assign `array[i] = &block[i * 2]` rather than allocating each block separately. It is more memory efficient too. – Clifford Apr 06 '14 at 10:22
0

Arrays are not first-class data types in C, you cannot return an array by copy, and returning a reference to a local variable will have undefined behaviour (and is never good).

There are three ways (at least) to do what you are attempting. The most usual (not to mention safe and efficient) is to have the caller own the array, then pass the array into the function by reference and have the function operate on the provided array:

void myFunc( int array[2][2] )
{
    // operate directly on caller's array
}

The second method is to wrap the array in a struct, which is a first-class data type and can be exchanged by copy or reference. Note for large structures, exchange by copy can become expensive computationally.

typedef struct
{
    int array[2][2] ;
} array_container ;

array_container myFunc()
{
    array_container contained_array ;

    return contained_array ;
}

Dynamically allocating the array within the function is a possibility, but leaves the question of who is responsible for freeing the memory and how and when it is safe to do so. However although I would not recommend it:

#define ARRAY_DIM1 2
#define ARRAY_DIM2 2

int** myfunc()
{
    int** array = malloc( sizeof(int*) * ARRAY_DIM1 ) ;
    int* array_memory = malloc( sizeof(int) * ARRAY_DIM1 * ARRAY_DIM2 ) ;
    int i = 0 ;

    for( i = 0; i < ARRAY_DIM1; i++ )
    {
        array[i] = array_memory[i * ARRAY_DIM2]
    }

    return array;
}
Clifford
  • 88,407
  • 13
  • 85
  • 165