Search code examples
carrayscalloc

calloc causes Bad Access


My main function has this:

 int main() {
  //
  double minW, minL, width, length;
  unsigned tileCap = 10;
  auto *tiles = (Tile*)calloc(tileCap, sizeof(Tile) );
  GetInput(&minW, &minL, &tiles, &tileCap);
 }

And my GetInput() will read and save into the array of Tiles:

void GetInput(double *w, double *l, Tile **tiles, unsigned *tileCap) {
  //
  printf("Tile:\n");
  double tileSize, tileJoint;
  int argc;
  unsigned tileCount = 0;

  do {
    argc = scanf("%lf %lf", &tileSize, &tileJoint);
    if (tileSize == 0 || !CorrectSize(tileSize) || !CorrectSize(tileJoint) || argc != 2)
      BadInput();

    bool needTransform = HasFloatingPoint(tileSize);
    if(needTransform) {
      tileSize = MultiplyByTen(tileSize);
      tileJoint = MultiplyByTen(tileJoint);
    }

    tiles[tileCount]->size = (long long)tileSize;
    printf("%lld\n", tiles[tileCount]->size);
    tiles[tileCount]->joint = (long long)tileJoint;

    if(++tileCount == *tileCap) {
      DoubleArray(tiles, tileCap); //f() with realloc
    }
  } while(argc != EOF);
}

This program works for first iteration of inputs but always gives exit code 11 and the debugger says BAD_ACCESS at the assignment.

So either I'm accessing or allocating the array incorrectly.

I give my function a double pointer. So in order to access Tile members, I need to dereference it twice. One dereference is [] and the other one is ->. Printing the Tile after assigning confirms it.

And I see nothing wrong with my allocation. Where am I wrong?

EDIT: tiles[index]->size would mean *(tiles[index]).size while I need (*tiles)[index].size. Dereference order and scope is important.


Solution

  • Even though your code seems incomplete and I'm mostly guessing, the issue seems to be in the following line in your main function:

     GetInput(&minW, &minL, &tiles, &tileCap);
    

    You should consider that tiles is already a pointer. When you're using &tiles, you're actually passing a pointer to your pointer and not the pointer itself.

    In your GetInput function, you're using tiles[tileCount] which indicated you wanted to pass a pointer. If your GetInput was supposed to get a double pointer, you would have used (*tiles)[tileCount].

    You can solve many of these issues by listening

    I think what you probably meant to do was:

     GetInput(&minW, &minL, tiles, &tileCap);
    

    And the function definition should probably look like this:

     void GetInput(double *w, double *l, Tile *tiles, unsigned *tileCap
    

    EDIT: (using a double pointer)

    Since you need to use a double pointer, than you should remember to dereference the double pointer when you're looking into the data. i.e.:

    *(tiles)[tileCount]->size = (long long)tileSize;
    printf("%lld\n", *(tiles)[tileCount]->size);
    *(tiles)[tileCount]->joint = (long long)tileJoint;
    

    Explanation:

    A double pointer needs a double de-referencing. The first dereferencing collects the information on the nested pointer (*tiles) and the second dereferencing collects the data (**tiles).

    The double dereferencing can also be achieved using the square brackets ((*tiles)[i] or tiles[0][i]).

    Since tiles is a struct you can use the "arrow" as the second dereferencing technique as well: (*tiles)->size