This item was added on: 2003/02/24
The following article was written by Stoned_Coder
What is a pointer?
How do I declare a pointer in my c/c++ code?
Can pointers point to functions?
OK. So now I have a good idea how to declare a simple pointer, how do I use them. How do I get the object being pointed at?
So is there some relationship between operator * and operator & ?
Can you apply operator * to an object or operator & to a pointer.
Can several pointers all point at the same object?
How should we signify that a pointer doesn't point to anything?
Can we set one pointer to equal another pointer?
What is a void* ?
Explain how const works with pointers.
So what's this pointer arithmetic you have mentioned?
Can we talk about function pointers now?
What is a smart pointer?
What is passing by value?
So what is passing by reference?
Supplimentary Examples
Q. What is a pointer?A pointer is a variable just like any other. It holds a memory address and no matter what type it is pointing to, the size of a pointer is constant, 32 bits on a 32bit system.
Q. How do I declare a pointer in my c/c++ code?For a given type T a pointer to T is a T*. So here are some examples.
int myint;
double mydouble;
long mylong;
int *pointer_to_myint = &myint;
double *pointer_to_mydouble = &mydouble;
long *pointer_to_mylong;
pointer_to_mylong = &mylong;
Q. Can pointers point to functions?Yes they can. We will deal with this later when we understand pointers better.
Q. OK. So now I have a good idea how to declare a simple pointer, how do I use them. How do I get the object being pointed at?To get at the object being pointed to by a pointer you have to dereference it. This is where most newbies suffer the most confusion. It is simple I promise you. Given a pointer P then the object being pointed to is *P. This might be easier to see in code...
int myintA, myintB;
int *pmyint = &myintB;
myintA = 10;
pmyint = &myintA;
Q. So is there some relationship between operator * and operator & ?Yes. operator & is the address of operator. You can use it to turn an object into a pointer. Operator * is the dereference operator. You use it to turn a pointer back into an object.
Q. Can you apply operator * to an object or operator & to a pointer.You cannot dereference an object. Thats an illegal operation. You can however take the address of a pointer. This surprisingly enough is called a pointer to a pointer. This is sometimes necessary to do especially in C when you have to pass a pointer by reference into a function. Simple meaningless snippet to illustrate..
int A;
int * pmyint = &A;
int** pointer_to_pointer = &pmyint;
Q. Can several pointers all point at the same object?Of course. You can have an unlimited number of pointers to a single object.
Q. How should we signify that a pointer doesn't point to anything?Set the pointer to NULL or 0.
Q. Can we set one pointer to equal another pointer?If they are of the same type then yes otherwise you must cast to the correct type to do this.
Q. What is a void* ?A void* is a generic pointer type. It's a pointer but the type pointed to is unknown. You may not dereference a void* but instead must first cast it to another pointer type before you dereference. Also you may not use a void* in any form of pointer arithmetic.
Q. Explain how const works with pointers.OK. This is another source of confusion for the newbies. It's simple enough once you see it in action. To explain this we need to touch on pointer arithmetic. Don't worry we will come back to that later in more detail. Firstly when we talk about const with pointers we have to make a distinction between the pointer and the object being pointed at. This snippet will explain in code....
const int cintA = 10;
int intB = 20;
const int *pointer_to_const_int = &cintA;
*pointer_to_const_int = 20;
pointer_to_const_int++;
const int *const const_pointer_to_const_int = &cintA;
const_pointer_to_const_int++;
*const_pointer_to_const_int = 40;
int *pointer_to_int = &intB;
*pointer_to_int = 40;
pointer_to_int++;
int *const const_pointer_to_int = &intB;
const_pointer_to_int++;
*const_pointer_to_int = 80;
So in recap if the const appears before the * then it relates to the object and if the const appears after the * it relates to the pointer itself.
Q. So whats this pointer arithmetic you have mentioned?Lets think about an array for a minute. Arrays have a type. It is this type that governs the size of a single element. The number of elements multiplied by the sizeof( arraytype ) is the amount of contiguous memory that is needed to store the array. The name of the array is nothing more than a disguised constant pointer to the first element of the array or array[0] in c/c++ terms. If we wish to access the second element of our array, in c we would use the term array[1]. Lets examine what exactly the [] does. This is actually shorthand for *(array+number_inside_[]). This is pointer arithmetic but it is disguised with a friendly face, operator [].
Addition and subtraction are allowed with pointers. When you add an integer to a pointer you are moving the memory location pointed at by the integer number multiplied by the sizeof (pointertype). For instance if I have a char* and I add 1 to it I have advanced the pointer by sizeof(char) bytes. If I add 1 to an int* then I will have advanced the pointer by sizeof(int) bytes. Subtraction does the same except it retreats the pointer by sizeof(pointertype). You can also subtract 1 pointer from another to get the spacing between them. C++ and C provide a special type for this particular calculation. Its called ptrdiff_t and is found in cstddef
or stddef.h
.
Illustration in code of pointer arithmetic....
int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int *parray = array;
for (int i = 0; i < 10; i++)
{
cout << *(parray + i) << endl;
cout << array[i] << endl;
}
parray = &array[9];
for (int i = 0; i < 10; i++)
{
cout << *(parray - i) << endl;
cout << array[(9 - i)] << endl;
}
Naturally you can also use both forms of operator ++ and operator -- on pointers.Remember also that void* pointers cannot be used for pointer arithmetic.
Not strictly pointer arithmetic but you can also compare pointers with the usual comparison operators !=,==,<,>,<=,>= . This can be a very useful facility sometimes.
Q. Can we talk about function pointers now?Sure now that we have covered simple pointers lets look at function pointers. Just as an array name is a constant pointer to an array, a function name is similarly a constant pointer to the starting address in memory of the function. Declaring a function pointer can be a bit tricky and again another major source of confusion to the newbies. It looks like this...
return_type (*pointer_to_function_name) (params)
For instance, look at this small working program.....
#include <iostream>
#include <iomanip>
using namespace std;
void Swap(int *const, int *const);
void BubbleSort(int[], const int, bool(*) (int, int));
bool Ascending(int, int);
bool Descending(int, int);
int main(void)
{
int array[] = { 20, 10, 30, 50, 70, 60, 80, 90, 110, 140, 120, 130, 200 };
const int ArraySize = sizeof(array) / sizeof(array[0]);
cout << "1 to sort ascending or 2 to sort descending: ";
int choice;
cin >> choice;
for (int i = 0; i < ArraySize; ++i)
{
cout << setw(6) << array[i];
}
cout << endl;
if (choice == 1)
BubbleSort(array, ArraySize, Ascending);
else if (choice == 2)
BubbleSort(array, ArraySize, Descending);
else
{
cout << "Blithering Idiot!" << endl;
return(0);
}
for (int i = 0; i < ArraySize; ++i)
{
cout << setw(6) << array[i];
}
cout << endl;
return(0);
}
void Swap(int *const ptr1, int *const ptr2)
{
int temp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = temp;
}
bool Ascending(int a, int b)
{
return(b < a);
}
bool Descending(int a, int b)
{
return(b > a);
}
void BubbleSort(int array[], const int ArraySize, bool (*compare) (int, int))
{
for (int pass = 1; pass < ArraySize; ++pass)
{
for (int single_pass = 0; single_pass < ArraySize - 1; ++single_pass)
{
if ((*compare) (array[single_pass], array[single_pass + 1]))
Swap(&array[single_pass], &array[single_pass + 1]);
}
}
}
Here you can see function pointers in action. This is not a great example but was quick to put together. Go to the full function pointer tutorial for more!
Q. What is a smart pointer?A smart pointer is a user defined class in c++ that acts as a pointer but is in fact an object. This has some important uses when you want to write exception-safe code. There are many uses for smart pointers and they warrant a very in depth article in themselves.
For more on smart pointers, see the tutorial on using the auto_ptr smart pointer.
Q. What is passing by value?To explain this we must first look at exactly what happens when a function is called, so let's look at a simple example:
int func (int a, int b)
{
return (a + b);
}
Now as you can see we've made a function that takes 2 ints and returns their sum. What happens when we call this. Well firstly the parameters for the function must be COPIED to the stack. Then the function code executes and the return value is COPIED to the stack. So if we say:
int a = 10;
int b = 20;
int c = func(a,b);
then inside the code for func()
we're manipulating copies of a and b and not a and b themselves. This is passing by value. Any changes we make to a and b within the function will not be reflected to a and b in the calling function.This can be observed by running this simple program.
#include <iostream>
using namespace std;
void ByVal(int a)
{
a++;
cout << " Value of a in ByVal is " << a << endl;
}
int main(void)
{
int a = 10;
cout << "Value of a in main is " << a << endl;
ByVal(a);
cout << "Value of a in main is " << a << endl;
return(0);
}
In C all parameter passing is by value. Soon we will see how to get around that.
Q. So what is passing by reference?This answer is split in two. First, an answer that suits both C and C++, then one for C++ only.
When we pass by reference we are not working with copies of our data but instead the data itself. Therefore any changes made to our data in a function WILL BE REFLECTED BACK TO THE CALLING FUNCTION. To accomplish this in C you have to use pointers.
Instead of passing our data, we instead pass our data's address in memory. Look at this small snippet.
void func (int* a)
{
(*a)++;
}
Here we have a small function that takes a pointer (by value) and uses it to "reference" the data we want to play with. This time the increment to *a is reflected back to the calling function. Please note that the pointer a is passed by value. So, what if we wanted to pass a pointer by reference? Well there is an answer to this, you pass a pointer to a pointer.
void func(int **a)
{
(*a)++;
}
This would modify a pointer by reference. The pointer to pointer is passed by value but you can use that to "reference" the pointer you want to play around with. Here's a small program so that you can see it in action.
#include <stdio.h>
void ByRef(int *a)
{
(*a)++;
printf("The value of *a in ByRef is %d\n", *a);
}
int main(void)
{
int a = 10;
printf("Value of a in main is %d\n", a);
ByRef(&a);
printf("Value of a in main is %d\n", a);
return(0);
}
And now to the C++ only answer.Everything above is valid for C/C++ but in C++ we also have reference parameters. These do what pointers do but are much easier to use and less prone to errors. Here's how you pass by reference in C++.
void func(int &a)
{
a++;
}
Notice the only difference between this and the by value alternative is we pass an int& rather than an int. int& means "reference to int". Behind the scenes of references the compiler is playing with pointers but that means we don't have to.A runnable example of reference passing C++ style:
#include <iostream>
using namespace std;
void ByRef(int &a)
{
a++;
cout << " Value of a in ByRef is " << a << endl;
}
int main(void)
{
int a = 10;
cout << "Value of a in main is " << a << endl;
ByRef(a);
cout << "Value of a in main is " << a << endl;
return(0);
}
Credit: Stoned_Coder
Supplimentary Examples
Here are some additional examples supplied by golfinguy4 to suppliment Stoned_coder's paper:
#include <iostream>
using std::cout;
using std::endl;
int main(void)
{
int *foo;
foo = new int;
*foo = 4;
cout << "The address of the pointer is " << &foo <<"." << endl
<< "The address the pointer is pointing to is " <<foo <<"." <<endl
<< "The value that is held in the address that the pointer is pointing to is " <<*foo <<"." <<endl;
delete foo;
return(0);
}
#include <iostream>
using std::cout;
using std::endl;
int main(void)
{
int *foo;
int number;
foo = &number;
number = 5;
cout << "The address that number is at is " << &number << endl;
cout << "This address being pointed to by foo " << foo << endl;
cout << "number= " << number << endl;
cout << "(accessed through foo) number= " << *foo << endl << endl;
number = 2;
cout << "number= " << number << endl;
cout << "*foo= " << *foo << endl << endl;
*foo = 10;
cout << "Number= " << number << endl;
cout << "*foo= " << *foo << endl;
return(0);
}