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

Kelmon

macrumors 6502a
Original poster
Mar 28, 2005
733
0
United Kingdom
OK, I'm looking to try and give something back to the Mac community by helping out on some of the open-source projects and wish to learn Cocoa with Objective-C. I've been working my way through the tutorials posted at cocoadevcentral.com but I've come across some syntax that I have no idea what its significance and no where have I seen it explained. For your information I'm coming to Cocoa and Objective-C from a Java background and my first experience of C has been the tutorials that I've worked through.

Anyway, the issue that I have is that I keep seeing the asterisk symbol appearing in method and variable declarations, as illustrated in the following example:

Code:
#import <Cocoa/Cocoa.h>
#import "Converter.h"
 
@interface ConverterController : NSObject
{
    IBOutlet NSTextField *amountField;
    IBOutlet Converter *converter;
    IBOutlet NSTextField *dollarField;
    IBOutlet NSTextField *rateField;
}
- (IBAction)convert:(id)sender;
@end

What the heck does that asterisk mean for the instance variables? Equally, the same sort of thing shows up in method invocations, such as the following:

Code:
NSArray * foo = SomeFunctionReturningAnNSArray();
NSMutableArray * bar = [foo mutableCopy];
[foo release];

Much of everything else that I have read about the Objective-C language and the tutorials that I have performed make sense but this eludes me at the moment so can someone put me out of my misery? Thanks.
 
It defines the variable as a pointer. "Pointers are designed to hold memory addresses. With a pointer you can indirectly manipulate data stored in other variable."

Most C / C++ books devote 1 or 2 whole chapters just on pointers. I'm still trying to understand them. :D
 
It's a pointer.

If you have a Java background then you already are familiar with object references (since practically EVERYTHING in Java is one). Java just doesn't let you mess with them as easily as C/C++ do. So:

NSArray * foo = SomeFunctionReturningAnNSArray();

Means the function is returning a reference to an object of type NSArray. foo is a variable which points to NSArray objects. foo is not an NSArray, it points to one.

Like in Java, if you were to declare

NSArray foo;

You would not say that foo is an NSArray. Yet. It's just ready to point to one (and would currently point to NULL), until you do this:

foo = new NSArray(...)

NOW foo is pointing to an NSArray object.

You can also have pointers to basic types:

int i = 5; // i is a basic integer type
int* x; // x is a POINTER to an integer
x = &i; // x now points to the same memory space as i does

Now we can "dereference" the pointer x and use it to change the value of i.

*x = 7; // sets the variable where the pointer is pointing, to 7

or

(*x)++; // increment the variable x points to

It would be the equivalent in Java of something like:

Integer i = new Integer(5);
Integer x;
x = i;

(Sort of, anyway.)

Here's a good thorough tutorial on pointers: http://home.netcom.com/~tjensen/ptr/pointers.htm

They are single-handedly the most powerful, yet potentially most annoying, feature of C/C++.
 
  • Like
Reactions: ulna
Think of pointers as phone numbers. By themselves, just numbers (references to memory locations for pointers, digits for phone numbers). But... reference the pointer (call the number) and you get to the object (person) you want.

However, you can't affect the object (person) by changing the value of the pointer (phone number) itself - altering the pointer value itself is like dialing a different phone number. No longer connects you to what it used to.
 
  • Like
Reactions: Knapp
Hey guys, this is great information. At least I know what I need to look at and have a reasonable idea of what this gig is all about. Thanks very much!
 
In general, one reason pointers are used is because they are usually a lot smaller than the thing they point to. For example, a pointer is 4 bytes on an Apple system but could point to an array that has thousands of bytes. If you wanted to pass that array to a function what would be more efficient - passing the four bytes (saying this is where the array's at) or the whole array?

Luckily with objective-C and cocoa you don't really have to worry about pointers that much apart from remembering nearly everything is one. In other C dialects pointers are a lot more involved.
 
jsw said:
Think of pointers as phone numbers. By themselves, just numbers (references to memory locations for pointers, digits for phone numbers). But... reference the pointer (call the number) and you get to the object (person) you want.

However, you can't affect the object (person) by changing the value of the pointer (phone number) itself - altering the pointer value itself is like dialing a different phone number. No longer connects you to what it used to.

I like this analogy. :)
 
jsw said:
Think of pointers as phone numbers.
nice one.

when teaching pointers in the past, i've used this analogy:

