4

How to return a C-style array of integers from an Objective-C method? This is what my code looks like so far:

Function call:

maze = [amaze getMaze];

Function:

-(int*) getMaze{
    return maze;
}

I just started writing in Objective-C today so this is all new to me.

Pang
  • 9,564
  • 146
  • 81
  • 122
mlclmss
  • 107
  • 1
  • 3
  • 6

4 Answers4

6

In C if you need to return an array from a function, you need to allocate memory for it using malloc and then return the pointer pointing to the newly allocated memory.

Once you're done working with this memory you need to free it.

Something like:

#include <stdlib.h> /* need this include at top for malloc and free */

int* foo(int size)
{
    int* out = malloc(sizeof(int) * size); /* need to get the size of the int type and multiply it 
                                            * by the number of integers we would like to return */

    return out; /* returning pointer to the function calling foo(). 
                 * Don't forget to free the memory allocated with malloc */
}

int main()
{
    ... /* some code here */

    int* int_ptr = foo(25); /* int_ptr now points to the memory allocated in foo */

    ... /* some more code */

    free(int_ptr); /* we're done with this, let's free it */

    ...

    return 0;
}

This is as C style as it gets :) There are probably other (arguably more suitable) ways to do this in Objective C. However, as Objective C is considered a strict superset of C, this would also work.

If I may further expand on the need to do this by pointers. C-style arrays allocated in a function are considered local, once the function is out of scope they are automatically cleaned up.

As pointed out by another poster, returning a standard array (e.g. int arr[10];) from a function is a bad idea as by the time the array is returned it no longer exists.

In C we get around this problem by allocating memory dynamically using malloc and having a pointer that points to that memory returned.

However unless you free this memory adequately, you may introduce a memory leak or some other nasty behavior (e.g. free-ing a malloc-ed pointer twice will produce unwanted results).

Community
  • 1
  • 1
Nobilis
  • 7,310
  • 1
  • 33
  • 67
  • this is very likely to intoduce memory leak and we want to avoid manual memory management as much as possible – Bryan Chen Jun 13 '13 at 02:58
  • Agreed, I've hopefully made it clear that this is C only and that Objective C probably has better ways of doing this :) – Nobilis Jun 13 '13 at 03:00
4

Given you explicitly ask about C-style arrays no suggestions here that you should use NSArray etc.

You cannot return a C-style array directly (see below) as a value in Objective-C (or C or C++), you can return a reference to such an array.

Types such as int, double and struct x can all be passed by value - that is the actual bits representing the value are passed around. Other things; such as C-style arrays, dynamically allocated memory, Objective-C style objects, etc.; are all passed by reference - that is a reference to a location in memory that contains the actual bits the represent the value is passed around.

So to return a C-style array from a function/method you can:

  1. Dynamically (malloc et al) an array and return the reference to the allocated memory;
  2. Pass in a reference to an already existing array and have the function fill it up; or
  3. Wrap the array up as a struct...

The normal choices are (1) or (2) - note you cannot return a reference to a stack allocated array, as in:

int *thisIsInvalid()
{
   int myValues[5];
   ...
   return myValues; // will not work, the type is correct but once function
                    // returns myValues no longer exists.
}

If you really want to return a (small) array by value you can actually do it using (3). Remember that struct values are passed by value. So the following will work:

typedef struct
{
   int array[5];
} fiveInts;

fiveInts thisIsValid()
{
   fiveInts myValues;
   ...
   myValues.array[3] = ...; // etc.
   ...
   return myValues;
}

(Note that there is no overhead from wrapping the array inside a struct when it comes to reading/writing the array - the cost in the above is copying all the values back - hence only advised for small arrays!)

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86
0
- (NSArray *)toArray:(int *)maze {
   NSMutableArray *retVal = [[NSMutableArray alloc] init];
   for (int c = 0; maze[c] != NULL; c++) {
      [retVal addObject:[NSNumber numberWithInt:maze[c]]];
   }
   return [retVal array];
}

I've never been comfortable passing mutable data in and out of methods and not sure why. If you need to change the values later, send the array a mutableCopy message.

hd1
  • 33,938
  • 5
  • 80
  • 91
-1

you can do it in this way

- (void)getArray:(int *)array withLength:(NSUInteger)length{
    for (int i = 0; i < length; i++)
        array[i] = i;
}

int array[3];
[object getArray:array withLength:3];
NSLog(@"%d %d %d", array[0], array[1], array[2]);  // 1 2 3
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • I'm pretty sure your first code example is bugged. You can't return an array, because it decays into a pointer into the stack frame that's about to get popped. – Chuck Jun 13 '13 at 06:43
  • @Chuck No you are wrong. I have checked the assemble code and found it use `objc_msgSend_stret` which means the array is treated as struct. Or if you think I am wrong and you know the truth, you can answer my question http://stackoverflow.com/questions/16709923/return-fixed-size-array – Bryan Chen Jun 13 '13 at 07:12
  • @xlc - Sorry Chuck is correct. I hadn't seen your question, which had gone unanswered by all. I've added an answer for you. – CRD Jun 13 '13 at 20:46