Memory Allocation for the budding Objective-C programmer

… or, “How I Learned to Stop Worrying and Love malloc”

OK, here’s a scenario:

You have a whole crapload of ints, or floats, or even CGPoints or CGRects. You need to hang onto these things and use them later. Hopefully you are not even considering making a whole crapload of variables to store them in, i.e. myNumber0, myNumber1, myNumber2, etc. If that even crossed your mind, close the browser, turn off the computer, go straight to the book store and pick up the first Programming for Dummies book you can find.

No, of course you immediately thought, “Array!” Good! Now, in Objective-C we have NSArrays and NSMutableArrays. NSArrays have to be initialized with all their content and cannot thereafter change. NSMutableArrays can have things added, removed, and altered at any time. Say you go for the mutable species, and say you want to use it to store a bunch of ints. I guarantee your first attempt would look something like this:

[c]NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity:10];
[myArray addObject:0];
[myArray addObject:1];
[myArray addObject:2];
[myArray addObject:3];
[myArray addObject:4];
[myArray addObject:5];
[myArray addObject:6];
[myArray addObject:7];
[myArray addObject:8];
[myArray addObject:9];
[/c]

And as you run your app, it’s going to crash. Hard.

Or say you try to add some points:

[c][myArray addObject:CGPointMake(100, 100)];[/c]

Now you are going to get an error like: “incompatible type for argument 1 of ‘addObject'” Why? because ints are not objects. They are primitive types. In Objective-C, an object is something that extends NSObject.

An int is not an object, but I believe will get interpreted as a pointer. And when it tries to read the “objects” at memory locations 0 through 10, it doesn’t find what it’s looking for.

CGPoints and CGRects are also not objects. They are structs. A struct is essentially a chunk of memory that can hold multiple values of multiple types. A CGPoint holds two floats. In fact, you can see the actual definition by Command-clicking on CGPoint in XCode:

[c]struct CGPoint {
CGFloat x;
CGFloat y;
};
typedef struct CGPoint CGPoint;[/c]

(CGFloat is just a typedef for float.)

A struct is not an NSObject so you get an error.

One solution would be to wrap the int in an object. Objective-C has a NSNumber object for this purpose. So you change the code to something like this:

[c][myArray addObject:[NSNumber numberWithInt:0]];
[myArray addObject:[NSNumber numberWithInt:1]];
[myArray addObject:[NSNumber numberWithInt:2]];
//etc.[/c]

Now, when you want to get those ints back, you do something like this:

[c]myInt = [[myArray objectAtIndex:0] intValue];[/c]

I don’t know about you, but that’s an awful lot of overhead for saving and reading a list of integers.

But let’s look at structs. There is no “NSPoint” or “NSRect” so you’d have to create your own class that extends NSObject, wraps up a point or a rectangle, makes it accessible as a public var or a property, and use that in your array. So you get something perhaps like this:

[c][myArray addObject:[MyRectObject objectWithRect:CGRectMake(0, 0, 100, 100)]];[/c]

and similarly wicked verbose code to retrieve the value. And not only is does it take up finger resources to type all that, it takes CPU and memory resources to create all those extra objects, and access them via various methods, not to mention the fact that you’re going through high level “objectAtIndex” methods in the array class itself.

So let’s look at a much simpler way to do it. Enter malloc.

malloc means memory allocation. It’s a very low level, core C function that lets you directly allocate a chunk of raw memory and use it how you want. Powerful stuff. Blah blah blah great power, blah blah blah responsibility. In other words, you have the power to seriously crash your computer/iDevice. And you probably will. So get over it. It’s not going to melt or explode. But you may have to reboot it every once in a while until you learn the ropes.

Basically, you call malloc as a function, passing in how many bytes of memory you would like. The system reserves that chunk of memory for you and hands you back a pointer to it. You should cast this data as a pointer to the type of data you are storing in it. Like so:

[c]int *myInts = malloc(numberofbytestoallocate);[/c]

