2
votes

Is it possible to create statically in C a 2d array of pointers to 2d arrays, like:

#define m 4
#define n 4
#define p 2
#define q 2

char arr1[m][n] = {{0}};
char arr2[m][n] = {{0}};
char (*parr[m][n])[p][q] = {{&arr1, 0, &arr2, 0}};

int main() {
    return 0;
}

The 2d array of pointers parr is sparse, with some values to 0 (NULL), which is why I don't want to use a 4d array in the first place.

This compiles, but I get the following warning:

warning: initialization from incompatible pointer type

With the following command:

gcc -Wall -Wextra -pedantic -std=c99 test.c

What is wrong?

4
Please post the actual code you are having problems with. I cannot reproduce the compiler warning and your code looks fine (apart from a1 needing to be arr1). One possible cause could be that NULL is not defined to be 0 on your particular compiler. Try to change the 0 in the 2D array to NULL. Also if possible, consider using a typedef for the array type so that the code gets easier to read. - Lundin
I updated my post with a full working example and the GCC command line I use. - OlivierB
@Lundin Same warning when I use NULL instead of 0 (including stddef.h). - OlivierB

4 Answers

3
votes

The problem is that when you declare pointers, arrays and array pointers, the [] takes precedence over * unless you add parenthesis. This is why you declare an array pointer as (*parr)[] rather than *parr[], since the latter gives an array of pointers instead.

Similarly, when declaring a pointer to a 2D array, you would type (*parr)[m][n]. So it seems logical that an array of 2D-array pointers should be declared as ((*parr)[m][n])[p][q]). But the outer parenthesis here actually does nothing, that expression is equivalent to (*parr)[m][n][p][q]. And that's an array pointer to a 4D array! Which is why you get compiler warnings.

Now what you actually want is to get an array of array pointers to 2D arrays, is something like char (*parr[p][q])[m][n]. Which looks rather insane, nobody will understand a declaration like that.

The only sane way to write code like this is through typedefs:

typedef char arr_t[m][n];

arr_t arr1 = {{0}};  
arr_t arr2 = {{0}};  
arr_t* parr[p][q] =
{
  {&arr1, 0},
  {&arr2, 0}
};
1
votes

I think what you meant to do is the following:

char arr1[m][n] = {{0}};
char arr2[m][n] = {{0}};

typedef char (*some_type)[n];  // type of arr1 and arr2
some_type parr[p][q] = {{arr1, NULL}, {arr2, NULL}};  //array containing arr1 and arr2

You can then access parr e.g by

printf("%c\n", parr[0][0][0][0]);

which will print arr1[0][0].

1
votes

In the declaration of parr I think you meant to use p and q as its dimensions:

$ cat test.c
#include <stdio.h>

#define m 4
#define n 4
#define p 2
#define q 2

char arr1[m][n] = {{0}};
char arr2[m][n] = {{0}};

char (*parr[p][q])[m][n] = {{&arr1, NULL}, {&arr2, NULL}};

int main(void)
{
    printf("%d\n", (*parr[0][0])[0][0]);
    return 0;
}

This compiles cleanly with GCC 4.8.2:

$ gcc --version
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc -ansi -fsanitize=address -g -pedantic -Wall -Wextra -Wfatal-errors -Wno-unused-parameter -o test test.c
$
0
votes

Here would be my solution -- i prefer using static 1D arrays rather than static 2D arrays due pointer arithmetic (i like to keep things simple):

PS. i would suggestin using m!=n and p!=q for testing, so you can catch possible indexing errors!

#include <stdio.h>

#define m 4
#define n 4
#define p 2
#define q 2


char arr1[m*n] = {0};
char arr2[m*n] = {0};
typedef char array_2d[m][n];

char* parr[p][q] = { {(char*)arr1, NULL}, { (char*)arr2, NULL} };


int main() 
{
    for (int i = 0; i < m; i ++ )
    for (int j = 0; j < n; j ++ )
    {
       arr1[i*n + j] = i + j;
       arr2[i*n + j] = i - j;
    }

     for (int i = 0; i < m; i ++ )
     {
         for (int j = 0; j < n; j ++ )
         {
            char* arr1_ptr = parr[0][0];
            char* arr2_ptr = parr[1][0];
            printf("%d", (int)(arr1_ptr[i*n + j] - arr2_ptr[i*n + j] ));
         }
         printf("\n");
     }

    return 0;
}