EOSERV Wiki > Page: Simple Explanation of Pointers > History > Revision Diff

Revision Diff: Simple Explanation of Pointers

Revision by at 4th Jul 2011 07:25 am
DeletionsAdditions
todo: Pointers in classes and pointers to classes; explanation of the -> operator.
Pointers are a very important part of C++. They are a useful tool that allows you to manipulate the memory of a computer dynamically (at runtime).
This short(ish) explanation discusses the assigning memory, creating pointers, allocating new memory, and operators such as *, &, and ->.
Normal memory allocation is done with a data type and an identifier. The memory can be assigned a value at the same time as well.
Here is an example showing declaration of variables (allocation of memory) of ''int'' data types. ''double'' data types are declared and assigned in a single line, single statement format.
<pre>
int x;
int y;
int w, z;
</pre>
<pre>
double zz = 1.05;
double yy = 5.49;
double xx = 2, ww = 6;
</pre>
Pointers are declared using the * operator. When used as a unary operator (only one operand), it allows for dynamic allocation of a pointer type which is stored in a different part of the computer's memory than a standard variable. It is called a pointer because it essentially 'points' to a different location. The actual variable itself only holds a memory address of the location of that data item.
Since a pointer only holds an address to a chunk of data in memory, we need to know the '''address-of''' operator. This operator is an ampersand, and gives us the address of another variable. It can also be used in method signatures to pass a variable as a reference parameter.
If a variable int x; is stored in memory location 1000, the statement int y = &x; would store 1000 in y. If int x; is stored in memory location 10FFEAB2090774, the statment int y = &x would store 10FFEAB2090774 in y.
<pre>
int x = 100;
int y = &x;
cout << x << " " << y;
//Output would be "100 100"
</pre>
Since the address-of operator (the ampersand) provides a way of accessing a variable under multiple names (x and y both refer to the same location), it also allows manipulation of the same location.
<pre>
int x = 100;
int y = &x;
cout << x << " ";
y = 200;
cout << x;
//Output would be "100 200"
</pre>
Here is an example that uses the power of reference variables to pass three values back from a function.
<pre>
#include <iostream>
using namespace std;
int myFunc(int &x, int &y)
{
x = 1;
y = 2;
return 3;
}
int main()
{
int xx, yy;
cout << myFunc(xx,yy) << xx << yy;
return 0;
}
//output is 312
</pre>
Now that we have discussed references, we are ready to move on to pointers.
A pointer type variable is a regular data type that is marked with an asterisk (*) to indicate that it is a pointer type. Pointers (as previously mentioned) are variables that point to another location.
<pre>
int x = 5;
int* y = &x;
cout << x << y;
//Output will be "5" and the memory location of x.
</pre>
We know that a pointer stores a memory location of a data type. The way to access the data that the pointer points to is to again use the asterisk(*) operator in a process called '''dereferencing'''.
<pre>
int x = 5;
int* y = &x;
cout << x << *y;
//output will be "55"
</pre>
We know how to create a pointer from existing memory objects. The most confusing part is dealing with allocation of new memory, dynamically (at runtime). We will also need to make sure that memory is properly cleaned up as well. To do this we will need to use the ''new'' and ''delete'' keywords.
New memory is allocated in a space of memory called the 'heap'. Normal memory (what we have already discussed concerning allocation) is called the 'stack'. C++ does not include a garbage collector like Java or other languages that deal with most of the inner workings of dynamic allocation for you. This creates a need for the programmer to take care of deallocation themselves.
Here is an example for allocating an integer (usually 4 bytes).
<pre>
int *x = new int;
</pre>
Now this memory is allocated dynamically on the heap, as opposed to on the stack. It must also be cleaned up once you are done with it, this is done using the delete keyword. If the delete keyword is not used, a '''memory leak''' occurs and can cause memory problems on low-memory systems (usually not a problem, but makes for a terrible program/programmer if you can't even solve simple memory leaks).
<pre>
delete x;
</pre>
Pointers can also be used with arrays to dynamically allocated the size of a simple array. They are also useful with linked-list type structures (such as PtrList and PtrVector in eoserv) in which a list is a collection of 'nodes' where each node contains a pointer to the next item in the collection.
Here is a more complete example of using pointers to allocate an array where the size of the array is input from the command line.
<pre>
int arr_size;
cout << "Size of the array: ";
cin >> arr_size;
cout << endl;
int *my_array = new int[arr_size];
for(int i = 0; i < arr_size; ++i)
my_array[i] = i + 1;
for(int i = arr_size - 1; i >= 0; ++i)
cout << my_array[i] << " ";
delete [] my_array;
//This example prints out the contents of my_array in reverse order.
</pre>
From this example, the power of using pointers to manipulate data in a completely new way. A new syntax is presented here: ''delete [] my_array'' where the brackets are between the keyword ''delete'' and the identifier that you want to deallocate. Using the [] brackets there allows us to deallocate all the memory in the array, rather than just the first cell of the array. When deallocating an array, ALWAYS use the [].
[more to come, I'm tired ~ethanmoffat]
EOSERV Wiki > Page: Simple Explanation of Pointers > History > Revision Diff