So how many bytes should you allocate? Well, it depends on how many “things” you want to store in there, and how big those “things” are. The first part you probably know, the second you probably don’t. Luckily there’s a sizeof function that will figure that out for you. So you do something like this if you are storing 10 integers:

[c]int *myInts = malloc(sizeof(int) * 10);[/c]

Or if you are storing 50 CGPoints:

[c]CGPoint *myPoints = malloc(sizeof(CGPoint) * 50);[/c]

You get the point. Or the 50 points. (I crack myself up sometimes!)

Now, you can access that chunk of memory with bracket notation:

[c]myInts[0] = 10;
myInts[1] = 20;
myInts[2] = 30;
myInts[3] = 40;
// etc.[/c]

Or:

[c]someNumber = myInts[8];[/c]

Very simple, very low level, very efficient. Also, very dangerous. If you suddenly decide to say something like:

[c]myInts[99] = 50;[/c]

and you only allocated enough space for 10 ints, you have no protection whatsoever. Your program is going to go to whatever location myInts[99] happens to land on and write the int value 50 there, with no regard for any consequences. You’re not going to get a compiler error. You’re not even going to get a runtime error that politely tells you are attempting to access an element of an array that is out of bounds, so sorry for the inconvenience. No, it’s just going to do exactly what you tell it to and claim it was just following orders. Generally, this means your app is going to crash and burn, fast and hard, with no explanation at all. So don’t do it. OK, you’re going to do it. But after a few times, you’ll realize what you did and you’ll do it much less often.

Generally this means that you are going to keep an extra int or two around to serve as indexes. Maybe one to indicate the maximum amount of values you CAN store in the array, and one to indicate how many values actually ARE in there. For example:

[c]#define MAX_THINGS 100
int *things = malloc(sizeof(int) * MAX_THINGS);
int numThings = 10;
for(int i = 0; i < numThings; i++) { things[i] = i; }[/c] You don't want MAX_THINGS to change, so that's a good candidate for #define. numThings could change so we'll leave that as an int. Here, since we are only setting the first 10 out of 100 things, the other 90 will have garbage values. You're totally safe to read and write them, but don't expect them to have any meaningful value until you set them. The last thing to mention is to clean up after yourself. You asked for a chunk of memory, and the system was nice enough to give it to you. Actually, it just lent it to you. When you are done, give it back so someone else can use it. Do this using the free function: [c]free(myInts);[/c] Where you do this is wherever it makes sense. If you are just using the array as a local variable in a method, free it up as soon as you are done using it. If it's a instance variable of a class, free it in the dealloc method. That's the bare bones of malloc. There might be other things you want to look up. For instance, what if you ask for a big chunk of memory and the system can't allocate it. Generally 10 ints or 50 CGPoints won't be a problem, but you might want to look at what happens if malloc fails, to make sure you guard against that. So happy mallocing, happy crashing. Once you get the hang of it, it's a pretty cool feeling to have that kind of fine level of control over the memory your program is using, especially if you are coming from the ActionScript world, where memory management is a secret black box that occasional posts by Grant Skinner gives you some shadowy concept of what's going on in there. With C and malloc, you know, because you are calling the shots.

This entry was posted in iPhone, Objective C. Bookmark the permalink.

