1

I have the following 2-dimension array N*2 (I can't modify its declaration):

bool* myArray[2];
int N;

I want to allocate it with calloc but no success:

myArray = calloc(N, 2*sizeof(bool));
for (int i=0; i!=N; i++)
{
    myArray[i] = calloc(2, sizeof(bool));
}

The compiler raises me (on the first calloc):

error: incompatible types in assignment of 'void*' to 'bool* [2]'

what am I doing wrong?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
rudy
  • 176
  • 3
  • 14

3 Answers3

3

This code:

bool* myArray[2];
int N;

doesn't declare a 2-dimensional array but an array of pointers. This is an important difference because 2-dimensional arrays are not arrays of pointers to arrays -- they are just stored contiguously, like 1-dimensional arrays are (one "row" after the other).

So, as you state you cannot change the declaration, let's instead explain what you need for an array of pointers. With your declaration, you declare exactly 2 pointers, so N can only mean the "second dimension" as in the number of elements in the arrays those pointers point to. With this declaration, you can have 2 times an array of N bools. Allocating them would look like this:

myArray[0] = calloc(N, sizeof(bool));
myArray[1] = calloc(N, sizeof(bool));

There's no need to allocate space for myArray itself, with your declaration, it already has automatic storage.

  • When you wrote "2-dimensional arrays are not _arrays of arrays_", did you mean "2-dimensional arrays are not _arrays of pointers_"? It seems to make more sense that way. – Ian Abbott Jun 23 '17 at 12:42
  • @IanAbbott I wrote the more abstract *arrays of arrays* because in some languages, multi-dimensional arrays are defined this way. But of course, to build *arrays of arrays* in C, you have to use pointers. –  Jun 23 '17 at 12:43
  • 1
    I think that you are trying to draw a distinction between arrays and jagged arrays, but "2-dimensional arrays are not arrays of arrays" is not quite true. Given `char arr[2][2];`, `arr` is an array of two arrays of `char`. Contiguous storage, yes, but note that in most expressions `arr` will decay to a pointer to its _first element_, an array of `char`s: `(*)[2]`. – ad absurdum Jun 23 '17 at 14:37
  • 1
    @DavidBowling ok, this is a valid objection (given the "pointer type" of `arr` here). I'm not sure whether the term *jagged array* would make it clear, maybe I'll go with the simple *arrays of array pointers*. (explaining pointers and arrays in C is hard, that's probably the reason so many beginners get it wrong) –  Jun 23 '17 at 14:47
  • Agree. It seems that one needs to keep several pieces in mind to make sense of pointers and arrays, meaning beginners have to digest a bit first. Yes, I think that _arrays of array pointers_ is fine, and less likely to induce confusion among beginners than _jagged array_. – ad absurdum Jun 23 '17 at 14:53
2

Do this instead:

bool (*myArray)[2] = calloc(N, sizeof(*myArray));

Or, if you do not wish to modify your declaration, just get rid of the first calloc here and modify your for loop:

myArray = calloc(N, 2*sizeof(bool)); // you do not need that
for (int i=0; i < 2; i++)
{
    myArray[i] = calloc(N, sizeof(bool));
}

PS: In C we don't cast malloc, we do that when we wish to compile C++.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • i can't change the declaration of myArray in the header – rudy Jun 23 '17 at 12:16
  • The question states "*(I can't modify its declaration)*". So, for whatever reason that is, an answer should explain that this isn't a 2D-array but an array of pointers to arrays ... and show how it's done properly. –  Jun 23 '17 at 12:17
  • A simpler solution would be to just get rid of the first line: `myArray = calloc(N, 2*sizeof(bool));`. – cs95 Jun 23 '17 at 12:19
  • @Coldspeed indeed, but an one liner looks prettier in this case, I hink. – gsamaras Jun 23 '17 at 12:21
  • Thank you BLUEPIXY, again! ;) @FelixPalmen updated (nice answer BTW)! – gsamaras Jun 23 '17 at 12:26
  • 2
    @rudy if you need a cast, you're using a [tag:c++] compiler. That's not a good idea for compiling C code. –  Jun 23 '17 at 12:29
  • @Felix i know, but it's an ugly code i have to modify and I'm not able to correct the ugly stuffs – rudy Jun 23 '17 at 12:30
  • @rudy I updated my answer, hope it's good now and acceptable. – gsamaras Jun 23 '17 at 12:45
1

The reason you can't reallocate myArray is that myArray is not a pointer. It is an array of two pointers to bool. It is also, contrary to your description, not a "2-dimension array".

All you need to do is

for (int i=0; i < 2; ++i)
{
    myArray[i] = calloc(N, sizeof(bool));
}

and you can then use as a '2*N' array, for example to set all elements to true;

for (int i = 0; i < 2; ++i)
{
    for (j = 0; j < N; ++j)
          myArray[i][j] = true;
}

If you swap the order of indices (e.g. use myArray[j][i] in the inner loop above) and use myArray as a 'N*2' array rather than as a '2*N' array, the result will be undefined behaviour. There is no solution to change that, without changing the declaration of myArray - which you have said you do not want to do.

Peter
  • 35,646
  • 4
  • 32
  • 74