1. the object is the house
2. the pointer to the house is its address
3. the pointer to the address are instructions on where to find the piece of paper the address is written on
 
  • Like
Reactions: ulna
also, there's a very good reason for using pointers when passing objects / variables / arrays / etc to functions.

in C and C++, unless specificed, things passed to functions are not passed by reference. rather, they are copied and the called function operates on its own copy which is destroyed when the function ends. i've seen this confuse many a programmer.

consider:

Code:
void foo (int i)
{
    i++;
}

int main (int argc, char** argv)
{
    int i=0;

    foo(i);

    cout << i << endl;
}
the output will be zero.

correct:
Code:
void foo (int* i)
{
    (*i)++;
}

int main (int argc, char** argv)
{
    int i=0;

    foo(&i);

    cout << i << endl;
}
there are actually a couple ways of doing it the "correct" way in C++, fwiw.
 
Pointers are essential to intermediate-to-advanced levels of programming. While they can really be a pain in the ass (especially in C++) they can also save you a lot of time, and allow you to perform actions that couldn't perform otherwise.
 
zimv20 said:
Code:
void foo (int* i)
{
    (*i)++;
}

int main (int argc, char** argv)
{
    int i=0;

    foo(&i);

    cout << i << endl;
}

OK, next stupid questions: what does the double asterisk (**) in the main method arguments signify, and why is an ampersand (&) used in the call to the foo method rather than an asterisk?

Thanks for the clarification that C/C++ is not pass by reference since I've got very used to that in Java and it would undoubtedly have caught me out.
 
Kelmon said:
what does the double asterisk (**) in the main method arguments signify
char** argv is a pointer to an array. an array of strings, actually, where a string is an array of characters.

in C/C++, the main() always has those two arguments: argc is the number of token strings on the command line, and argv (where v is 'vector') contains all the values of the command line, including the name of the executable, any options, and the arguments.

for example, for this execution command:

% a.out file1 file2

argc would be 3, and argv would be:
argv[0] = "a.out"
argv[1] = "file1"
argv[2] = "file2"

further:
argv[0][0] = 'a'
argv[2][4] = '2'

in general, ** means a pointer to a pointer. basically, anytime you make a pointer to something (including another pointer), it means "where to find".

why is an ampersand (&) used in the call to the foo method rather than an asterisk?
& means "take the address of". it's how you make a pointer to something. the * means to dereference the pointer, if it's in code. if it's part of a declaration, it's simply indicating the variable is a pointer.

consider this C++ fragment:
Code:
int i = 5;
int *k = &i;
int **j = &k;

cout << i << endl;
cout << k << endl;
cout << j << endl;
the output would look something like:
Code:
5
0x09383fa4
0x09383fac

but changing it to:
Code:
cout << i << endl;
cout << *k << endl;
cout << **j << endl;
would get you all 5's.
 
Kelmon said:
why is an ampersand (&) used in the call to the foo method rather than an asterisk?
it may help if i answer this more directly by commenting my code...

Code:
//
// foo (int* i) declares a function called foo, returning a void, that takes
// as a single argument a pointer to an integer. any changes made to the
// value of the integer at that address will survive once foo finishes
// executing (what we call "popping off the stack").
//
// note that because the * is part of a function definition, it's not actually
// dereferencing i at this point.
//
void foo (int* i)
{
    // this statement increments, by one, the value found at the memory
    // location passed in. this statement is equivalent to: *i = *i + 1;
    //
    // note that because this is not a statement of declaration, but rather
    // a statement to be executed, * here means to dereference the pointer,
    // which in this case gives us an integer.

    (*i)++;
}

int main (int argc, char** argv)
{
    // declare an integer in this scope.
    int i=0;

    // because we wish to change the value of i in foo(), and have that
    // change reflected in this scope, we must pass the value in by
    // using a pointer. using the & is one way of doing that, it means to take
    // the memory address of i and pass that to foo. we use this method
    // because foo() expects a pointer to an integer.
    foo(&i);

    cout << i << endl;
}

if you're not confused enough, i'll tell you the other way the C++ handles passing by reference (called "passing by reference"), which is much more like java. i'll highlight the changes:
Code:
void foo ([color=red]int&[/color] i)
{
    [color=red]i[/color]++;
}

