A pointer is a variable that points to the memory location of another variable or an object. The pointer itself is also a variable — the difference between a pointer and another variable, or an object, is that while a variable or an object contains data, a pointer contains an address or the memory location of another variable or object in memory. In this article we will explore the concept of pointers in C++, how to use them, and the best practices for using them.
Working with Pointers
Now that you have an idea of what pointers are, let's dig into some code. The following are valid pointer declarations:
int *i; // pointer to an integer variable
double *d; // pointer to a double variable
float *f; // pointer to a float variable
char *c; // pointer to a character variable
Note that the data type of the pointer should generally be of the same type to which it points. So, an integer pointer would point to an integer variable, a character pointer to a character variable, and so on. However, in the case of pointers to objects of classes, you can also have a base class pointer pointing to a derived class instance. We will explore more on this as we move on.
A pointer can also point to an instance of a class. Consider the following class.
cout << "Hello World" << endl;
Test *ptrObj = &testObj;
As you can see in the code snippet above, the pointer ptrObj is of type Test and points to the memory location of the object testObj. And, testObj is an instance of the Test class. Note that "ptr" is a naming convention generally used to denote pointers.
Once a pointer has been made to point to an instance of a class, you can access the public members of that class using the member access operator as shown in the code snippet below.
Dangling pointers are dreaded errors in C++. You often come across a runtime error if the pointer you are trying to access is dangling. What are dangling pointers? Well, a dangling pointer is one that points to the memory location of an object that has already been deleted from memory. Let's understand this with an example.
Consider the Test class we declared earlier. Suppose there are two pointers, both of which point to the same instance of the Test class.
Test *ptr1 = new Test();
Test *ptr2 = ptr1;
Now, suppose you delete one of the two pointers — say ptr2 in our example.
If you try to invoke the Display() method now, using the other pointer (ptr1), you will encounter an error as ptr1 is now a dangling pointer.
ptr1->Display(); //Error: The pointer ptr1 is now a dangling pointer!
Function pointers are pointers that point to the base address of a function in memory. Function pointers are used to call any number of functions using one single function pointer, provided the signature of those functions are identical.
To assign the address of a function to a function pointer, just assign the function without the parentheses to the function pointer. So, if fptr is a function pointer to a function fn, the following statement would assign the address of the function fn to the function pointer named fptr.
fptr = fn;
The statement given below denotes a function pointer fptr to a function that returns int and doesn't accept any arguments.
int (*fptr) ();
To call the function fn through the function pointer fptr, use the statement given next.
Dynamic Memory Allocation and De-allocation
Dynamic memory allocation is a strategy in which memory is allocated dynamically in the heap memory. To allocate memory dynamically in the memory heap, the methods
realloc are used. When memory that is dynamically allocated is no longer needed, you should free the memory using the free method. The free method is used to return the allocated memory to the memory heap. Memory leaks occur if dynamically allocated memory is not released. After a certain point of time, the system runs out of memory — this might result in stack overflow or failure to allocate memory dynamically in the heap.
Points to Be Noted
In this section I would like to provide you a few tips and precautionary measures that you should keep in mind when programming using pointers.
- Never de-allocate a pointer twice especially if the pointer is a dangling pointer.
- One you are done using a pointer, set it to NULL (meaning that the pointer now doesn't point to any valid memory address) or call free to de-allocate the allocated memory.
- Use void pointers (void *) as generic pointers to point to any data types.
Pointers are variables that point to addresses in the memory. Pointers, though powerful, should be used with utmost care to avoid errors that might creep in at runtime. In this article we have explored a bird's eye view of using pointers in C++. Happy reading!