5

I am coming from Java, and I'm very new to Objective C. Anyway, I have this static method which is designed to make a copy of an array (if there's a better way to accomplish this, please let me know, but I'm asking this question more-so to find out why I got this error and how to avoid such an error in the future.) I ran into some problems with it, but just when I thought I had them all sorted out, I got this error that looked like XCode

Here is the method in the interface:

+ (float[]) copyArray: (float[]) array withLength: (int) length;

And here is the method in the implementation:

+ (float[]) copyArray: (float[]) array withLength: (int) length
{
    float copiedArray[length];
    for (int i = 0; i < length; i++)
    {
        copiedArray[i] = array[i];
    }
    return copiedArray;
}
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
michaelsnowden
  • 6,031
  • 2
  • 38
  • 83

5 Answers5

6

If all you really want is to copy the first n elements from one C array into another already existing array, probably the best way is to simply use memcpy:

memcpy(targetArray, sourceArray, sizeof(sourceArray[0]) * numElements);

The sizeof(sourceArray[0]) calculates the byte-size of the type in your array (in your case, it's equivalent to sizeof(float).

DarkDust
  • 90,870
  • 19
  • 190
  • 224
4

method/function cannot return C array. you should do this

+ (void) copyArrayFrom:(float *)array to:(float *)toArray withLength: (unsigned) length
{
    for (int i = 0; i < length; i++)
    {
        toArray [i] = array[i];
    }
}
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • 1
    Now if you don't mind, do you think I should be using C-style arrays and your method, or just stick to NSArrays. My application is really memory-intensive, so if C-style is faster, that would be really important. – michaelsnowden Jan 05 '14 at 21:53
  • Nonsense. Objective-C methods can return any C type. – jlehr Jan 05 '14 at 21:54
  • 1
    @jlehr What do you mean? – michaelsnowden Jan 05 '14 at 21:56
  • @doctordoder depends. if these array are used for OpenGL/CoreGraphics/Other C API, use C array. if you are passing them around to other ObjC API, use NSArray – Bryan Chen Jan 05 '14 at 21:56
  • The answer incorrectly states: "method/function cannot return C array." That's completely false. – jlehr Jan 05 '14 at 21:57
  • @jlehr it is possible to return C *pointer*, but not C *array*. but return *pointer* will make memory management a mess – Bryan Chen Jan 05 '14 at 21:57
  • @BryanChen I'm just designing a fairly simple application with XCode on their default OpenGL template, but it's still going to need to be as conservative on memory as possible. – michaelsnowden Jan 05 '14 at 22:01
2

C arrays are way more tricky than Java arrays. One of the biggest issues is that in a lot of instances, you don't know how large a C array is unless you have saved this information in a different variable, for example. The C FAQ "Arrays and Pointers" lists a lot of traps and they apply to Objective-C as well. You might want to see question 6.5 in particular.

As @lwxted already suggested, try to avoid C arrays unless you really know what you're doing and you have determined that you need them. C arrays are faster than NSArray but unless you have determined that your array really is a performance bottleneck by measuring with a profiler you will most likely not notice any difference.

And I strongly recommend avoiding a C array of Objective-C objects (id objects[]) unless you really, really know very well what you are doing (memory management issues).

DarkDust
  • 90,870
  • 19
  • 190
  • 224
1

In Objective-C, unless for particular needs, a better way to handle this usually is to use the NSArray as opposed to C arrays.

[NSArray arrayWithArray: array];

will copy an array.

Besides, in this case, if you insist on using C arrays, the use of implicitly typed length float[] is advised against. A better way is to use pointers to manipulate arrays.

Also, the stack-allocated array would be invalid after leaving the function, since it's local only in the scope of the copyArray function. You should dynamically allocate memory, if you wish the array to be valid outside the scope.

lwxted
  • 2,419
  • 2
  • 16
  • 22
  • +1, I was also going to suggest avoiding C arrays unless there is a very good reason to go for a C array. But all you need then is `[myArray copy]`, not a dedicated method. – DarkDust Jan 05 '14 at 21:42
  • 2
    Why would you ever write a method that does nothing but return the value returned by `[NSArray arrayWithArray:]`? – jlehr Jan 05 '14 at 21:42
  • Yeah... Just trying to make the point that `NSArray` should be used. Fixed. – lwxted Jan 05 '14 at 21:43
  • @jlehr because I want to deal with the float[]-style array because my application deals a lot with OpenGL. Coming from Java, that was the way to do it, but if NSArray works just as well as the regular float[]-style array, then this method would be totally pointless, yes. – michaelsnowden Jan 05 '14 at 21:44
  • 1
    `[array copy]` is easier than `[NSArray arrayWithArray: array]` – Bryan Chen Jan 05 '14 at 21:44
  • Ok, like I predicted in my question, there is a better way to do what I'm trying to do, at least for an NSArray, but is this possible with just a float[]-style, or other primitive[]-style array? – michaelsnowden Jan 05 '14 at 21:46
  • I believe you can use a C array; you should dynamically allocate the memory in the function though. Using pointer is also more recommended than using `float[]`. – lwxted Jan 05 '14 at 21:48
1

While I agree with all the points @DarkDust makes, if you're working with a C API such as OpenGL, there may be situations where using NSArray and NSNumber vs. C arrays of type float will have performance impacts. As always, try to use the simpler approach first, and carefully measure performance before deciding to optimize.

In any case, to answer the original question, here's how to correctly return a copy of a C array:

+ (float *)copyOfCArray:(float *)array withLength:(int)length
{
    float *copyOfArray = malloc(length * sizeof(float));

    for (int i = 0; i < length; i++) {
        copyOfArray[i] = array[i];
    }

    return copyOfArray;
}

Also, there's arguably no need to make the above a method at all. Instead, consider writing it as a C function:

float *CopyArray(float *array, int length)
{
    // Implementation would be the same...
}
jlehr
  • 15,557
  • 5
  • 43
  • 45
  • 1
    don't do this. it will leak memory. because someone will forget to call `free` on returned value. BTW `sizeof(array)/sizeof(float)` does not make sense (it will be 1 in most of the cases) – Bryan Chen Jan 05 '14 at 22:07
  • @BryanChen Heh, you're right, the sizeof stuff I grabbed from a slightly different context. Updating now. – jlehr Jan 05 '14 at 22:11
  • @jlehr Wow, those look like the fastest and most concise approaches, but before I really move forward with this, when you say "the simplest approach," I agree, but do you mean that using an NSArray is the simplest approach? – michaelsnowden Jan 05 '14 at 22:13
  • @BryanChen Function naming conventions convey the same kinds of things about memory management semantics as method names, so a method or function that begins with `copy` or `create` implies ownership. – jlehr Jan 05 '14 at 22:15
  • 1
    @doctordoder Heh, that depends to some degree on the developer. The answer might be different for an ace C programmer with little experience in Objective-C. But yes, `NSArray` and other Foundation classes are extremely powerful wrappers around low-level C code that can be very tricky to write and maintain correctly. – jlehr Jan 05 '14 at 22:17
  • still, this does add one more way to leak memory. and you stop the possibility to allocate memory on stack (when size is small). – Bryan Chen Jan 05 '14 at 22:17
  • @BryanChen And that's the nature of optimizations -- they generally add some complexity and risk in order to achieve better performance. Note, I didn't recommend starting with this approach, but it does directly answer the OP's original question, (though @DarkDust's suggestion to use `memcpy` is even better). – jlehr Jan 05 '14 at 22:19
  • 1
    I think I'll move forward with the NSArrays then, and once my application is fully-functional, I'll start profiling and optimizing – michaelsnowden Jan 05 '14 at 22:20