![]() |
Introduction to Pointers |
After executing the program, you could get:
|
|
|||||||||||
|
Definition |
|
|
Pointers are not particularly useful when declared and used inside of one function. They show their capabiliities when different functions (and/or objects) exchange data stored in those pointers. As you can see from the execution of the program above, the address of a variable is very difficult to read and interpret. Fortunately, we don't need to know that address and we don't need to know what it means or where the variable is located. C++ provides an alternative to this problem. DataType * PointerName; The identifier should be one of those we have learned already. This means it could be an int, a char, a double, etc. The identifier should be the same type of identifier the pointer variable will point to. Therefore, if you are declaring a pointer that will point to an integer variable, the pointer identifier should be an integer. DataType* PointerName; DataType * PointerName; DataType *pointerName; By default, it does not matter how you append the *, the compiler will know that the thing that follows is a variable. Be careful when declaring various pointers. If you declare a few of them on the same line, like this: DataType* pointer1, pointer2; Only the first variable is a pointer, the second is a regular variable. If you want to declare different variables, you use: DataType* pointer1, *pointer2; Or DataType* pointer1; DataType* pointer2; Since the name of the pointer is indeed the name of a variable, you will follow the naming rules that govern every C++ variable. |
#include <iostream>
using namespace std;
int main()
{
int value;
int *pointer;
cout << "Value lives at " << &value << "\n";
cout << "Pointer lives at " << &pointer;
cout << "\n\n";
return 0;
}
|
After executing the program, you might get:
Value lives at: 0x0065FDF4 Pointer lives at: 0x0065FDF0 |
|
Initializing a Pointer |
|
|
The reason you are using a pointer is to find an alternative to knowing the address
of a variable. Therefore, from now on, we are not interested in a variable's real address. Instead, we will use a pointer to point to that variable. int* Pointer;
initialize it by following the assignment operator with & operator and the name of the variable, like this |
#include <iostream>
using namespace std;
int main()
{
int value = 12;
int *pointer = &value;
cout << "Value lives at: " << value << "\n";
cout << "Pointer lives at: " << *pointer;
cout << "\n\n";
return 0;
}
|
The program would produce:
Value lives at: 12 Pointer lives at: 12 |
This program could also have the pointer initialized as:
#include <iostream>
using namespace std;
int main()
{
int Value = 12;
int *pointer;
cout << "Value lives at: " << value << "\n";
Pointer = &value;
cout << "Pointer lives at: " << *pointer;
cout << "\n\n";
return 0;
}
|
|
And it would produce the same result. As another of the program, you can first declare both variables, then initialize them later on, when needed: |
#include <iostream>
using namespace std;
int main()
{
int value;
int *pointer;
pointer = &value;
Value = 26;
cout << "Value = " << value << "\n";
cout << "*Pointer = " << *pointer << "\n";
cout << "\n";
return 0;
}
|
|
Once you have declare a variable and assign it to a pointer, during the course of your program, the value of a variable is likely to change, you can therefore assign it a different value: |
#include <iostream>
using namespace std;
int main()
{
int value;
int *pointer;
Pointer = &value;
Value = 26;
cout << "Value = " << value << "\n";
cout << "*pointer = " << *pointer << "\n";
Value = 35;
cout << "Value = " << value << "\n";
cout << "*pointer = " << *pointer << "\n";
cout << "\n";
return 0;
}
|
|
As you know now, both *pointer and Value have the same value. This allows you to change the value of the pointer directly and affect the main variable meanwhile. Therefore, you can safely change the value of the pointer and it will be assigned accordingly. To see an example, make the following change to the file: |
#include <iostream>
using namespace std;
int main()
{
int value;
int *pointer;
Pointer = &value;
Value = 26;
cout << "Value = " << value << "\n";
cout << "*pointer = " << *pointer << "\n";
Value = 35;
cout << "Value = " << value << "\n";
cout << "*pointer = " << *pointer << "\n";
*pointer = 144;
cout << "Value = " << value << "\n";
cout << "*pointer = " << *pointer << "\n";
cout << "\n";
return 0;
}
|
This would produce:
Value = 26 *pointer = 26 Value = 35 *pointer = 35 Value = 144 *pointer = 144 |
|
Operations on Pointers |
|
|
Consider that, added just a few rules, a pointer is a variable like any other: it can get its value from the user (indirectly), you can apply any of the algebraic operations we have learned, it can be incremented, it can be applied on a function, etc. A variable is a value that is supposed to change some time to time. Since a pointer is a variable whose value points to another variable, the value of a pointer is affected by the variable it points to. You can use this indirection to change the value of a pointer when changing its main variable. To get a value from the user, we have already learned that you can use the cin operator. When using a pointer to get a value from the user, don't forget the * operator, otherwise, the compiler would get confused. We have already learned how to request and display the value of a regular variable from the user: |
#include <iostream>
using namespace std;
int main()
{
int students;
cout << "Number of students: ";
cin >> students;
cout << "\nNumber of students: " << students;
cout << "\n\n";
return 0;
}
|
Once you have gotten a value and store it in a variable, it is available:
#include <iostream>
using namespace std;
int main()
{
int students;
int *ptrStudents;
ptrStudents = &students;
cout << "Number of students: ";
cin >> students;
cout << "\nNumber of students: " << students
<< "\nThat is: " << *ptrStudents << " students.";
cout << "\n\n";
return 0;
}
|
This could produce:
Number of students: 24 Number of students: 24 That is: 24 students |
|
In the same way, you can request a value from the user and store it in the pointer. To see an example, make the following change to the file: |
#include <iostream>
using namespace std;
int main()
{
int students;
int *ptrStudents;
ptrStudents = &students;
cout << "Number of students: ";
cin >> *ptrStudents;
cout << "\nNumber of students: " << students
<< "\nThat is: " << *ptrStudents << " students.";
cout << "\n\n";
return 0;
}
|
|
Of course, you can use various pointers on the same program. Apply an example by making the following changes: |
#include <iostream>
using namespace std;
int main()
{
int boys;
int girls;
int *ptrBoys;
int *ptrGirls;
ptrBoys = &boys;
ptrGirls = &girls;
cout << "Number of male students: ";
cin >> *ptrboys;
cout << "Number of female students: ";
cin >> *ptrGirls;
cout << "\nNumber of students:";
cout << "\nBoys:" << "\t" << Boys
<< "\nThat is: " << *ptrBoys << " students.";
cout << "\nGirls:" << "\t" << Girls
<< "\nThat is: " << *ptrGirls << " students.";
cout << "\n\n";
return 0;
}
|
|
We have learned how to perform algebraic calculations and expressions in C++. When performing these operations on pointers, remember to use the * for each pointer involved. The calculations should be as smooth: |
#include <iostream>
using namespace std;
int main()
{
int boys;
int girls;
int total;
int *ptrBoys;
int *ptrGirls;
int *ptrTotal;
ptrBoys = &boys;
ptrGirls = &girls;
ptrTotal = &total;
cout << "Number of male students: ";
cin >> *ptrBoys;
cout << "Number of female students: ";
cin >> *ptrGirls;
cout << "\nNumber of students:";
cout << "\nBoys:" << "\t" << Boys
<< "\nThat is: " << *ptrBoys << " students.";
cout << "\nGirls:" << "\t" << Girls
<< "\nThat is: " << *ptrGirls << " students.";
Total = Boys + Girls;
*ptrTotal = *ptrBoys + *ptrGirls;
cout << "\n\nTotal number of students: " << total;
cout << "\nThere are " << *ptrTotal << " students";
cout << "\n\n";
return 0;
}
|
Number of male students: 26 Number of female students: 24 Boys: 26 That is: 26 students Girls: 24 That is: 24 students Total number of students: 50 There are 50 students |
|
Passing Pointers to Functions |
|
|
We know that a function uses arguments in order to carry its assignment. The arguments are usually provided to the function. When necessary, a function also declares its own variable to get the desired return value. Like other variables, pointers can be provided to a function, with just a few rules. When declaring a function that takes a pointer as an argument, make sure you use the asterisk for the argument or for each argument. When calling the function, use the references to the variables. The function will perform its assignment on the referenced variable(s). After the function has performed its assignment, the changed value(s) of the argument(s) will be preserved and given to the calling function. Here is a starting file from what we have learned so far: |
#include <iostream>
using namespace std;
int main()
{
int shirts = 12;
int pants = 5;
cout << "Shirts = " << shirts << endl;
cout << "Pants = " << pants << endl;
cout << endl;
return 0;
}
|
This would produce:
Shirts = 12 Pants = 5 |
To pass arguments to a function, you can make the following changes:
#include <iostream>
using namespace std;
int main()
{
int shirts = 3;
int pants = 5;
void Deposit(int s, int p);
cout << "When starting, within main():\n";
cout << "\tShirts = " << shirts << endl;
cout << "\tPants = " << pants << endl;
Deposit(Shirts, Pants);
cout << "\n\nAfter calling Deposit(), within main():\n";
cout << "\tShirts = " << shirts << endl;
cout << "\tPants = " << pants << endl;
cout << endl;
return 0;
}
void Deposit(int s, int p)
{
s = 8;
p = 12;
cout << "Within Deposit()"
<< "\n\tShirts = " << s
<< "\n\tPants = " << p;
}
|
After executing, the program would produce:
When starting, within main():
Shirts = 3
Pants = 5
Within Deposit()
Shirts = 8
Pants = 12
After calling Deposit(), Within main():
Shirts = 3
Pants = 5 |
|
To pass pointer arguments, use the asterisks when declaring the function, and use the ampersand & when calling the function. Here is an example: |
#include <iostream>
using namespace std;
int main()
{
int shirts = 12;
int pants = 5;
void Deposit(int s, int p);
void Pickup(int *sht, int *pt);
cout << "When starting, within main():\n";
cout << "\tShirts = " << shirts << endl;
cout << "\tPants = " << pants << endl;
Deposit(shirts, pants);
cout << "\n\nAfter calling Deposit(), within main():\n";
cout << "\tShirts = " << shirts << endl;
cout << "\tPants = " << pants << endl;
Pickup(&shirts, &pants);
cout << "\n\nAfter calling Pickup(), within main():\n";
cout << "\tShirts = " << shirts << endl;
cout << "\tPants = " << pants << endl;
cout << endl;
return 0;
}
void Deposit(int s, int p)
{
s = 8; p = 5;
cout << "\nWithin Deposit()"
<< "\n\tShirts = " << s
<< "\n\tPants = " << p;
}
void Pickup(int *sht, int *pt)
{
*sht = 26;
*pt = 17;
cout << "\nWithin Pickup()"
<< "\n\tShirts = " << *sht
<< "\n\tPants = " << *pt;
}
|
The result of executing the program is:
When starting, within main():
Shirts = 12
Pants = 5
Within Deposit()
Shirts = 8
Pants = 5
After calling Deposit(), within main():
Shirts = 12
Pants = 5
Within Pickup()
Shirts = 26
Pants = 17
After calling Pickup(), within main():
Shirts = 26
Pants = 17 |
|
Pointers and Memory Management |
|
|
By definition, the variables in your program are meant to "vary", that is, their values
change regularly. When you declare a variable, such as PointerName = new DataType; The keyword new is required. The data type can be any of those we are already familiar with, but it must be appropriate to the variable it is pointing to. This means that, if it is pointing to an integer variable, the data type must be an integer. For example, our corresponding dynamic allocation would be: ptrShirts = new int; After dynamically allocating memory, you can assign a new value to the pointer for any purpose. Once the memory is not anymore in use, you should reclaim it. This is done with the delete keyword, like this: delete ptrShirts; Here is a starting point for this section: |
#include <iostream>
using namespace std;
int main()
{
int studentAge = 12;
cout << "Student age = " << studentAge << endl;
cout << endl;
return 0;
}
|
Now, let's add a pointer and try to access it without initializing it:
#include <iostream>
using namespace std;
int main()
{
int studentAge = 12;
int* age;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
cout << endl;
return 0;
}
|
|
You will get a value that is not insignificant. Depending on the compiler, you might even get a nasty dialog box and a warning. This is because you were trying to access a pointer that has not been initialized. You can initialize the pointer like this: |
#include <iostream>
using namespace std;
int main()
{
int studentAge = 12;
int* age;
Age = &studentAge;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
cout << endl;
return 0;
}
|
|
To illustrate that an un-initialized variable has an address (although empty), you can change the file as follows: |
#include <iostream>
using namespace std;
int main()
{
int studentAge;
int* ptrAge;
ptrAge = &studentAge;
cout << "Student age = " << studentAge << endl;
cout << "*ptrAge = " << *ptrAge << endl;
cout << endl;
return 0;
}
|
|
When you initialize a variable, its value gets stored in the memory space that was statically allocated by the compiler. In the same way, since its corresponding pointer points to its address, you can initialize the pointer and still access the value assigned to the variable it is pointing to. To see an example of a pointer, and not the variable itself being initialized, make the following changes to the file: |
#include <iostream>
using namespace std;
int main()
{
int studentAge;
int *age;
age = &studentAge;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
*Age = 15;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
cout << "\n";
return 0;
}
|
This results in:
Student age = -858993460 *Age = -858993460 Student age = 15 *Age = 15 |
|
To dynamically allocate memory, you assign the pointer with the new keyword followed by the appropriate identifier: |
#include <iostream>
using namespace std;
int main()
{
int studentAge;
int *age;
age = &studentAge;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
*age = 15;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
age = new int;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
cout << "\n";
return 0;
}
|
|
As you can see, since the value of the pointer has been dynamically assigned, its address is now empty. If you want to access its content, you have to reassign it another value; this is one of the mistakes that happen regularly in a program. When this happens, the program will compile fine, without any error or warning, but the result… Therefore, you should always know the value of a pointer. In our example, you can reassign a value to the empty pointer: |
age = new int; *Age = 17; cout << "Student age = " << studentAge << endl; cout << "*Age = " << *age << endl; cout << "\n"; }
After using a pointer, don't forget to clean your memory. You do this using the delete operator:
#include <iostream.h>
int main()
{
int studentAge;
int *age;
age = &studentAge;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
*age = 15;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
Age = new int;
*age = 17;
cout << "Student age = " << studentAge << endl;
cout << "*Age = " << *age << endl;
delete age;
cout << "\n";
return 0;
}
|
|
|
||
| Previous | Copyright © 2000-2005 FunctionX, Inc. | Next |
|
|
||