0

I am trying to allocate a matrix using a function that takes its dimensions and a triple pointer. I have allocated an int** (set to NULL) and I am passing its address as the function's argument. That gives me a mem access violation for some reason.

void allocateMatrix(int ***matrix, int row, int col)
{
    int i;
    if((*matrix = (int**)malloc(row * sizeof(int*))) == NULL)
    {
        perror("There has been an error");
        exit(EXIT_FAILURE);
    }
    for(i = 0; i < row; ++i)
    {
        if((*matrix[i] = (int*)malloc(col * sizeof(int))) == NULL)
        {
            perror("There has been an error");
            exit(EXIT_FAILURE);
        }
    }
}

/* main.c */

    int** matrix = NULL;
    allocateMatrix(&matrix, MATRIX_ROW, MATRIX_COL); //error
Venom
  • 1,107
  • 4
  • 21
  • 46
  • Your structure is inefficient. Use a single array instead of an array of arrays, and access with `[y*width+x]` – Dave Apr 14 '13 at 21:43
  • @Dave I know, but the pointer arithmetic is scary enough as it is... – Venom Apr 14 '13 at 21:52
  • @Venom Wouldn't it be less scary to have just one pointer, instead of pointer to array of pointers? :) – hyde Apr 14 '13 at 21:56
  • @hyde Maybe I'll change it later on, the dimensions are small enough to prevent the inefficiency from showing. I am aware that malloc and its derivatives are quite expensive. – Venom Apr 14 '13 at 22:02

3 Answers3

3

You need to change

if((*matrix[i] = (int*)malloc(col * sizeof(int))) == NULL)

to

if(((*matrix)[i] = (int*)malloc(col * sizeof(int))) == NULL)
//  ^       ^

You need to dereference matrix before using the array subscript.
*matrix[i] is equivalent to *(matrix[i])

simonc
  • 41,632
  • 12
  • 85
  • 103
  • I don't know which one to accept now. You were the first to answer but without an explanation. This is probably trivial to you anyway :) – Venom Apr 14 '13 at 21:50
  • @Venom Glad its fixed for you. You can up-vote more than one answer as well as accepting so can recognise multiple answers if more than one helped you :-) – simonc Apr 14 '13 at 21:52
3

It's a problem of operator precedence. In

if ((*matrix[i] = (int*)malloc( ... ))

the default precedence is *(matrix[i]), while you should use (*matrix)[i].

I would still recommend to allocate the matrix as a contiguous array instead as a array of pointers to arrays.

Elmar Peise
  • 14,014
  • 3
  • 21
  • 40
1

I have made a solution program for gcc C11/C99 with apropriate allocation funtions based on links:

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

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

After some discussion in comments, it is clear that matrix2 is correctly allocated, it can be passed to this function fn(int row, int col, int array[col][row]) as matrix2[0] (data in one dimensional array) with a cast to (double (*)[])

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

#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]);
double **alloc_matrix2(int row, int column);
double  *alloc_matrix3(int row, int column);
void    *alloc_matrix4(int row, int 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; //data of matrix2 is just matrix3                 
    matrix2=alloc_matrix2(MX,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=alloc_matrix3(MX,MY);
    input_matrix(MX,MY,(double (*)[])matrix3);
    printf("matrix allocated as two-dimensional array\n");
    print_matrix(MX,MY,(double (*)[])matrix3);
    free(matrix3);

    j=MY;
    double (*matrix4)[j];
    matrix4 = (double (*)[])alloc_matrix4(MX,MY);
    input_matrix(MX,MY,matrix4);
    printf("matrix allocated via pointer to array 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");
    }
}

double **alloc_matrix2(int row, int column){
    double **matrix;
    matrix=malloc(row*sizeof(double*));
    matrix[0] = (double *)malloc(row*column*sizeof(double));
    for(int i = 1; i < row; i++)
        matrix[i] = matrix[0]+i*column;
    return matrix;
}

double *alloc_matrix3(int row, int column){
    double *matrix;
    matrix=malloc(row*column*sizeof(double));
    return matrix;
}

void *alloc_matrix4(int row, int column){
    double (*matrix)[column];
    matrix = (double (*)[])malloc(row*sizeof(*matrix));
    return matrix;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
42n4
  • 1,292
  • 22
  • 26
  • The `matrix2` version causes undefined behaviour (`T **` is not the same as `T (*)[n]`). Hiding the compiler error behind a cast doesn't fix anything. – M.M Dec 13 '14 at 09:49
  • matrix3 and marix4, the code is OK (it has unnecessary casts that can be removed) but the comments are wrong. `matrix4` is allocated via pointer to array (not array of pointers to arrays). – M.M Dec 13 '14 at 09:51
  • @Matt McNabb: I add some new comments. Could you explain why matrix4 is just made via pointer to an array, and not the array of MX dimension? And matrix2 solution is just working: it is just the same as matrix3 but with an additional array of pointers. Data of matrix2 is in one-dimensional array. – 42n4 Dec 13 '14 at 09:58
  • Matrix2 doesn't work, youhave a jagged array allocated correctly, but it cannot be passed to function expecting contiguous memory bloc. The input_matrix function will scribble over unallocated memory on the end of the first row (and the print_matrix function reads the same memory). In matrix4 you allocate an array, each of whose elements is another array. Returned is a pointer to the first element of the outer array. – M.M Dec 13 '14 at 10:04
  • @Matt McNabb: So this site solution http://c-faq.com/aryptr/dynmuldimary.html is correct. They used such a design of the pointer array http://c-faq.com/aryptr/array2.gif. But is it possible for print_matrix to read unallocated memory? How to prove it in a code? – 42n4 Dec 13 '14 at 10:08
  • you can't prove undefined behaviour, have to read the C standard or other posts on the topic. Try running your prog under valgrind tho – M.M Dec 13 '14 at 11:13
  • @Matt McNabb: I have run valgrind-svn (gcc 4.9.2) and no problem was reported. All 4 allocs were made free. – 42n4 Dec 13 '14 at 11:46
  • the current version of matrix2 is OK (maybe I misread it earlier). You are passing `matrix2[0]` which is pointer to contiguous block, unlike the other examples where you pass `matrixN`. – M.M Dec 13 '14 at 11:59
  • @Matt McNabb: Thank you for your validation of my code! – 42n4 Dec 13 '14 at 12:26