22

Can we convert an NSArray to a C array?

If not what alternatives, are there? Suppose I need to feed the C array to OpenGL functions where the C array contains vertex pointers read from plist files.

3 Answers 3

41

The answer depends on the nature of the C-array.

If you need to populate an array of primitive values and of known length, you could do something like this:

NSArray* nsArray = [NSArray arrayWithObjects:[NSNumber numberWithInt:1],
                                             [NSNumber numberWithInt:2],
                                             nil];
int cArray[2];

// Fill C-array with ints
int count = [nsArray count];

for (int i = 0; i < count; ++i) {
    cArray[i] = [[nsArray objectAtIndex:i] intValue];
}

// Do stuff with the C-array
NSLog(@"%d %d", cArray[0], cArray[1]);

Here's an example where we want to create a new C-array from an NSArray, keeping the array items as Obj-C objects:

NSArray* nsArray = [NSArray arrayWithObjects:@"First", @"Second", nil];

// Make a C-array
int count = [nsArray count];
NSString** cArray = malloc(sizeof(NSString*) * count);

for (int i = 0; i < count; ++i) {
    cArray[i] = [nsArray objectAtIndex:i];
    [cArray[i] retain];    // C-arrays don't automatically retain contents
}

// Do stuff with the C-array
for (int i = 0; i < count; ++i) {
    NSLog(cArray[i]);
}

// Free the C-array's memory
for (int i = 0; i < count; ++i) {
    [cArray[i] release];
}
free(cArray);

Or, you might want to nil-terminate the array instead of passing its length around:

// Make a nil-terminated C-array
int count = [nsArray count];
NSString** cArray = malloc(sizeof(NSString*) * (count + 1));

for (int i = 0; i < count; ++i) {
    cArray[i] = [nsArray objectAtIndex:i];
    [cArray[i] retain];    // C-arrays don't automatically retain contents
}

cArray[count] = nil;

// Do stuff with the C-array
for (NSString** item = cArray; *item; ++item) {
    NSLog(*item);
}

// Free the C-array's memory
for (NSString** item = cArray; *item; ++item) {
    [*item release];
}
free(cArray);
Sign up to request clarification or add additional context in comments.

2 Comments

This is a great answer, I wish I could up vote more than once. I do have one suggestion which is that the use of the NSString** type is a bit obfuscated. I suggest using [NSData initWithBytesNoCopy:length:freeWhenDone:] with the pointer that malloc returns, and the size of the array.
I tried the second approach that uses malloc, I think it requires arc to be disabled. At least, that is how I got it to work. Maybe arc did not exist when this question was asked....
6

NSArray has a -getObjects:range: method for creating a C-array for a subrange of an array.

Example:

NSArray *someArray = /* .... */;
NSRange copyRange = NSMakeRange(0, [someArray count]);
id *cArray = malloc(sizeof(id *) * copyRange.length);

[someArray getObjects:cArray range:copyRange];

/* use cArray somewhere */

free(cArray);

2 Comments

That won't convert the NSNumber objects to a primitive numeric type, though. The questioner needs that conversion to use the C array with OpenGL; because of that, they might as well populate the C array entirely themselves, without ever putting NSNumbers into it.
ahhh! Didn't see the OpenGL requirement for the problem. In that case yes, iterating the array manually would be appropriate.
5

I would suggest to convert yourself, with something like:

NSArray * myArray;

... // code feeding myArray

id table[ [myArray count] ];

int i = 0;
for (id item in myArray)
{
    table[i++] = item;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.