Showing posts with label Pointer Parameters and the Address Operator. Show all posts
Showing posts with label Pointer Parameters and the Address Operator. Show all posts

Wednesday, December 4, 2013

Pointer Parameters and the Address Operator


Objective-C is chock-a-block with pointers (and asterisks), because that’s how Objective-C refers to an object. Objective-C methods typically work with objects, so they typically expect pointer parameters and return a pointer value. But this doesn’t make things more complicated. Pointers are what Objective-C expects, but pointers are also what Objective-C gives you. Pointers are exactly what you’ve got, so there’s no problem.

For example, one way to concatenate two NSStrings is to call the NSString method stringByAppendingString:, which the documentation tells you is declared as follows:
    - (NSString *)stringByAppendingString:(NSString *)aString

This declaration is telling you (after you allow for the Objective-C syntax) that this method expects one NSString* parameter and returns an NSString*. That sounds messy, but it isn’t, because every NSString is really an NSString*. So nothing could be simpler than to obtain a new NSString consisting of two concatenated NSStrings:
    NSString* s1 = @"Hello, ";
    NSString* s2 = @"World!";
    NSString* s3 = [s1 stringByAppendingString: s2];

Sometimes, however, a function or method expects as a parameter a pointer to a thing, but what you’ve got is not that pointer but the thing itself. Thus, you need a way to create a pointer to that thing. The solution is the address operator (K&R 5.1), which is an ampersand before the name of the thing.
For example, there’s an NSString method for reading from a file into an NSString, which is declared like this:
    + (id)stringWithContentsOfFile:(NSString *)path
                          encoding:(NSStringEncoding)enc
                             error:(NSError **)error	
Never mind for now what an id is, and don’t worry about the Objective-C method declaration syntax. Just consider the types of the parameters. The first one is an NSString*; that’s no problem, as every reference to an NSString is actually a pointer to an NSString. An NSStringEncoding turns out to be merely an alias to a primitive data type, an NSUInteger, so that’s no problem either. But what on earth is an NSError**?
By all logic, it looks like an NSError** should be a pointer to a pointer to an NSError. And that’s exactly what it is. This method is asking to be passed a pointer to a pointer to an NSError. Well, it’s easy to declare a pointer to an NSError:
    NSError* err;
But how can we obtain a pointer to that? With the address operator! So our code might look, schematically, like this:
    NSString* path = // something or other
    NSStringEncoding enc = // something or other
    NSError* err = nil;
    NSString* result =[NSString stringWithContentsOfFile: path encoding: enc error: &err];
The important thing to notice is the ampersand. Because err is a pointer to an NSError, &err is a pointer to a pointer to an NSError, which is just what we’re expected to provide. Thus, everything goes swimmingly.
You can use the address operator to create a pointer to any named variable. A C function is technically a kind of named variable, so you can even create a pointer to a function! This is an example of when you’d use the name of the function without the parentheses: you aren’t calling the function, you’re talking about it. For example, &square is a pointer to the square function. Moreover, just as the bare name of an array is implicitly a pointer to its first element, the bare name of a function is implicitly a pointer to the function; the address operator is optional.