Objective-C Programming_ The Big Nerd Ranch Guide - Aaron Hillegass [22]
int main(int argc, const char * argv[])
{
int i = 17;
int *addressOfI = &i;
printf("i stores its value at %p\n", addressOfI);
printf("this function starts at %p\n", main);
return 0;
}
Build and run the program. You should see no change in its behavior.
We’re using integers right now to be simple. But if you’re wondering what the point of pointers is, I hear you. It would be just as easy to pass the integer value assigned to this variable as it is to pass its address. Soon, however, your data will be much larger and much more complex than single integers. That’s why we pass addresses. It’s not always possible to pass a copy of data you want to work with, but you can always pass the address of where that data begins. And it’s easy to access data once you have its address.
Getting the data at an address
If you have an address, you can get the data stored there using the * operator. Have the log display the value of the integer stored at addressofI.
int main(int argc, const char * argv[])
{
int i = 17;
int *addressOfI = &i;
printf("i stores its value at %p\n", addressOfI);
printf("this function starts at %p\n", main);
printf("the int stored at addressOfI is %d\n", *addressOfI);
return 0;
}
Notice that the asterisk is used two different ways The first is in the declaration where you declare the variable addressOfI to be an int *. That is, it is a pointer to a place where an int can be stored.
The second is where you read the int value that is stored at the address stored in addressOfI. (Pointers are also called references. Thus, using the pointer to read data at the address is sometimes called dereferencing the pointer.)
You can also use the * operator on the left-hand side of an assignment to store data at a particular address:
int main(int argc, const char * argv[])
{
int i = 17;
int *addressOfI = &i;
printf("i stores its value at %p\n", addressOfI);
*addressOfI = 89;
printf("Now i is %d\n", i);
return 0;
}
Build and run your program.
Don’t worry if you don’t have pointers squared away in your mind just yet. We’ll spend a lot of time working with pointers in this book, so you’ll get plenty of practice.
Now let’s make a common programming mistake. Remove the * from the fourth line of main() so that it reads
addressOfI = 89;
Notice Xcode pops up a warning that says Incompatible integer to pointer conversion assigning to 'int *' to 'int'. Fix the problem.
How many bytes?
Given that everything lives in memory and that you now know how to find the address where data starts, the next question is “How many bytes does this data type consume?”
Using sizeof() you can find the size of a data type. For example,
int main(int argc, const char * argv[])
{
int i = 17;
int *addressOfI = &i;
printf("i stores its value at %p\n", addressOfI);
*addressOfI = 89;
printf("Now i is %d\n", i);
printf("An int is %zu bytes\n", sizeof(int));
printf("A pointer is %zu bytes\n", sizeof(int *));
return 0;
}
We see yet another new token in the calls to printf(): %zu. The sizeof() function returns a value of type size_t, for which %zu is the correct placeholder token. This one’s not very common in the wild.
Build and run the program. If your pointer is 4 bytes long, your program is running in 32-bit mode. If your pointer is 8 bytes long, your program is running in 64-bit mode.
sizeof() will also take a variable as an argument, so you could have written the previous program like this:
int main(int argc, const char * argv[])
{
int i = 17;
int *addressOfI = &i;
printf("i stores its value at %p\n", addressOfI);
*addressOfI = 89;
printf("Now i is %d\n", i);
printf("An int is %zu bytes\n", sizeof(i));
printf("A pointer is %zu bytes\n", sizeof(addressOfI));
return 0;
}
NULL
Sometimes you need a pointer to nothing. That is, you have a variable that can hold an address, and you want to store something in it that makes it explicit that the variable is not set to anything. We use NULL for this:
float