 |
Pointers and References in C++
|
Introduction
The ability to manipulate memory and memory locations directly
is part of what makes C and C++ so powerful, so dangerous,
and so difficult for beginners. C only has "pointers",
but C++ uses pointers and "references" that have
a nicer syntax and attempt to be safer. This article will
attempt to demystify these concepts in the minds of beginning
C/C++ programmers.
This article assumes the reader has a basic
understanding of C/C++ including variable
declaration, conditionals, loops, functions,
and data types. This article will speak more
specifically about C++.
Remember, pointers can twist your mind at
first and they are a difficult concept to
grasp. Often times it is hard to see where
they would be useful.
The
Basics
The "normal" way of storing information
(data) in C++ is using certain predefined
types like integers (int), floating point
values (float, double), and characters (char).
The programmer tells the compiler about the
data he wishes to store by giving its type,
its name, and possibly an initial value.
int total_balls = 2300;
float gravity = 9.8f;
char start_char = 'a';
None of this should be new or difficult.
This is easy, assuming you know the different
types, and the best part about it is that
the compiler takes care of finding a place
to store the variable and we just tell
it when we want to know what is "stored" in
the variable. But wait! The compiler knows
where the variable is stored in memory, it
has to. We can get at the address of a variable
by using the address of operator, "&" (ampersand).
std::cout << &total_balls;
std::cout << &gravity;
std::cout << &start_char;
But why would we care about knowing the
address of our variables? The compiler
takes care
of storing our data for us, right? Yes,
and we as humans have very little
use of printing
out the addresses of variables except for
debugging purposes. But we can store an
address of a variable into a special
data type called
a pointer and the compiler takes care of
storing our "pointer value" for
us. We designate pointers with a data type
(int, float...) followed by the * (asterisk)
symbol.
int*
addr_balls = &total_balls;
float* addr_grav = &gravity;
char* addr_char = &start_char;
Now we have variables that store the
addresses of the other variables
we already created!
Not very useful yet. But these concepts
are important, a pointer can point
to practically
anywhere in the computers memory, and wherever
it is pointing to we can retrieve the value
there or store a new value in that location.
Most pointers have a type associated with
them, but there is a special pointer, a red-head
in the group, called a void pointer (void*).
Well, what's at the other end of the pointer,
what is stored in the location? The programmer
has to know that and cast it into an appropriate
type.
Dereferencing
and Multiple Pointers
If we have the address of an integer how
do we get at the integer instead of the
address. We use the * (asterisk) symbol
again, which can be somewhat confusing.
// Declare an integer.
int total_balls = 205;
// Declare a pointer that "points" at
the address of total_balls.
int* addr_balls = &total_balls;
// Print the address of total_balls twice.
std::cout << &total_balls << " " << addr_balls;
// Print out the value of total_balls twice.
std::cout << total_balls << " " << *addr_balls;
In this way we can switch between the
memory address and the actual value
stored there
effortlessly. We can also have a pointer
to another pointer, which requires two
* (dereference) to obtain the object.
int a = 0;
int b = 1;
int* addr_int = &a;
int** addr_addr_int = &addr_int;
**addr_addr_int = 3; // changes variable "a" to
3
addr_int = &b;
**addr_addr_int = 3; // WOW, the same exact
line now changes variable "b"
Practical
Pointers
So far, we haven't really seen the use
of pointers. Why do we need to know the
address
of a variable? There are many reasons including
storing contiguous data (arrays), storing
a "string" of characters (string),
taking over memory management from the compiler,
manipulating the same data from different
functions, and not duplicating large chunks
of memory when passing to a function in order
to increase performance. Don't worry if these
sound confusing now
Pointer
Arithmetic
An array is a bunch of variables stored one
after the other in memory so we can easily
access any of the variables with a number.
Instead of saying "Give me the book
by Thomas Hardy" we can say "Give
me book #3."
If
we have a pointer to the first variable
in an array, we can get or set the value
of any other variable in the array. Since
we know how big each object is we can "jump" to
the correct address with some simple multiplication
and addition. You've probably seen array[5]
to get the sixth element in an array (remember
array[0] is the first element). To calculate
that location we move over 5 elements. Then
we dereference that spot, to work with the
object there. So array[5] == *(array + 5)
is true. Notice how we dereferenced the address
after we moved over five elements.
In fact it is hard to give a short example
showing the usefulness of pointers since
they mostly crop up in larger projects. But
a character string is a good way to start.
// Something probably familiar:
char message[] = "Hello";
// But it's really sugary syntax for:
char message[] = {'H','e','l','l','o','\0'};
We have a pointer to a character and
we know that after that character
is another character,
and after that another character until
we reach the value 0. So we can print
out a
word, instead of just a character!
int index = 0;
while( *(message + index) != 0 )
{
std::cout << *(message + index);
++index;
}
// alternatively
while( message[index] )
{
std::cout << message[index];
++index;
}
// or simply
std::cout << message;
In that last example, the program doesn't
do what you might expect it to do.
It should print out a char* but instead, when you insert a char* into a output
stream, it steps over every character until it reaches the null character
(0) or ("\0").
About
this Tutorial
This tutorial is from The
Game Progamming Wiki which is published under the
GNU Free Documentation License 1.2.
InfoWorld's Java IDE Comparison Strategy Guide If you're looking for a Java IDE, you want one based on Eclipse. But which offering do you want? Download the Infoworld Java IDE Comparison Strategy Guide. In this three-part guide we'll go deep into the details, comparing Technology of the Year winner JBuilder 2007, IBM's IRAD, MyEclipse and the free open-source Eclipse platform.
We close this Java IDE Strategy Guide with a look at an advanced concept in Java development: Application Factories. This innovative development metaphor and associated collection of tools allows developers to focus more on the nature and purpose of the application, and less on the underlying platform, framework, and technologies being used. Request Your Free Strategy Guide!
|
|