2

I have really been confused about this 2D char array

char **arg = malloc(sizeof(char*) * argc)
for (int i = 0; i < argc; i++)
  arg[i] = malloc(sizeof(char) * size)
...
...

Now suppose after a series of operations, I forget the variable argc, how can I free those memory? Can I do something like this? Is this absolutely correct under all circumstances?

char **tmp = arg;
while (*tmp != NULL){
    free(*tmp); 
    tmp++;
}
free(arg);
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
Louis Kuang
  • 727
  • 1
  • 14
  • 30
  • Arrays aren't NULL terminated, that's only valid for strings (char * in C) – John Oct 11 '15 at 13:02
  • you are in fact allocating memory for an array of char*, then allocating memory for each of items in the array. You have to free items first then free the array it self. – milevyo Oct 11 '15 at 13:05
  • This is in fact not a bad idea, but you should explicitly put a `NULL` at the end of the array. I use this in many situations and it's good. – Iharob Al Asimi Oct 11 '15 at 13:07
  • 1
    This is not a 2D array, but a pointer of pointer. – Jens Gustedt Oct 11 '15 at 13:25
  • actually arg it is a dynamic array of char*; that can hold (argc) elements; elements are dynamic array of char that can hold (size) chars; each array and elements are freed separately; – milevyo Oct 11 '15 at 15:29

3 Answers3

3

No

while(*tmp != NULL){

you may reach above a point where you will dereference memory which hasn't been assigned to and trigger undefined behaviour.

Or as suggested you can explicitly assign a NULL to the last allocated pointer, and in that case it will work.

Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
0

As others have said, the problems with freeing in a loop as shown is that an extra item (argc + 1) needs to be allocated and it has to be set to NULL. An alternative technique is to first allocate the space for the pointers as you have done

char **arg = malloc(sizeof(char*) * argc)

Then, if you know all the subsequent items are the same size, allocate it in one huge block and set the rest of the elements at spaced offsets

arg[0] = malloc(sizeof(char) * size * argc);
for (int i = 1; i < argc; ++i)
   arg[i] = arg[i - 1] + size;

Freeing the space is a doddle: no need to even remember argc

free(arg[0]); /* this will free the memory used by all the elements */
free(arg);

The big disadvantages to this technique is that if any of the array elements overrun, it will corrupt the next item. This cannot be detected so easily with a heap check unless it is the last item.

cup
  • 7,589
  • 4
  • 19
  • 42
-1

if you define your char * array like this:

char **arg = calloc( 1, sizeof( char * ) * argc );

you can be sure that every undefined pointer will be equal to NULL

and then you can use the while loop almost like you suggested:

char *tmp = *arg;
while ( tmp != NULL ) {
    free( tmp ); 
    tmp++;
}
free(arg);
Itay Sela
  • 942
  • 9
  • 26