3

I have the following:

struct matrix {
    int h;
    int w;
    int** data;
};

int m1[2][2] = {
    {1, 2},
    {3, 4}
};

int m2[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

struct matrix matrix1 = {2, 2, m1};
struct matrix matrix2 = {3, 3, m2};

This gives the error 'initialisation from incompatible pointer type'. What pointer type should I be using?

Dimpl
  • 935
  • 1
  • 10
  • 24
  • Start by checking the type of `m1` or `m2`..... – Sourav Ghosh Mar 16 '16 at 11:48
  • 3
    2d array is not a pointer to pointer... – LPs Mar 16 '16 at 11:49
  • @SouravGhosh I didn't think you could get a string out of typeof()...? – Dimpl Mar 16 '16 at 12:03
  • @Dimpl Please look at LP's comment. And sometimes just try to think before implementing., that helps. Meh. – Sourav Ghosh Mar 16 '16 at 12:04
  • A 2d array is not a pointer to a pointer... except that it kind of is. See http://stackoverflow.com/questions/26454022/storing-and-accessing-a-2d-array-in-a-struct. I asked this question as that answer doesn't address the situation where all values for the 2d array are assigned in one statement. – Dimpl Mar 16 '16 at 12:12
  • To clarify, a pointer to a pointer can be used to represent a 2d array. – Dimpl Mar 16 '16 at 12:28
  • I would appreciate the explanations for vote downs - I have received great answers, so the question is most definitely solvable. – Dimpl Mar 16 '16 at 13:45
  • @Dimpl: Maybe this answer helps a bit in understanding the differences between arrays and pointers: http://stackoverflow.com/a/1641963/2675154 – honk Apr 17 '16 at 08:29
  • @Dimpl: Regarding the [question you linked](http://stackoverflow.com/q/26454022/2675154): I think, the line where the 2D array is assigned in one statement is: `Spiral spiral = generateSpiral(size);` – honk Apr 17 '16 at 08:36
  • @honk I believe I understand the difference between arrays and pointers. When I said above that it "kind of is", I was referring to the fact that a 2d array data may be located by a double pointer, as a double pointer may be dereferenced using 2d array syntax. Many responses/comments have said "2d array is not a pointer to pointer". While this statement is not strictly false, it is misleading as it implies that a double pointer shouldn't be used with 2d array data. – Dimpl Apr 17 '16 at 11:31
  • I linked [that question](http://stackoverflow.com/questions/26454022/storing-and-accessing-a-2d-array-in-a-struct#answer-26454082) as it demonstrated that 2d array data may be stored in a double pointer. However, at the time, I did not understand malloc, so that answer was not sufficient. – Dimpl Apr 17 '16 at 11:33

4 Answers4

2

A matrix, as you declared, is not a pointer to pointer. Use a simple pointer to point its element.

#include <stdio.h>

struct matrix {
    int h;
    int w;
    int* data;
};

int m1[2][2] = {
    {1, 2},
    {3, 4}
};

int m2[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

struct matrix matrix1 = {2, 2, &m1[0][0]};
struct matrix matrix2 = {3, 3, &m2[0][0]};

int main(int argc, char **argv)
{
   int i, j;

   for (i=0; i<matrix2.h; i++)
      for(j=0; j<matrix2.w; j++)
         printf("%d ", matrix2.data[(i*matrix2.h)+j]);

    printf("\n");
}

EDIT

To answer to the comment, you can use compound literal as below. In this way you could access it with [i][j]

#include <stdio.h>

struct matrix {
    int h;
    int w;
    int** data;
};

int *m2[3] = {
    (int[]){1, 2, 3},
    (int[]){4, 5, 6},
    (int[]){7, 8, 9}
};

struct matrix matrix2 = {3, 3, m2};

int main(int argc, char **argv)
{
    int i, j;

    for (i=0; i<matrix2.h; i++)
        for(j=0; j<matrix2.w; j++)
            printf("%d ", matrix2.data[i][j]);

    printf("\n");
}
LPs
  • 16,045
  • 8
  • 30
  • 61
  • This is satisfactory, though not optimal, as I would prefer to use [i][j] than [(i*3)+j]. – Dimpl Mar 16 '16 at 11:58
  • Thank you, this is very good. In my application, I only access the matrix in 1 library function, so Peter A. Schneider's answer works better, but i would accept this solution too if I could. – Dimpl Mar 16 '16 at 13:31
2

2d array is not a pointer to pointer.

How to use the void *.

#include <stdio.h>

struct matrix {
    int h;
    int w;
    void *data;
};

int m1[2][2] = {
    {1, 2},
    {3, 4}
};

int m2[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

struct matrix matrix1 = {2, 2, m1};
struct matrix matrix2 = {3, 3, m2};

int main(void){
    int i, j;

    int (*matp)[matrix2.w] = matrix2.data;//Back from the void* to pointer to array

    for (i=0; i<matrix2.h; i++){
        for(j=0; j<matrix2.w; j++)
            printf("%d ", matp[i][j]);
        puts("");
    }
    printf("\n");

    return 0;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • I can't get my head around what's going on with `int (*matp)[matrix2.w] = matrix2.data;`, but it works! I've never seen the variable name bracketed before. – Dimpl Mar 16 '16 at 12:35
  • 1
    I think this is the least bad version. Disadvantages are that you have to cast to and from the array pointer and void pointer, and that the void pointer is not type safe. I started to write an answer which created a struct with VLA through a macro, but it was far less readable. Another alternative would be some array of pointers solution, but that's not pretty either. – Lundin Mar 16 '16 at 12:35
  • 1
    @Dimpl It creates an array pointer to a 1D array of size `w`. Then uses pointer arithmetic on such a pointer type to access each array in the 2D array. `matp[i][j]` means "give me array `i`, and in that array give me item `j`". – Lundin Mar 16 '16 at 12:37
  • @Lundin Thanks. I tend to use int* for declaration and *matp for dereferencing, so got a bit mixed up. – Dimpl Mar 16 '16 at 12:42
  • Perhaps a macro could be used for the matrix pointer declaration though, to make the code more generic. `#define declare_matrix_ptr(name, matrix) int(*name)[matrix.w] = matrix.data` Not pretty but less chance for typos. – Lundin Mar 16 '16 at 12:44
2

You may be interested in the variable length arrays of C99. This solution does not directly answer your question about how to initialize the structure with a properly typed data (one can't); but you can use a simple pointer to store the array's address and then cast to the variable length array pointer when using struct matrix.

The user side would just call functions like printFroMat() which receive a single argument of type struct matrix; the code inside these functions (so to speak, the library implementation) would perform the somewhat unsightly casts, as demonstrated. The typedef makes the cast perhaps a little more understandable because it demonstrates where the variable name in a declaration would go.

Note that the funny sizeof(m2)/sizeof(*m2) etc. are not strictly necessary, you can just say 3. But the sizeof expression automatically stays in sync with the actual matrix size, which quickly becomes a real asset.

You can pass "arrays" (in fact: still just addresses, but of a known array type) together with their dimensions as parameters to functions, and index them the normal way (below in printMatrix). Example:

#include<stdio.h>
#include<string.h>


struct matrix {
    int h;
    int w;
    int *data; // first element of matrix
};

int m2[4][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9},
    {10, 11, 12}
};

void printMatrix(int dim1, int dim2, int mat[][dim2] )
{
    printf("Address of matrix: %p\n", (void *)mat);

    for(int i1=0; i1<dim1; i1++)
    {
        for(int i2=0; i2<dim2; i2++)
        {
            printf("%d ", mat[i1][i2]);
        }
        putchar('\n');
    }
}

void printFromMat(struct matrix mat)
{
    printMatrix(mat.h, mat.w, (int (*)[mat.w])mat.data);

    // or:
    typedef int (*mT)[mat.w];
    printMatrix(mat.h, mat.w, (mT)mat.data);
}

int main() 
{

    printMatrix(   sizeof(m2) /sizeof(*m2),   // number of highest-order elements
                   sizeof(*m2)/sizeof(**m2),  // number of second-order elements per highest-order
                   m2  );                     // address of the first sub-array

    struct matrix mat = { sizeof(m2) /sizeof(*m2), sizeof(*m2)/sizeof(**m2), *m2 };

    printFromMat(mat);


    return 0;
}

Sample session:

$ gcc -std=c99 -Wall -o 2d-matrix 2d-matrix.c && ./2d-matrix
Address of matrix: 0x100402020
1 2 3
4 5 6
7 8 9
10 11 12
Address of matrix: 0x100402020
1 2 3
4 5 6
7 8 9
10 11 12
Address of matrix: 0x100402020
1 2 3
4 5 6
7 8 9
10 11 12
Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
  • Thank you for your answer! I am passing matrix (or matrix*, to be precise) as a parameter. Is there a way to cast inline? I tried (int(*)[mat.w])mat.data[r][c], but this didn't work. – Dimpl Mar 16 '16 at 13:41
  • 1
    Try `((int(*)[mat.w])(mat.data))[r][c]`. `[]` and `.` have [higher precedence](http://en.cppreference.com/w/c/language/operator_precedence) than the cast. You only want to cast `mat.data`, not `mat.data[r][c]`. That said, `((int(*)[mat.w])mat.data)[r][c]` should do. – Peter - Reinstate Monica Mar 16 '16 at 13:47
0

You may not initialize the structure such a way like

struct matrix matrix1 = {2, 2, m1};
struct matrix matrix2 = {3, 3, m2};

because there is no conversion from types int ( * )[2] and int ( * )[3] to type int **

I suggest to allocate memory for copies of the arrays dynamically.

The approach can look the following way as it is shown in the demonstrative program

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

struct matrix 
{
    size_t h;
    size_t w;
    int **data;
};

int m1[2][2] = 
{
    { 1, 2 },
    { 3, 4 }
};

int m2[3][3] = 
{
    { 1, 2, 3 },
    { 4, 5, 6 },
    { 7, 8, 9 }
};

struct matrix init( size_t h, size_t w, int a[h][w] )
{
    struct matrix matrix = { 0 };

    matrix.data = malloc( h * sizeof( int * ) );

    if ( matrix.data )
    {
        matrix.h = h;
        matrix.w = w;
        for ( size_t i = 0; i < h; i++ ) 
        {            
            matrix.data[i] = malloc( w * sizeof( int ) );
            if ( matrix.data[i] )
            {                
                for ( size_t j = 0; j < w; j++ ) matrix.data[i][j] = a[i][j];
            }
        }
    }        

    return matrix;
}

int main( void ) 
{
    struct matrix matrix1 = init( 2, 2, m1 );
    struct matrix matrix2 = init( 3, 3, m2 );

    for ( size_t i = 0; i < matrix1.h; i++ )
    {
        for ( size_t j = 0; j < matrix1.w; j++ ) printf( "%d ", matrix1.data[i][j] );
        printf( "\n" );
    }
    printf( "\n" );

    for ( size_t i = 0; i < matrix2.h; i++ )
    {
        for ( size_t j = 0; j < matrix2.w; j++ ) printf( "%d ", matrix2.data[i][j] );
        printf( "\n" );
    }
    printf( "\n" );

    // free allocated arrays of matrix1 and matrix2
}    

The program output is

1 2 
3 4 

1 2 3 
4 5 6 
7 8 9 

You need also to write a function that will free the allocated memory for the structure.

The compiler must support variable length arrays.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335