Home | Gaming | Programming | Play Online | Contact | Keyword Query
Games++ Games & Game Programming

GAMES++
Games++ Home
Games++ Gaming
Games++ Programming
Beta Testing Games
Free Online Games
Hints & Cheats

BROWSER UTILITIES
E-mail This Page
Add to Favorites

SITE SEARCH

Web Games++

AFFILIATES
Cheat Codes
Trickster Wiki
Game Ratings
Gameboy Cheats
PlayStation Cheats
BlackBerry Games
Photoshop Tutorials
Illustrator Tutorials
ImageReady Tutorials

ADVERTISEMENT

ADVERTISEMENT

Ch 6: Pointers - C++ by Metrowerks

Introduction to C++ by Metrowerks

Introduction to Pointers

Pointers contribute to making C++ the powerful programming language it is. I've talked about them in previous lessons, and pointers will be discussed in many of the subsequent lessons, as their use will be expanded over this course. For now, we will introduce the basic use of pointers and use this lesson as a foundation to build upon.

A pointer is unlike any of the variables we have discussed so far. Instead of storing an assigned value, a pointer stores a memory address, which, in turn, points to another variable. Following are examples of declarations of pointers:

int *x;
float *p;
char *fn;

Note that none of the above variables (*x, *p, or *fn) hold values. Instead, they hold memory addresses. We will discuss the importance of the base type of a pointer in a few minutes.

Pointer Operators

There are two pointer operators: * and &. The first operator returns the value of the variable located at a specific memory address; the second returns the memory address of that variable. Using these two operators, a programmer can indirectly access a variable. The following short program illustrates the basic uses of these two operators:

#include 
using namespace std;
int main()
{
    int x;
    int *y;
    int z;
    x = 623;
    y = &x;
    z = *y;
    cout << "z now equals: " << z << '\n';
    return 0;
}

In the above example, the value of x is set to 623. Then y is set to hold the address of x using the & operator. Z is then set to the value stored at the address held by y with the * operator. Therefore, the output for this program will look like this:

z now equals: 623

Pointer base types

Let's now modify the above sample program. Suppose that the variable declarations looked like this:

double x;
int *y;
int z;

Although this program should function similarly to the one above, the memory allocation for z is only large enough to hold an int. Now, since we have assigned a value of double to a memory space only capable of holding an int, an error will occur. If the value of xwere set to 456.789, we would get an invalid result if this program were run.

Using a pointer to assign values

If we have an integer pointer, *y, we can assign a value to the memory address that *y points to:

*y = 50;

We can also decrement the value stored at the memory location pointed to by *y:

(*y)--;

Look at the following program and determine its output:

#include 
using namespace std;
int main()
{
    int *y, x;
    y = &x;
    *y = 50;
    cout << x << '\n';
    (*y)--;
    cout << x << '\n';
    return 0;
}

The output would be:

50
49

The pointer y is set to the memory location of variable x . This means that when *y is accessed, it will be writing to x's memory space. When y is dereferenced, the value of x is accessed, so the assignment and decrement operations happen and can be accessed through variable x.

Pointer Expressions

There are four arithmetic operators that can be used on pointers: ++, --, +, and -. The use of these operators on pointers, however, is different than their use on other variables. If you increment an integer pointer, its value does not increase by a value of 1. The increment will instead be of a value equal to the memory location of the next integer in the computer's memory. Similarly, decrementing a pointer changes its value to that of the previous integer.

If you have a float pointer and add a value of 3 using the + operator, you are assigning to it the memory location of the third float variable past its current location. You can use the minus operator in the same manner. This is often referred to as pointer math and is very useful to randomly move the pointer to and from elements of an array.

It is important that the programmer be aware that the pointer moves and that it does move into addresses prior to or past the end of an array.

The - operator may also be used in a special way: If you subtract two pointers of the same base type, the remainder will be the number of elements separating the two pointers. Pointer math should only be used on arrays, as accessing arbitrary memory locations can cause unexpected results.

Comparing pointers

The relational operators (==, <, >) may be used to compare pointers. However, the comparison will be meaningless unless the pointers point to related variables. In the last section of this lesson, we will discuss the ways relational operators are used to compare pointers to variables within an array.

Pointers and Arrays

Pointers and arrays are very closely related. They are often used in conjunction with each other. Let's take a look at their relationship:

char strarray[50];
char *y;
y = strarray;

What happened here? First, an array strarray was declared with a size of 50. Then, a pointer, *y, was declared. In the third line, the address of the first element of strarray is assigned to y. We now have two different methods of accessing the tenth element in the array strarray:

y = &strarray[9]

or

*(y+9)

In many cases, accessing array elements using pointer math is faster than array indexing.

There is a third way of accessing elements in an array: a pointer itself may be indexed. The following also accesses the tenth element of array strarray:

y[9]

String Constants

When a string is generated, it is stored in the program's string table. Therefore, it is possible to assign a pointer to the first element in the string table:

#include 
using namespace std;
int main()
{
    char *y;
    y = "Playing with pointers!\n";
    cout << y;
    return 0;
}

The above program outputs

Playing with pointers!

Arrays and Pointer Comparisons

The following program illustrates one use for pointer comparisons within arrays. The two pointers, beginning and ending, are used to determine if the array is full. When the array is full, the program outputs the elements within the array:

#include 
using namespace std;
int main()
{
    int numarray[15];
    int *beginning, *ending;
    beginning = numarray; //points beginning to the first element
    ending = &numarray[14]; // points ending to the last element
    while (beginning != ending) {
        cout << "Enter a number: ";
        cin >> *beginning;
        beginning++;
    }
    beginning = numarray; // resets beginning to the first element
    while (beginning != ending) {
        cout << *beginning << ' ';
        beginning++;
    }
    return 0;
}

