Kamath
Kamath

Reputation: 4664

Matrix as argument to a function in C

I am stuck at the very basics. It's not homework, I'm just presenting the problem in a simplistic way.

I need a matrix print function, and the matrix is passed as an argument along with row and col count information. The matrix is allocated on the stack.

In function prototype mentioned below MAT_COL is a compile time define.

void matrix_print(uint8_t (*mat)[MAT_COL], int row, int col)

and print matrix elements as

print mat[i_row][i_col];

The approach will not work if I have multiple matrix with different sizes i,e "MAT_COL" is no more available.

One possible way out would be

void matrix_print(uint8_t *in_mat, int row, int col)
{
    uint8_t (*mat)[col] = in_mat;          // typecast "col" is an arg
    // access them as eariler
    print mat[i_row][i_col];
}

Any problems with this approach ? What is the standard solution to this problem in C.

Upvotes: 0

Views: 2621

Answers (4)

42n4
42n4

Reputation: 1329

I have made an "ultimate" solution to this problem in gcc C11/C99 using these links:

http://c-faq.com/aryptr/dynmuldimary.html

http://c-faq.com/aryptr/ary2dfunc3.html

//compile with gcc --std=c11 program.c
#include <stdio.h>
#include <stdlib.h>

#define MV(array, ncolumns, i, j) array[i * ncolumns + j]
#define MX 9
#define MY 14

void input_matrix(int row, int column, double matrix[row][column]);
void print_matrix(int row, int column, double matrix[row][column]);

int main()
{
    int i=MX, j=MY;
    printf("Generate input values and print matrices with functions fn(int w, int k, double matrix[w][k]) (in C99 and C11)\n");
    double matrix1[i][j];
    input_matrix(MX,MY,matrix1);
    printf("matrix static\n");
    print_matrix(MX,MY,matrix1);

    double **matrix2;
    matrix2=malloc(MX*sizeof(double*));
    matrix2[0] = (double *)malloc(MX*MY*sizeof(double));
    for(i = 1; i < MX; i++)
        matrix2[i] = matrix2[0]+i*MY;
    input_matrix(MX,MY,(double (*)[])(*matrix2));
    printf("matrix two times allocated one for pointers, the second for data (double (*)[])(m[0])\n");
    print_matrix(MX,MY,(double (*)[])(matrix2[0]));
    free(*matrix2);
    free(matrix2);

    double *matrix3;
    matrix3=malloc(MX*MY*sizeof(double));
    input_matrix(MX,MY,(double (*)[])matrix3);
    printf("matrix alocated as twodimensional array\n");
    print_matrix(MX,MY,(double (*)[])matrix3);
    free(matrix3);

    j=MY;
    double (*matrix4)[j];
    matrix4 = (double (*)[])malloc(MX * sizeof(*matrix4));
    input_matrix(MX,MY,matrix4);
    printf("matrix alocated as an array of pointers to arrays m = (double (*)[])malloc(MX * sizeof(*m))\n");
    print_matrix(MX,MY,matrix4);
    free(matrix4);
    printf("\nThe End!\n");
    return 0;
}

void input_matrix(int row, int column, double matrix[row][column]){
    for(int i=0; i<row; i++){
        for(int j=0; j<column; j++)
            matrix[i][j]=i+1;
    }
}

void print_matrix(int row, int column, double matrix[row][column]){
    for(int i=0; i<row; i++){
        for(int j=0; j<column; j++)
            printf("%.2lf ", matrix[i][j]);
        printf("\n");
    }
}

Upvotes: 1

Johannes
Johannes

Reputation: 6707

I think you could go for a structure to help yuo with handling the type. If the type is relevant to your Design you should make it explicit.

The following is an Ansi-C Version since you wrote C/C++ as a tag. In C++ you would make your matrix a class.

typedef struct
{
    int * data;
    int IsAllocated;
    unsigned row_max;
    unsigned col_max;
} Matrix;

void Matrix_construct(Matrix * m, int cols, int rows);
void Matrix_destruct(Matrix * m, int cols, int rows);
static int Private_GetElement(Matrix * m, unsigned col, unsigned row, int * element);
void Matrix_print(Matrix * m);

void Matrix_construct(Matrix * m, int cols, int rows)
{
    m->col_max = cols;
    m->row_max = rows;
    m->data = (int*) malloc(sizeof(int) * cols * rows);
    m->IsAllocated = 1;
}

void Matrix_destruct(Matrix * m, int cols, int rows)
{
    m->col_max = 0;
    m->row_max = 0;
    if(m->IsAllocated)
    {
        free(m->data);
        m->IsAllocated = 0;
    }
}

static int Private_GetElement(Matrix * m, unsigned col, unsigned row, int * element)
{
    int e = 0;
    if(m && element && col < m->col_max && row < m->row_max && m->IsAllocated)
    {
        *element = m->data[col + row * m->col_max];
    }
    else
    {
        e |= 1;
    }
    return e;
}

void Matrix_print(Matrix * m)
{
    unsigned col, row;
    int element;
    for( col = 0; col < m->col_max; ++col)
    {
        for( row = 0; row < m->row_max; ++row)
        {
            if(!Private_GetElement(m, col, row, &element))
            {
                printf("%i", element);
            }
        }
        printf("\n");
    }
}

If you allocate different sizes in Matrix_construct the printing would still work since Matrix_print uses the maximum values that are stored in the structure.

Using different sizes would lead to changing the structure in the above example, the Matrix_print should still work as expected.


EDIT:

The example was edited to show how dynamic allocation of variable sizes would look like.

Upvotes: 0

Kirill
Kirill

Reputation: 182

C99 supports the following way of function declaration:

void matrix_print(int row, int col, uint8_t in_mat[row][col])

Upvotes: 3

tangrs
tangrs

Reputation: 9930

I corrected your typecast from an int to a uint8_t so the following should indeed work.

void matrix_print(uint8_t *in_mat, int row, int col)
{
    uint8_t (*mat)[col] = (uint8_t (*)[col])in_mat;
    // access them like mat[y][x];
}

But if you're trying to avoid typecasts where available (which may or may not be good practice), you could implement it with offsets like so

void matrix_print(uint8_t *in_mat, int row, int col)
{
    // access them like mat[x + y*col];
}

Upvotes: -1

Related Questions