1

None of the answers I have found seem to address my issue. I am creating a dynamic 3d array in C and later freeing it. I can store and later access the data stored in this array using a nested for loop but I get an access violation when trying to free it using the same nested for loop setup. Where am I going wrong?

unsigned char ***buff1;
int r, c;
someFunction(&buff1, &r, &c);
for(int i = 0; i < r; ++i)
{
  for(int j = 0; j < c; ++j)
  {
    free(buff1[i][j]);
  }
  free(buff1[i]);
}
free(buff1);


someFunction(unsigned char**** buff, int *nR, int *nC)
{
  ...
  *buff = (SQLCHAR***)malloc(*nR * sizeof(SQLCHAR**));
  for(int i = 0; i < *nR; ++i)
  {
    (*buff)[i] = (SQLCHAR**)malloc(*nC * sizeof(SQLCHAR**));
    for(int j = 0; j < *nC; ++j)
    {
      (*buff)[i][j] = (SQLCHAR*)malloc(256);
    }
  }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Your code doesn't show how `r` and `c` are initialized — or how `*nR` and `*nC` are initialized in `someFunction()` if that's where the initialization occurs. It seems a little odd to pass an `unsigned char ****` and then cast the return value from `malloc()` using `SQLCHAR` instead of `unsigned char`. There are those who'd say using a cast at all is bad; I'm not wholly in that camp, but I do think consistency is good and the code is not consistent as written. – Jonathan Leffler Jul 24 '13 at 00:31

3 Answers3

2

Multiple things are wrong:

unsigned char**** buff

What is this, if not wrong? (Well, OK, not technically, but stylistically anyway...)

(SQLCHAR*)malloc(256);

isn't any better either, since you must not cast the return value of malloc() in C.

The third mistake is that you don't have a 3D array. You have a pointer-to-pointer-to-pointer. Ewww. Ugly. Why not allocate a true 3D array instead?

size_t xsize, ysize, zsize; // initialize these!
unsigned char (*arr)[ysize][zsize] = malloc(sizeof(*arr) * xsize);

Then all you need to do in order to free it is:

free(arr);

Honestly, isn't this way better?

Community
  • 1
  • 1
  • That does look much better. xsize and ysize are both determined at runtime and will not work this way. – Nole Fan 81 Jul 23 '13 at 20:23
  • Oh, and before Eric Postpischil points out that this isn't a true array either: that's right, it's a pointer to the first element of an array of type `unsigned char [xsize][ysize][zsize]`, which (obviously) points to a contiguous block of memory which can be treated as an array (except that pointers are not arrays, so the usual warnings about the `sizeof` and the `&` operators apply). A true 3D array, strictly speaking, would be `unsigned char [xsize][ysize][zsize]`, but that's not dynamically alocated. –  Jul 23 '13 at 20:24
  • @NoleFan81 Excuse me, but do you happen to be stuck in 1989? VLAs are standard in C99. –  Jul 23 '13 at 20:25
  • 1
    OP wanted to return the allocated array from the function; i don't see how you can do it when using a VLA – anatolyg Jul 23 '13 at 20:31
  • @NoleFan81 What do you mean by that? Why do you have "no choice"? Are you obliged to use a compiler which doesn't support C99? (If so, you should have mentioned that well before diving deep into the question.) –  Jul 23 '13 at 20:33
  • Also, what's the reason for the (edit: now-revoked) downvote? I can assure everybody that this answer is correct - both technically and conceptually. –  Jul 23 '13 at 20:34
  • I removed my downvote: did some tests and actually figured the syntax out. Not easy (unless you edit OP's code by removing `someFunction` altogether). – anatolyg Jul 23 '13 at 20:37
  • 2
    @anatolyg Conversely, it's pretty trivial: `unsigned char (*p)[y][z] = theAllocatorFunc();`. Also, if **you** can't figure out the syntax, that's not my fault. Don't judge others before having made sure that it's not indeed you who made a mistake. –  Jul 23 '13 at 20:39
2

I try you code in this way,and it works good:

#include "stdio.h"
#include "stdlib.h"

int  someFunction (unsigned char**** buff, int *nR, int *nC)
{
  int i,j;
  *buff = (unsigned char ***)malloc(*nR * sizeof(char**));
  for(i = 0; i < *nR; ++i)
  {
    (*buff)[i] = (unsigned char**)malloc(*nC * sizeof(char**));
    for(j = 0; j < *nC; ++j)
    {
      (*buff)[i][j] = (unsigned char*)malloc(256);

      (*buff)[i][j][0] ='1';
    }
  }
}


int main()
{
unsigned char ***buff1;
int r = 3, c= 2,i,j;
someFunction(&buff1, &r, &c);
for( i = 0; i < r; ++i)
{
  for(j = 0; j < c; ++j)
  {
        printf("        %c",buff1[i][j][0]);
    free(buff1[i][j]);
  }
  free(buff1[i]);
}
free(buff1);
}

So, maybe the mistake is not happening in the code you are showing to us.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Lidong Guo
  • 2,817
  • 2
  • 19
  • 31
1

Your code looks pretty buggy. For starters you are calling someFunction(&buff1, &r, &c) while that function expects ints and not int *s. Later you dereference nR and nC and they aren't pointers.

I guess you should be getting some nasty warnings when compiling.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
user2553780
  • 161
  • 8