views:

2288

answers:

3

I'm trying to mimic the following Java code:

int[][] multi; // DIMENSIONS ARE UNKNOWN AT CREATION TIME
// LATER ON...
multi = new int[10][];
multi[5] = new int[20];
multi[5][11] = 66;
// LATER ON...
multi = null; // PROPER WAY OF FREEING EVERYTHING

I've came out with the following Objective-C version:

int* *multi;
//
multi = malloc(10 * sizeof(int*));
multi[5] = (int *) malloc(20 * sizeof(int));
multi[5][11] = 66;
//
free(multi[5]);
free(multi);

So first, I'd like to hear if it's the best way to go. And mostly: I can't find a way to free memory in some "automatic" fashion, i.e. the following code is causing run-time exceptions on the IPhone:

for (int i = 0; i < 10; i++)
{
    if (multi[i] != NULL) free(multi[i]);
}
A: 

You can make a one-dimensional array and then use an index based off of your two values. That way will have less initialization code to deal with.

Also, if you defer initializing multi until you know the dimensions, you can just initialize it as if it were a static array, rather than a variable-sized one.

Ben Alpert
Thanks, but I think you miss the point: the data structure that I require must be dynamic. 1) It should be possible to change the length of one of the "rows" without affecting the whole data-set. 2) The data-set should be declarable as a class variable before i.e. before the number of rows is known
Ariel Malka
+3  A: 

First, the suggested solution in the question is not specific to Objective-C, this is standard C. The C translation of Java code looks correct.

Second, the suggested "automatic" free cannot work: malloc() does not initialize the allocated memory. I would use calloc() instead, or add a memset() after malloc().

Third, for an Objective-C version, I would consider an NSMutableArray object populated with NSMutableArray objects themselves populated with NSNumber objects. For your goal, I think that the C version is OK.

mouviciel
The suggestion of using calloc() was helpful (together with to the other post by Jason Coco...) And concerning mutable arrays: I need to stick to primitive types because the data in question is meant to be send right to the GPU.
Ariel Malka
+6  A: 

Free doesn't zero out the memory address in the pointer, it just invalidates it. So, if you're running this loop more than once, you will get exceptions when you try to free memory that has already been invalidated. You can use an NSPointerArray or wrap your integers in objects and use an NSMutableArray for your purposes, but if you just want to use what you have, and you're running the loop more than once, you will have to do something like:

int **multi;
multi = calloc(10, sizeof(int*));
multi[5] = calloc(20, sizeof(int));
//
multi[5][11] = 66;
//
for( int i = 0; i < 10; i++ ) {
  if( multi[i] ) {
    free(multi[i]);
    multi[i] = NULL;
  }
}
//
free(multi);

This way if the loop is run more than once, you won't fail. Also, I use calloc instead of malloc because it will set all the pointers to NULL and integers to 0. The first parameter is the size of the array you want (in your case) and the second parameter is the size of the type (so no multiplication is required).

Jason Coco
Great! One question still: why "multi[i] = NULL" is required? Everything should be wiped out by the "free(multi)" at the end anyway, no?
Ariel Malka
It is required, that's part of the problem. Free doesn't wipe anything out, just marks the memory as available to the operating system. The old data will still be there, so if you sweep through the array again, you will get bad data unless you specifically clear it.
Jason Coco
By the way, if you only ever run this loop one time and then free(multi), you're right, the multi[i] = NULL is not needed...
Jason Coco