Like other variables, several pointers can be grouped into an array. The following declares an array of 10 integer pointer elements:

int *a[10];

We can then assign the address of an integer variable, z,to the fourth element of the array:

int z;
a[3] = &z;

Then, to access the value of z, you can use:

*a[3]

Common Pointer Problems

Pointers are not simple elements within a program. Pointers can cause bugs within a program that are hard to detect. Let's now look at some common problems with pointers and how they can be avoided.

Uninitialized Pointers

Take a look at the following program. Do not compile it; it is wrong! The pointer fails to point where we want it to point. An uninitialized pointer points to an unspecified place in the computer's memory:

int main()
{
    int a, *b;
    a = 5;
    *b = a;
    return 0;
}

In this program, b points to an unknown address. We don't know where the value of a has been written because we did not access &a. If this were a large program, it would be likely that b points to a section of code or data, which would cause the program to freeze.

Important: Always make sure a pointer is pointing to a valid memory address before using it.

Invalid Pointer Comparisons

Remember our sample program using pointers to point to the beginning and end of an array? We were able to successfully use pointer comparisons within that program because the pointers were used within a single array. Invalid pointer comparisons occur when each of the two pointers points to addresses found within different arrays. Trying to use an invalid pointer comparison can lead to the overload of an array or other problems.

Forgetting to Reset a Pointer

Let's look at the program we just mentioned above. This time, we will remove the line resetting beginning to the first element in the array:

#include 
using namespace std;
int main()
{
    int numarray[15];
    int *beginning, *ending;
    beginning = numarray; //points beginning to the first element
    ending = &numarray[14]; // points ending to the last element
    while (beginning != ending) {
        cout << "Enter a number: ";
        cin >> *beginning;
        beginning++;
    }
    while (beginning != ending) {
        cout << *beginning << ' ';
        beginning++;
    }
    return 0;
}

What will this program output now? Nothing! The key to avoiding problems with pointers is to know, at all times, where your pointers are pointing!

Calling Functions With Pointers

There are two methods of calling a function using a pointer as the argument. Within both of these methods, it is necessary to declare the parameter as a specific pointer type. Take a look at the following programs to understand the different methods of using pointers as arguments. Both set the value of a to 623 and output that value.

//Sample program 1: passing an actual pointer variable.
#include 
using namespace std;
void f1(int *p);
int main()
{
    int a;
    int *b;
    b = &a;
    f1(b);
    cout << a;
    return 0;
}
void f1(int *p)
{
    *p = 623;
}

The next program doesn't pass an actual pointer, only the address of the variable a:

//Sample program 2: passing the address of a variable.
#include 
using namespace std;
void f1(int *p);
int main()
{
    int a;
f1(&a);
    cout << a;
    return 0;
}
void f1(int *p)
{
    *p = 623;
}

Calling a function with a pointer argument allows the function to modify the value of the variable. This can be good, but it can also be dangerous. Be careful that you don't modify variables by accident!

Reference Parameters

C++ allows you to pass arguments using the call-by-reference method. This method does not require the use of pointers. Instead, we use a reference parameter. When you use a reference parameter, the address of an argument, not the value, is automatically passed to the function. Let's revisit our cubing program from Lesson 4. This time, we'll add a reference parameter:

#include
ý
using namespace std;
void cubenum(int &x);
int main()
{
    int y;
    cout << "Enter an integer to be cubed: ";
    cin >> y;
cubenum(y);
cout << "The cube is " << y << '.';
return 0;
}
void cubenum(int &x)
{
    x = (x)*(x)*(x);
}

As you can see, this method is less complicated than passing an argument with a pointer. You don't have to remember to pass the address of the argument; this is done for you automatically.

Returning References

Instead of returning an actual value, a reference to a value can be returned. Important uses for this will be presented later in this course. We will study the "how-to" in this section and the uses in subsequent lessons.

The following is a simple example of returning a reference. You will see that one advantage of this method is its ability to use a function on the left side of an assignment statement:

#include 
using namespace std;
int &f1();
int num1 = 10;
int main()
{
    int num2;
    cout << f1() << '\n';
    num2 = f1();
    cout << num2 << '\n';
f1() = 5;
cout << f1() << '\n';
return 0;
}
int &f1()
{
    return num1;
}

The output for this program will look like this:

10
10
5

Bounded Arrays

One advantage to returning a reference, rather than a value, is that you can create bounded arrays without fear of overloading an array. Study the following program. It creates a safe array of five integers that cannot become overloaded:

#include 
using namespace std;
int &enter(int j);
int get(int j);
int a5[5];
int problem = -1;
int main()
{
    enter(0) = 50;
    enter(1) = 55;
    enter(2) = 60;
    enter(3) = 65;
    enter(4) = 70;
cout << get(0) << '\n';
cout << get(1) << '\n';
cout << get(2) << '\n';
cout << get(3) << '\n';
cout << get(4) << '\n';
enter(10) = 75;
    cout << get(6);
return 0;
}
int &enter(int j)
{
    if (j>=0 && j<5)
        return a5[j];
    else {
        cout << "Out of bounds!\n";
        return problem;
    }
}
int get(int j)
{
    if(j>=0 && j<5)         return a5[j];     else {         cout ><< "Out of bounds!\n";
        return problem;
    }
}

The output for this program would look like this:

50
55
60
65
70
Out of bounds!
Out of bounds!
75

Notice that the last cout << statement shows the number 75. This is because on the enter(75) function, problem is the return and therefore the values of 75 is assigned to it instead of -1. Therefore when the cout << get(6) is called it does not show the array value and instead transfers to the else clause, which returns problem -- which was previously set to 75.

Next Lesson

Copyright © 1998-2007, Games++ All rights reserved. | Privacy Policy