#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; } |
Value = 26 *pointer = 26 Value = 35 *pointer = 35 Value = 144 *pointer = 144 |
A Pointer to a Pointer
|
|
Instead of pointing to a regular variable, a pointer
can be made to point to another pointer. To apply this, always remember
that you must specify what target a pointer is pointing to. Once again,
consider the following example:
#include <iostream>
using namespace std;
int main()
{
int value = 26;
int *pointer;
pointer = &value;
cout << " Value = " << value << "\n";
cout << "*Pointer = " << *pointer << "\n";
return 0;
}
This would produce:
Value = 26 *Pointer = 26
In this program, if necessary, you can declare a new
variable that is a pointer that itself points to another pointer. When
declaring such a variable, precede it with two *. After declaring the
pointer, before using it, you must initialize it with a reference to a
pointer, that is, a reference to a variable that was declared as a
pointer. Here is an example:
#include <iostream> using namespace std; int main() { int value = 26; int *pointer; int **pointerToPointer; pointer = &value; pointerToPointer = &pointer; cout << " Value = " << value << "\n"; cout << " *Pointer = " << *pointer << "\n"; cout << "**Pointer = " << **pointerToPointer << "\n"; return 0; }
This would produce:
Value = 26 *Pointer = 26 **Pointer = 26
Just as demonstrated earlier, after initializing a
pointer, if you change the value of the variable it points to, the pointer
would be updated. Consider the following program:
#include <iostream> using namespace std; int main() { int value = 26; int *pointer; int **pointerToPointer; pointer = &value; pointerToPointer = &pointer; cout << " Value = " << value << "\n"; cout << " *Pointer = " << *pointer << "\n"; cout << "**Pointer = " << **pointerToPointer << "\n"; value = 4805; cout << "After changing the value of the main variable...\n"; cout << " Value = " << value << "\n"; cout << " *Pointer = " << *pointer << "\n"; cout << "**Pointer = " << **pointerToPointer << "\n"; return 0; }
This would produce:
Value = 26 *Pointer = 26 **Pointer = 26 After changing the value of the main variable... Value = 4805 *Pointer = 4805 **Pointer = 4805
Notice that, by changing the value of the original
variable, when accessing its pointer or the pointer to its pointer, they
reflect the new value. In the same way, instead of (directly) changing the
value of the variable, you can change the value of its pointer. You can
also change the value of the pointer to its pointer. Like a chain
reaction, all variables would be updated. Consider the following program:
#include <iostream> using namespace std; int main() { int value = 26; int *pointer; int **pointerToPointer; pointer = &value; pointerToPointer = &pointer; cout << " Value = " << value << "\n"; cout << " *Pointer = " << *pointer << "\n"; cout << "**Pointer = " << **pointerToPointer << "\n"; value = 4805; cout << "\nAfter changing the value of the main variable...\n"; cout << " Value = " << value << "\n"; cout << " *Pointer = " << *pointer << "\n"; cout << "**Pointer = " << **pointerToPointer << "\n"; *pointer = -728; cout << "\nAfter changing the value of the pointer...\n"; cout << " Value = " << value << "\n"; cout << " *Pointer = " << *pointer << "\n"; cout << "**Pointer = " << **pointerToPointer << "\n"; **pointerToPointer = 945580; cout << "\nAfter changing the value of the pointer to pointer...\n"; cout << " Value = " << value << "\n"; cout << " *Pointer = " << *pointer << "\n"; cout << "**Pointer = " << **pointerToPointer << "\n"; return 0; }
This would produce:
Value = 26 *Pointer = 26 **Pointer = 26 After changing the value of the main variable... Value = 4805 *Pointer = 4805 **Pointer = 4805 After changing the value of the pointer... Value = -728 *Pointer = -728 **Pointer = -728 After changing the value of the pointer to pointer... Value = 945580 *Pointer = 945580 **Pointer = 945580 |
Operations on Pointers
|
|
Introduction
|
|
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:
Of course, you can use various pointers on the same program. Apply an example by making the following changes:
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:
This would produce:
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 |
A Function That Returns a Pointer
|
If you want a function to return a pointer, when declaring
the function, make sure that you specify its return type as a pointer and you
can use a type of your choice. Here is an example of such a declaration:
#include <iostream>
using namespace std;
int main()
{
int *GetNumber();
return 0;
}
In this case, we have declared a function named GetNumber
that will return a pointer to int. When implementing the function, you can apply
any of the techniques we have used so far inside the function. The most
important rule to keep in mind is that the function must return a pointer and
not a regular value. In the same way, when calling a function that returns a
pointer, you can use its value only where the returned pointer is appropriate.
For example, you can assign its returned value only to a pointer of the same
type. Here is an example:
#include <iostream> using namespace std; int main() { int *GetNumber(); int *number; number = GetNumber(); cout << "Number = " << *number << endl; return 0; } int *GetNumber() { int *a = new int(2885); return a; }
This would produce:
Number = 2885 |
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
int Shirts;
the compiler reserves an appropriate amount of memory
space for that particular variable. This is done when the program is
compiling but before its execution. This means of providing memory space
is called static allocation, the memory space is "allocated" to that
variable. When the program executes, this static memory allocation does
not change; but the memory space might be empty, especially if the
variable is not initialized. This is important: the fact that a variable
is not initialized means its memory space is empty, it is not equal to
zero; it is simply empty. Nothing is occupying it.
You can also ask the compiler to provide memory when the program is executing. This is called dynamic allocation. Dynamic allocation is performed using the new operator like this: 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:
|
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; } |
No comments:
Post a Comment