Returning multidimensional arrays from a function in C

What is the best way to return a multidimensional array from a function in c?

Let's say we need to create a multidimensional array in a function and call it basically, is it better to wrap it in a structure 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 a sketch of the main program that I have in mind.

+4
source share
4 answers

It is not right:

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

and should trigger 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 ends.


main(), , . main() .


, :

#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;
}

, .

+3

c?

- C ( ).

, struct, :

struct mymatrix_st {
  unsigned nbrows, nbcolumns;
  int values[];
};

( ):

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*/

struct mymatrix_st . free, .

; static inline , struct mymatrix_st create_matrix, .

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];
}

struct mymatrix_st.

( , , , )

+2
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;
}

. int array[rows][columns];, , , UB. .

0

, , , .

( , , - !)

, , , :

#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 multidimensional array. A true multi-d array is one continuous block, while an array of pointers (although used with the same indexing syntax) has a much worse link locality, so this may be preferable to returning pointers to pointers if you want to improve performance.

0
source

Source: https://habr.com/ru/post/1682595/


All Articles