Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

mysterytramp

macrumors 65816
Original poster
Jul 17, 2008
1,334
4
Maryland
In Kochan's book, as he's going through his Fraction class, he creates a method to add two fractions:

-(void) add: (Fraction *) f:

The (Fraction *) is to typecast the f variable but he doesn't explain why the asterisk is there, only that it's required. It seems like an odd construct. Why wouldn't (Fraction) f: work?

It's a stupid thing, I know, but it's one of those things that seems important before moving forward.

mt
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,566
In Kochan's book, as he's going through his Fraction class, he creates a method to add two fractions:

-(void) add: (Fraction *) f:

The (Fraction *) is to typecast the f variable but he doesn't explain why the asterisk is there, only that it's required. It seems like an odd construct. Why wouldn't (Fraction) f: work?

It's a stupid thing, I know, but it's one of those things that seems important before moving forward.

First, the (Fraction *) is not a typecast at all. It is just part of the syntax how to declare the types of parameters in Objective-C methods: To declare a parameter, you write the type of the parameter, enclosed in parentheses, followed by the parameter name. So what we have here is an object method (not a class method, because of the "-") named add:, returning void (= nothing), taking a parameter named f of type Fraction*. No typecast here.

Second, you never, ever use Objective-C objects directly. You would never have a variable like

Fraction x;

or a parameter

(Fraction) f

assuming that Fraction is an Objective-C class. You _always_ create an Objective-C object by calling alloc followed by init (possibly calling a function that does it for you), and then you have a pointer to that object that you use everywhere.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
gnasher729 covered this for the most part, but I wanted to ensure that you understand the C syntax that is being used. In C, and therefore Obj-C, * is used in 3 ways. One is the binary multiplication operator, which takes 2 primitive types and multiplies their values, and evaluates to the result of the multiplication. The second is part of a type in declarations, method signatures, etc. It is used to indicate a pointer to a certain type. This means that, say, an int* stores a pointer, and when the pointer is dereferenced the memory pointed to will be evaluated as an int. This can be done using the unary dereference operator, *(it's third use) or the binary array access operator [], which takes a pointer and an offset.

As was stated above, in Obj-C all object instances are stored on the heap, so all local variables dealing with objects are pointers to this heap memory. This is why you have all local variables and signatures referring to pointers to objects (NSObject *), instead of just a plain object name.

This differs from C++, where you can have local object instances, or pointers that you initialize with a call to new, that gives you a heap pointer.

-Lee

P.S. It's probably not that relevant, but there's another way to get at the juicy data that a pointer directs you to, but it only applies when you are using structs. If you have a pointer to a struct, there is a binary field indirection operator that can be used on the pointer to access fields of the structure immediately without explicitly dereferencing the pointer. It is the -> operator, and the left operand is the pointer to the struct, and the right operand is the field name. str_ptr->fieldname is really just a shortcut for (*str_ptr).fieldname. Again, this probably isn't relevant, but is another operator that deals with pointers.
 

mysterytramp

macrumors 65816
Original poster
Jul 17, 2008
1,334
4
Maryland
Thanks. I get it ... mostly.

One of the first things I read about C involved how difficult it was to learn pointers. Years ago I taught myself Pascal and the concept of pointers (and handles) seemed fairly straightforward. C seems to make things deliberately obtuse.

Thanks again.

mt
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
I think that understanding the concept of a pointer is much more important than the syntactical means of declaring and accessing a pointer. I think that the complexity of pointers is overblown to the point that they become intimidating and people try to get away with the most minimal understanding possible.

All a pointer is is a place to store a memory address. Everything else is implementation details. There are pointers in assembly in every architecture I've seen (admittedly few). Sometimes you need a lot of data available to a lot of functions, and it simply isn't acceptable to have copies of all of this data on the stack. A pointer gives you an easy way to store the memory address of this data so you can easily find it, and when you want another function to have access to it you just need to push 4 or 8 bytes onto the stack.

The only thing that C introduces is allowing you to determine what type of data is on the "other end" of your pointer. You don't have to do this, you can have a void * that points to an indeterminate type of data that you can later case to whatever type you need. However, since C is strongly typed, when you dereference a pointer it needs to know what type this evaluates to. C also uses pointers to deal with arrays. All an array is is a pointer to the first element, or base, of the list of values. Whenever you give an index into an array, the base address is added to sizeof(type)*index and this is the memory address for the element you've requested.

The C libraries dealing with character arrays use a special assumption of null termination to allow you do simply have a pointer to the start of a character array, with no additional information, to indicate a string. The libraries determine the end of the string when a null byte is reached. Without this convention more information would need to be known about the string, such as it's current length, maximum length, etc. I don't think it would have been awful for these things to be built-in, but one might argue that this is beyond language specification and really the job of a library to implement.

Once you wrap your head around what a pointer is for (which you may have already), then it's just a matter of syntax. The operators that come to mind immediately that deal with pointers in C are:
& - Unary. Get the address/pointer to the operand
* - Unary. Get the value pointed to by the operand
[] - Binary. The first operand is a pointer, the second an index. Take the value of the first operand, add the second times the size of the type of the first operand, and get the value at this memory address.
-> - Binary. This was discussed in my previous post. The left operand is a pointer to a struct, the right operand is the name of a field of this struct. Take the memory address pointed to by the left operand, add the offset of the field specified by the second operand in the struct, and return the value at this memory address (with the type determined by the struct definition).

That's pretty much it. I think a key to understanding all of this is to learn a bit about computer architecture, so you have some idea about memory and how data is shuffled around between it and registers, etc. It's not strictly necessary, but I think it helps a lot.

Really, it all boils down to the idea that a pointer is a variable that holds a memory address. The address itself is the value of a pointer. The value at the memory address the pointer contains isn't the pointer's value, as this memory can be changed without the value of the pointer being modified.

-Lee
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.