20 Responses to Memory Allocation for the budding Objective-C programmer

  1. Or just use Objective c++ and the c++ STL container classes like std::vector, std::list, etc. No hassles with malloc needed 🙂

  2. jtgrassie says:

    Or of course you can use new/delete instead of malloc/free…

    int *myInts = new int[10]; // for array of 10 ints

    // and later free them…

    delete [] myInts;

  3. kp says:

    stephan, sure, but this is for the “budding Objective-C programmer”. 🙂 One step at a time.

    jtgrassie, that, too, is C++ (or java), but will not work in Objective-C.

    Another one I realized I should mention is calloc. You pass in the number of things and the size of each thing, like so:

    int *myInts = calloc(10, sizeof(int));

    The main difference here is that the area of memory allocated will be cleared out to 0, whereas with malloc, it is unchanged.

  4. jtgrassie says:

    @kp Actually it is C++ and will work absolutely fine in a Obj C/C++.

    And as stephan points out, sensible to make use of the STL containers (especially if you are comparing to NSMutableArray).

  5. kp says:

    You’re saying you can type

    int *myInts = new int[10];

    or

    delete [] myInts;

    in an Objective-C file and have it compile? I get “error: ‘new’ undefined (first use in this function)” and same for ‘delete’.

    AFAIK, new and delete are C++, not C.

  6. jtgrassie says:

    @kp
    To use c++ in an objective c file, you either have to tell the compiler you are also using c++ (via xobjective-c++ switch) or give the file the .mm extension.

    Also not there is no “or”. You must use ‘delete’ to free objects allocated with ‘new’.

    • kp says:

      Right. So, as I was saying all along, new and delete are not in C. I understand you can use C++, but if you are not using that, malloc is the way to go. The article was for “the budding Objective-C developer”, which I guess I consider myself as well. I guess Objective-C++ will be in my near future. 🙂

  7. jtgrassie says:

    I highly recommend anyone new to Objective-C/C++ to read the Apple language guide:
    http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html#//apple_ref/doc/uid/TP30001163-CH1-SW2

    And specifically for mixing in C++:
    http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocCPlusPlus.html#//apple_ref/doc/uid/TP30001163-CH10-SW1

    And really, stephan is got it spot on, if you need a mutable collection of primitive types, its more sensible to use one of the STL containers.

  8. kp says:

    btw, I don’t mean to sound defensive. I really appreciate the feedback and additional data.

  9. jtgrassie says:

    No offence taken Keith 🙂

    The reason I highlight this is really because of one of the biggest strengths of Objective-C/C++, the fact you can mix C, C++ and Objective-C all together.
    This allows you to use what’s best / most appropriate language for given problem. I don’t think there is any valid reason to disregard C++ usage in Objective-C, especially when it offers an elegant solution to a given problem.

    For the specific problem you highlight – a mutable array of primitive types – an STL container really is the way to go.
    If you really are going to bother describing malloc and free for a mutable array, you really should also describe realloc (which is what you are going to need to shrink and grow your array).
    http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/

  10. kp says:

    on the current project I’m working on, I’m heavily using primitive arrays as vector arrays for OpenGL drawing. I think this is a necessity because OpenGL takes pointers to various types of arrays directly. Could you use STL containers in that context, or would you need to convert them?

  11. jtgrassie says:

    With a STL Vector certainly.
    The elements are guaranteed to be stored in contiguous storage locations. Just grab the pointer to the first element and pass that to GL functions requiring c array.

  12. kp says:

    ok, well that is enticing.

  13. Markus says:

    “int *myPoints = malloc(sizeof(CGPoint) * 50);”

    myPoints[0]= CGPointMake(100, 100);
    myPoints[1]= CGPointMake(110, 110);
    myPoints[2]= CGPointMake(120, 120);”

    wouldn’t the [1] overwrite parts of the previous defined point? The compiler always increases the pointer by one byte using the brackets,
    since it doesn’t have any information about of the size of each object.

    so the correct syntax should be:

    myPoints[0]= CGPointMake(100, 100);
    myPoints[sizeof(CGPoint)]= CGPointMake(110, 110);
    myPoints[sizeof(CGPoint)*2]= CGPointMake(120, 120);”

    or did I miss something?

    • kp says:

      Markus, array notation is magical. It knows how many bytes are in each element. You made your array as a pointer to int: int *myPoints

      If you make it a pointer to CGPoint, you’ll be all set: CGPoint *myPoints.

  14. umm... says:

    To clarify on what Markus said, look at your post again…

    It uses int *myInts = malloc(sizeof(CGPoint) * 50);

    I’m guaranteed that’s a mistake.

  15. kp says:

    oops. Right you are. My bad. Fixed now. That’s what happens when you copy and paste code. 🙂

  16. SSI says:

    Can any body tell me how to allocate a chunk of memory at desired memory address using malloc or any other function in C/C++?

  17. SSI says:

    OR how to write at desired memory location(address) in C/C++?

Leave a Reply