Sheikh Abdullah
Sheikh Abdullah

Reputation: 55

Return a 2D array of user-given size

I want to create a function that

  1. takes the row and column as arguments.

  2. takes inputs according to the given size and

  3. returns the 2D matrix/array.

I've gone through lots of solutions online, but everything I try, gives me some new errors.

int* input_taker(int row, int col)
{
    int mat[row][col];
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            scanf("%d", &mat[i][j]);
        }
    }
    return mat;
}

Upvotes: 1

Views: 558

Answers (4)

user16455232
user16455232

Reputation:

2D array of user-given size

and

pointer to an array of col integers.

both seem to avoid the term VLA. 4386's answer gives the "C90 forbids VLA" warning with -Wvla.

This

int mat[row][col];

dose not work because it is auto storage.

But

int (*mat)[col];

is only a pointer to a VLA; it can be malloced and returned.

To (over-)simplify 4386's function type and to split the definition of mat this can be done:

void *array_maker(int row, int col)   // just a pointer; no dimensions, no type
{
    int (*mat)[col];                  // declare runtime inner dim.: ptr to VLA  
    mat = malloc(row * sizeof *mat);  // mallocate both dims

    for (int i = 0; i < row; i++)
    for (int j = 0; j < col; j++)
            mat[i][j] = i*col + j;    // fill the array[][] 
    return mat;
}

The call from main is:

int col, row;

int (*p)[col=8];                  // ptr. to VLA  
p = array_maker(row=5, col);      // implicit cast from void-ptr 

Since a VLA is involved anyway, one might turn it around and put the array pointer into a param. This turns the function from array-maker to array-filler:

void array_filler(int row, int col, int mat[][col])
{
    for (int i = 0; i < row; i++)
    for (int j = 0; j < col; j++)
            mat[i][j] = i*col + j;    // fill the array[][] 
}

Now the array has to be allocated by the caller - either as auto-VLA or malloced VLA-pointer or fixed-size array:

col=row=9;
int mat[row][col];  
//int (*mat)[col] = malloc(row * sizeof*mat); 
//int mat[9][9];
array_filler(row, col, mat);

int mat[row][col]; wrong storage duration

int* input_taker(int row, int col) -> incompatible type warning

Upvotes: 2

4386427
4386427

Reputation: 44340

  1. The function return type is int* but you are trying to return mat which has a different type (i.e int* (*)[col]) so that's a bug.

  2. mat is a function local variable so it doesn't exists once the function returns. In other words - returning mat makes no sense at all. You are returning a reference to a "dead" object.

Instead you need to use dynamic allocation in the function so that the returned object still exist after function return.

For this you can define mat as a pointer to an array of col integers. Further, the function shall return a pointer to an array of integers.

Like:

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

int (* input_taker(int row, int col))[]
{
    int (*mat)[col] = malloc(row * sizeof *mat);
    if (mat == NULL) exit(1);
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            mat[i][j] = i*col + j;  // Here you can read user input
        }
    }
    return mat;
}

int main ()
{
    int col = 8;
    int row = 5;
    int (* p)[col] = input_taker(row, col);
    for (int i=0; i<row; ++i)
    {
        for (int j=0; j<col; ++j)
        {
            printf("%5d ", p[i][j]);
        }
        puts("");
    }
    free(p);
    return 0;
}

Output

    0     1     2     3     4     5     6     7 
    8     9    10    11    12    13    14    15 
   16    17    18    19    20    21    22    23 
   24    25    26    27    28    29    30    31 
   32    33    34    35    36    37    38    39 

Upvotes: 4

Costantino Grana
Costantino Grana

Reputation: 3468

Other answers used VLAs as in your original question. The point is that I don't think VLAs are the way to go for matrices, since it's not unlikely to have the same variable change size during execution, and this requires a murky design with VLAs.

If you renounce to the double square brackets syntax, using a simple pointer is pretty straigthforward (I'm adapting 4386427 code for this):

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

int *input_taker(int row, int col)
{
    int *mat = malloc(row * col * sizeof *mat);
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            mat[i * col + j] = i * col + j;  // Here you can read user input
        }
    }
    return mat;
}

int main ()
{
    int col = 8;
    int row = 5;
    int *p = input_taker(row, col);
    for (int i = 0; i < row; ++i) {
        for (int j = 0; j < col; ++j) {
            printf("%5d ", p[i * col + j]);
        }
        puts("");
    }
    free(p);
    return 0;
}

Even better pack everything in a struct:

struct mat {
    int rows, cols;
    int *data;
};

and provide functions to use it.

Upvotes: 2

Vasconcelos
Vasconcelos

Reputation: 310

Your problem appears to be a dangling pointer. You have to allocate memory before calling input_taker.

#include <cstdio>
#include <cstdlib>

int* input_taker(int *ptr, int row, int col)
{
    for (int i = 0; i < row; i++)
    {
        int *arr = &ptr[i*col];
        for (int j = 0; j < col; j++)
        {
            scanf("%d", &arr[j]);
        }
    }
    return ptr;
}

int main() {
    int n_rows, n_cols;
    n_rows = 2;
    n_cols = 3;
//    int *matrix = (int*)malloc(n_rows*n_cols*sizeof(int));
    int matrix [n_rows][n_cols];
    input_taker(&matrix[0][0], n_rows, n_cols);

    for (int i = 0; i < n_rows; i++)
    {
        printf("[");
        for (int j = 0; j < n_cols; j++)
        {
            j==n_cols-1?printf("%d]\n", matrix[i][j]):printf("%d, ", matrix[i][j]);
        }
    }
    return 0;
}

I changed the function parameters but kept the return value. You may, however, return void.

Upvotes: 1

Related Questions