PDA

View Full Version : multidimensional arrays in Objective-C




amalshah71
Mar 6, 2009, 08:17 AM
Hello,
I am reading some of the elements from a file...i would like to read it in a 2-d array..but till the point i don't read it , i would not know as to of how many rows and columns should i built the 2-d int array

as in...

// Test.h
@interface Test
{
int array[2][4];
}
@end

and...

@implementation Test

@end

The above one lets me declare a 2-d array with pre-known rows and columns....

so, how do i declare a global 2-d array and initialize it with number of rows and columns at runtime...

Thanks
amal



robbieduncan
Mar 6, 2009, 08:22 AM
I think something like this should work:


@interface Test
{
int *array;
}
@end

and...

@implementation Test
int x,y;
// Assume x and y get initialised to the "width" and "height" of the array
array = malloc(x*y*sizeof(int));
@end

lee1210
Mar 6, 2009, 08:40 AM
If you don't need a C-style array, I'd say use an NSMutableArray of NSMutableArrays, which lends itself better to dynamic sizing and easier memory allocation. If you must use a C-style array, you could do something like this:

Test.h

@interface Test
{
int **array;
}
@end


Test.m


@implementation Test
int x,y;
// Assume x and y get initialised to the "width" and "height" of the array
array = (int **)malloc(x*sizeof(int *)); //You need to free((void *)array) AFTER
for(int pos = 0; pos < x;pos++){
array[pos] = (int *)malloc(y*sizeof(int)); //you loop through array and free((void *)array[pos])
}
@end


I modified robbieduncan's code a bit, because i think to use [][] on array it must be an int **, not int *. Note that my solution doesn't give you a contiguous block of memory to work with, so you can't copy the whole thing at once, etc. This might work (too tired, late night of Watchmen) for a contiguous block:

Same Test.h
Test.m:

@implementation Test
int x,y;
// Assume x and y get initialised to the "width" and "height" of the array
array = (int **)malloc(x*sizeof(int *)); //Need to free((void *)array) AFTER
void *temp = malloc(x*y*sizeof(int)); // you free((void *)array[0]), which temp will be assigned to
for(int pos = 0; pos < x;pos++){
array[pos] = (int *)&temp[pos*y];
}
@end


Someone is definitely welcome to correct any of this, I am probably not in the proper shape to really be giving advice =). Also, i didn't write a dealloc method, but you will need to remember which

-Lee

robbieduncan
Mar 6, 2009, 08:54 AM
It appears that you are correct (http://www.eskimo.com/~scs/cclass/int/sx9b.html) :)

lazydog
Mar 6, 2009, 09:32 AM
Hi Amalshah71

The problem here is that the compiler needs to know at compile time the dimensions of the array. So if you don't know the dimensions until run time you have to role your own. Lee's suggestion will let you keep the same, familiar, syntax for accessing the array, ie


value = test[y][x] ;


but it does have the downside that you need to manage the array's memory yourself and it is has an extra level of indirection.

If you don't mind running your code through the Objective-C++ compiler though there is another way. It might not suite you but I'll post it here anyway.


class array2i
{
public:
array2i( int rows, int columns )
: columns_( columns ), data_( new int[ rows * columns ] ) {}

~array2i() { delete[] data_ ; }

int* operator []( int row ) { return data_ + columns_ * row ; }

private:
int columns_ ;
int* data_ ;
} ;



This small C++ class will let you create 2 dimensional arrays of ints and index them as normal (no bound checks though!). It will also manage memory for you so no need to free memory by hand etc. You would use it like this:-



array2i test( rows, columns ) ;

test[y][x] = value ;
value_at_x_y = test[ y ][ x ] ;



b e n

amalshah71
Mar 7, 2009, 05:29 AM
Thanks guys for the explanations...that external link to multidimensional arrays really helped understanding it better....

I have many things that wherein i would store data in a lot of multidimensional arrays...

This project is meant for iPhone...

It's ok i go with NSMutableArray way...in Objective-C....

but is there no other possible way where i can create 2-d arrays of a particular primitive type....

Thanks
amal

lee1210
Mar 7, 2009, 07:32 AM
It's ok i go with NSMutableArray way...in Objective-C....


I wasn't sure if this is a question or not. If you are targeting the iPhone, using NSMutableArray is definitely an option. The things you cannot do with Cocoa Touch vs. Cocoa are many fewer than the things you can do. A downside to going with NSMutableArray is that you have to store NSObjects, so you would have to wrap each element in an NSNumber or some other wrapper class. If you really have something like 6 elements, this overhead would be negligible, but if you have millions of elements, the overhead might not be worth the simplicity.


but is there no other possible way where i can create 2-d arrays of a particular primitive type....


We have suggested 3 different methods already:
1) Wrapping the primitive in NSNumber and storing an NSMutableArray of NSMutableArrays.

2) malloc'ing space for a number of int *, then malloc'ing space for each row (or one big malloc for all of the primitives, then some slightly awkward pointer manipulation to break this memory up into rows). This requires tracking and free'ing of the pointers, though.

3) building a C++ class to handle the memory management for you. You could build 1 per primitive type, or you could likely build a single class that handles this with templates or generics. i do not know C++ well enough to say if this would actually be possible but it "feels" like it.

Are all of these ideas unsuitable? Any of them should work for you, but they all have advantages and disadvantages to consider. The NSMutableArray of NSMutableArrays will have the most overhead, followed by the C++ approach, which would have only a little overhead, followed by the C malloc approach, which would have no real overhead. However, they go in the reverse order in terms of complexity of memory management, with the C++ and Cocoa (NSMutableArray) methods being pretty equal in terms of complexity.