int main (int argc, char** argv)
{
    int i=0;

    foo([color=red]i[/color]);

    cout << i << endl;
}
this was adopted in C++ simply because it cleans up the code -- a lot of people get thrown by C-style pointers. of course, the & is used again, just to confuse people, but because the context is a function declaration, and not an executed statement, we know that we're not taking the address of something, we're defining the variable as pass by reference (as opposed to pass by pointer).

because the signature of foo() changed, that meant we had to call foo() differently in main(). when passing by reference, it looks like pass by value (in fact, the only way to be certain is to look at the function definition of foo()).
 
Hey, zimv20, thanks for the explanations and examples. I think that I understand what is going on now but the implications of it are somewhat terrifying when compared to the relative simplicity of Java. I can quite easily see myself trying to work on pointers rather than the data that they point to simply because I forgot to add an asterisk or ampersand somewhere in my code. This looks like a nightmare waiting to happen...

Still, at least I can read the example code that I am working through and understand what is going on now properly, which is certainly more than before where I was slightly confused.
 
Kelmon said:
OK, next stupid questions: what does the double asterisk (**) in the main method arguments signify, and why is an ampersand (&) used in the call to the foo method rather than an asterisk?

Thanks for the clarification that C/C++ is not pass by reference since I've got very used to that in Java and it would undoubtedly have caught me out.
Already explained, just to add a clarification:

in an array with one dimension (for instance, a simple string) you must know that the declaration name for this array is just a pointer to the first element of this array.

Now, if you want to create a pointer to a 2 dimensional array of elements, you can declare it like this:
Code:
char **k;
To a 3 dimensional array, the pointer is
Code:
char ***k
and so on...

That also means that you can handle the variable declared as an array as if it's a pointer. Look at this code:
Code:
int main(){
	char k[] = "hello";
	
	cout << *(k+1);
	
	return 0;
}
This will show "e", because with the *(k+1) I told the program to show the element in the position k+1 (which k was a pointer in the first element, which means element 0) so it will show the second letter of your string.

Note that pointers that come from array declarations cannot be directed to point into other arrays or in any other position apart from the array specified in general. However, you can create individual pointers that can point anywhere in your program.

Do not be intimidated by the complexity of the pointers. They are here for a reason. Soon, as you begin to learn more and more about C++, you will see that it's a godsent gift for the intermediate and experienced programmer.
 
kelmon -- i edited post #12 because i made an error in how i described argc and argv. it's now correct.
 
WOW... Great Explanation!

Hi,

I don't post often... but I just wanted to thank everyone here for putting this discussion together...

In 15 minutes of reading you guys have given me what I haven't been able to find in 3 months of learning Objective-C from many books.
(All the books say, read up on references at X. So I go to X and find lots of theoretical discussions... but nothing practical like this...)
:D

It does leave me with two questions unanswered though...

NSArray *myArray /*Based on the conversation here... this points to an NSArray at the location *myArray. That makes PERFECT sense now... thanks!*/

VS.
NSArray * myArray /* What is this a reference too...? :confused:*/

VS.
NSArray* myArray /* Is this a Pointer to a Class? And if so, how would someone us it, if it is used at all? :confused:*/

Hope this post isn't so old that it is long forgotten... hehe
:D
 
Pointers are essential to intermediate-to-advanced levels of programming. While they can really be a pain in the ass (especially in C++) they can also save you a lot of time, and allow you to perform actions that couldn't perform otherwise.

Like using Objective C objects. :rolleyes:
 
Thanks for the clarification that C/C++ is not pass by reference since I've got very used to that in Java and it would undoubtedly have caught me out.

I know I'm responding to an ancient post here, but I feel the need to say:

Objective-C, like C and C++, does NOT pass by reference. Objective-C objects themselves are always passed around as C-style pointers, but they must be declared as such, and those pointers are copied--not passed by reference. Any object is passed exactly as it would have been in C. That is, an int would be copied unless passed as a pointer to an int; a pointer to an object will be copied unless passed as a double-pointer to an object.
 
I know this thread is old, but I noticed one other thing with the asterisk that confuses me. I apologize, I am very new to programming in general and decided to start with Objective-C. :)

what is the difference between:

(NSArray) *myArray

and

(NSArray *) myArray
 
I know this thread is old, but I noticed one other thing with the asterisk that confuses me. I apologize, I am very new to programming in general and decided to start with Objective-C. :)

what is the difference between:

(NSArray) *myArray

and

(NSArray *) myArray

Technically they are casts. The first casts the value pointed to by myArray as a NSArray, the second casts the value in myArray as a pointer to NSArray.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.