2

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?

3
  • 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. Commented Sep 25, 2014 at 8:07
  • I updated my post with a full working example and the GCC command line I use. Commented Sep 25, 2014 at 8:12
  • @Lundin Same warning when I use NULL instead of 0 (including stddef.h). Commented Sep 25, 2014 at 8:18

4 Answers 4

3

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}
};
Sign up to request clarification or add additional context in comments.

4 Comments

Best looking solution so far, but my printf show incorrect result -- are you sure it works?
@susundberg You need to feed something like (*parr[0][0])[0][0] to printf for it to work.
That seems correct, thanks for correction, using "printf("%d", (int)((*parr[0][0])[i][j] - (*parr[1][0])[i][j] ) );" the answear works fine!
"The only sane way to write code like this ..." isn't it the "only" possible way to do so? As per the parenthis-language-quirk you mention as "But the outer parenthesis here actually do nothing ..."?
1

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].

Comments

1

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
$

4 Comments

Are you sure this works, i got some weird results when trying to run this, more precise silly2.c:27:54: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] printf("%d,%d ", (char)parr[0][0][i][j], (char)parr[1][0][i][j] );
I believe the printf should be parr[0][0][0][0].
Doing printf, like on my answear, but in 2d array fashion, gives also weird results -- actually the sames as @Lundin gives, -16 on every cell, its not only the warning that buggers me.
@susundberg You need to dereference the pointer to the second matrix.
0

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;
}

3 Comments

The problem with "mangled" arrays is that you have to calculate the dimensions in runtime, which adds extra overhead code. And the code gets a bit harder to read.
Based on my tests 2D static arrays are 1D arrays like this after compiler does its magic, so i think this is less mangled code than with 2D arrays. About the 'ease of reading' : do you prefer extra "typedef + (parr[0][1])[i][j]" or just "parr[0][1][in + j]". I go with later.
Neither is good. If I ever found myself needing a 2D array of array pointers, I'd take a step back and try to find out where my fundamental program design went wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.