The other big way that C extends its range of data types is by means of pointers (K&R 5.1). A pointer is an integer (of some size or other) with a meaning: it designates the location in memory where the real data is to be found. Knowing the structure of that data and how to work with it, as well as allocating a block of memory of the required size beforehand and disposing of that block of memory when it’s no longer needed, is a very complicated business. Luckily, this is exactly the sort of complicated business that Objective-C is going to take care of for us. So all you really have to know in order to use pointers is what they are and what notation is used to refer to them.

Let’s start with a simple declaration. If we wanted to declare an integer in C, we could say:

int i;

That line says, “i is an integer.” Now let’s instead declare a pointer to an integer:

int* intPtr;

That line says, “intPtr is a pointer to an integer.” Never mind how we know there really is going to be an integer at the address designated by this point; here, I’m concerned only with the notation. It is permitted to place the asterisk in the declaration before the name rather than after the type:

int *intPtr;

I don’t generally use that second form when declaring a pointer, but it does come in handy when declaring several variables of the same type in a single statement. Here’s what I mean. It is legal, though I did not mention this earlier, to declare multiple variables of a single type in one statement, like this:

int i, j, k;

By the same token, it is possible to declare multiple pointers to the same type in one statement by attaching the asterisk to the variable name (repeatedly):

int *intPtr1, *intPtr2, *intPtr3;

However, the name of the type is still int*. If you are asked what type is intPtr is, the answer is int* (a pointer to an int); the asterisk is part of the name of the type of this variable. If you needed to cast a variable p to this type, you’d cast like this: (int*)p.

Pointers are very important in Objective-C, because Objective-C is all about objects (Chapter 2), and every variable referring to an object is itself a pointer. For example, I’ve already mentioned that the Objective-C string type is called NSString. So the way to declare an NSString variable is as a pointer to an NSString:

NSString* s;

An NSString literal is an NSString value, so we can even declare and initialize this NSString object, thus writing a seriously useful line of Objective-C code:

NSString* s = @"Hello, world!";

In pure C, having declared a pointer-to-integer called intPtr, you are liable to speak later in your code of *intPtr. This notation, outside of a declaration, means “the thing pointed to by the pointer intPtr.” You speak of *intPtr because you wish to access the integer at the far end of the pointer.

But in Objective-C, this is generally not the case. In your code, you’ll be treating the pointer to an object as the object. So, for example, having declared s as a pointer to an NSString, you will not then proceed to speak of *s; rather, you will speak simply of s, as if it were the string. All the Objective-C stuff you’ll want to do with an object will expect the pointer, not the object at the far end of the pointer; behind the scenes, Objective-C itself will take care of the messy business of following the pointer to its block of memory and doing whatever needs to be done in that block of memory. This fact is extremely convenient for you as a programmer, but it does cause Objective-C users to speak a little loosely; we tend to say that “s is an NSString,” when of course it is actually a pointer to an NSString.

You must never let this convenience lull you into forgetting the crucial fact that a pointer is a pointer. The logic of how pointers work is different from the logic of how simple data types work. The difference is particularly evident with assignment. Assignment to a simple data type changes the data value. Assignment to a pointer repoints the pointer. Suppose ptr1 and ptr2 are both pointers, and you say:

ptr1 = ptr2;

Now ptr1 and ptr2 are pointing at the same thing. Any change to the thing pointed to by ptr1 will also change the thing pointed to by ptr2, because they are the same thing. Meanwhile, whatever ptr1 was pointing to before the assignment is now not being pointed to by ptr1; it might, indeed, be pointed to by nothing (which could be bad). A firm understanding of these facts is crucial when working in Objective-C (Figure 1-1).

Pointers and assignment

Figure 1-1. Pointers and assignment

The most general type of pointer is pointer-to-void (void*), the generic pointer. It is legal to use a generic pointer wherever a specific type of pointer is expected. In effect, pointer-to-void casts away type checking as to what’s at the far end of the pointer. Thus, the following is legal:

int* p1; // and pretend p1 has a value
void* p2;
p2 = p1;
p1 = p2;

Get Programming iOS 4 now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.