Describing your problem more clearly might help us suggest which of these methods is best, or even a completely different method. However, at this point it seems like you've been given more than enough suggestions. Before anyone comes up with any other ideas on how one might store a dynamic number of primitives that can be accessed via two indicies (which there are basically an infinite number of ways to do), you might want to provide more precise details on what you really need.

-Lee

GorillaPaws
Mar 7, 2009, 08:01 AM
Out of curiosity, what would be the advantage of using NSMutableArray of NSMutableArrays vs. NSMatrix (which was my first instinct when I heard the OP asking about multidimensional arrays)?

kainjow
Mar 7, 2009, 08:18 AM
NSMatrix isn't a class for holding data. It's a UI control for managing multiple UI objects called cells.

GorillaPaws
Mar 7, 2009, 10:04 AM
NSMatrix isn't a class for holding data. It's a UI control for managing multiple UI objects called cells.

Thanks, so NSMatrix is exclusively a view class then. I had remembered reading about matrices in Kochan, but had forgotten that they were multiple-dimensional arrays and not NSMatrix objects.

lazydog
Mar 7, 2009, 10:18 AM
Running the risk of sounding a bit geeky... looking at the 3 ways I think the C++ class has has the least overhead and the least complex memory management of the 3. I'm pretty sure it will also be the fastest implementation! The only overhead the C++ class has is the storage for 1 pointer and 1 int (data_ and columns_). Compare this with the C method which uses a pointer for *each* row in the array. The C++ class also mallocs the memory for the array in one chunk. It's also the simplest to use. Memory is automatically allocated when you declare an array and the memory is released automatically when it goes out of scope... just like a native C array. So apart from the way you declare an array, it works in a similar way to a native array. Also, the code it produces for indexing the array is probably very near to what would be produced by the compiler for a native 2 dimensional array . If you want to uses dynamic arrays indexed in the familiar way then I'd say the C++ class wins hands down, not that it really matters anyway.

T
but is there no other possible way where i can create 2-d arrays of a particular primitive type....


You should be able to change the C++ class easily to handle any primitive type.

Using it isn't very difficult, I'd say give it a go. All you need to do is put the class definition in a .h file, and rename any source file that uses it to .mm. That's all there is to it. It will also work on the iPhone/iPod.

b e n

lee1210
Mar 7, 2009, 11:20 AM
...I think the C++ class has has the least overhead and the least complex memory management of the 3. I'm pretty sure it will also be the fastest implementation! The only overhead the C++ class has is the storage for 1 pointer and 1 int (data_ and columns_). Compare this with the C method which uses a pointer for *each* row in the array. The C++ class also mallocs the memory for the array in one chunk. It's also the simplest to use. ...

I didn't think of the memory overhead of all of those int *, so that is a downside of the C-style approach, for sure. The second approach i suggested is only two mallocs, so it's not so bad as it relates to that, and all of your data is in one contiguous block. In terms of use, i think you get both with [][] with pretty similar performance in terms of dereferencing, etc. All in all, any of these approaches should work fine. I haven't written any appreciable amount of C++ for 8-9 years, so the first solution that's going to come to my head will always be C.

If one wanted to save the memory of all of those int *s and use a C-style approach, you could just malloc one big chunk of memory, and have a structure that has the row length, the base of the array, etc. and helper functions that decode your indicies like operator[] does in the C++ approach. I have yet to read anything from the OP re: the real-world size of this thing, and what all of those ints are for, etc. It's not worth spending a lot of time arguing the memory-cost vs. run-time cost vs. programmer complexity etc. if these arrays are really going to only have 6 elements.

-Lee

amalshah71
Mar 9, 2009, 09:15 AM
Thanks guys for the help....


Before anyone comes up with any other ideas on how one might store a dynamic number of primitives that can be accessed via two indicies (which there are basically an infinite number of ways to do), you might want to provide more precise details on what you really need.

-Lee

basically i want to draw "something"...wherein it depends on large chunk of data

Running the risk of sounding a bit geeky... looking at the 3 ways I think the C++ class has has the least overhead and the least complex memory management of the 3. I'm pretty sure it will also be the fastest implementation! The only overhead the C++ class has is the storage for 1 pointer and 1 int (data_ and columns_). Compare this with the C method which uses a pointer for *each* row in the array. The C++ class also mallocs the memory for the array in one chunk. It's also the simplest to use. Memory is automatically allocated when you declare an array and the memory is released automatically when it goes out of scope... just like a native C array. So apart from the way you declare an array, it works in a similar way to a native array. Also, the code it produces for indexing the array is probably very near to what would be produced by the compiler for a native 2 dimensional array . If you want to uses dynamic arrays indexed in the familiar way then I'd say the C++ class wins hands down, not that it really matters anyway.



You should be able to change the C++ class easily to handle any primitive type.

Using it isn't very difficult, I'd say give it a go. All you need to do is put the class definition in a .h file, and rename any source file that uses it to .mm. That's all there is to it. It will also work on the iPhone/iPod.

b e n

Thanks for this....after reading all posts i settled to go for the C-style way...but after this post...i think c++ approach would be a balanced one...

It's not worth spending a lot of time arguing the memory-cost vs. run-time cost vs. programmer complexity etc. if these arrays are really going to only have 6 elements.

-Lee

no...it's not 6 elements...i would be having something around 6000 int's...8000 long's....in a 2-d array...that's huge...


Thanks guys...things now seem to be clear of which way to go...

Thanks
amal