Getting Deep Into C++ Pointers
In this article, we'll discuss the use of Pointers in C++. Pointers excel at making code shorter, more compact, and efficient, proving themselves valuable.
Join the DZone community and get the full member experience.
Join For FreeIntroduction
C++ being built on top of C language has readily inherited many core features, which include Pointers. Pointers were proven to be handy when it comes to working with data at memory level Statically or Dynamically. Many Programming Languages use Pointers in some or the other way.
Why Bother Learning Pointers?
Yes, it is so true that the same task could be accomplished without the use of pointers, but we must acknowledge that the proper use of pointers can make code more short, compact, and efficient at the same time.
C++ Pointers in Brief
Pointers were mainly introduced to peek and poke the data from memory effectively. Pointers were made to hold the memory addresses (i.e physical address/memory location) so that one could refer to the data at that memory location through pointers.
So What Is a Pointer?
Programmatically, a Pointer is a variable that can hold the address of other variables as its value and can indirectly refer to the contents of that memory address.
Pointer as a Variable
Yes, a pointer is a variable, which means that at some given time it can point to a variable (i.e hold the address of that variable) and next time it can point to some other variable of the same type (datatype).
Pointer as a constant
We can make a pointer constant which means it cannot point to other memory addresses with the use of const qualifier which we will see in the later parts. Before Moving into the Pointers Jargons, consider the following declaration:
int val = 100;
The above statement commands the compiler to
- Reserve memory space to hold an integer value.
- Associate name value to it.
- Assign value 100 to it.
Memory Map for the above statement are as follow:
As we can see, the compiler has chosen the memory location 65545 (Machine specific) to store the value 100. We can print this memory address as:
cout << &val; //prints the memory address of variable called val
We can store this address into a variable and refer to the value indirectly through that variable and here comes pointers into the limelight.
Pointers Syntax
Had the pointers been the same as ordinary variables, there wouldn’t have been any need to grasp them separately, so for sure pointers are not ordinary variables. Let’s take a look into the syntax of a pointer.
data_type* variable_name;
Here data_type refers to the data type of the variable whose address is going to be stored in the pointer variable. Alternatively, we can say that pointer is gonna point to a variable whose value is of type data_type.
Some valid examples of pointer declarations are as follows:
int *i_ptr;
float * f_ptr;
char* c_ptr;
string*s_ptr;
Note that the space isn’t necessary but the *(asterisk) should be in between data_type and variable_name.
Pointers Jargon
Consider the following pointer assignment statement:
xxxxxxxxxx
int val = 100;
int* ptr = &val;
Now we have successfully stored the address of val into ptr thus we can refer to val through ptr as:
xxxxxxxxxx
cout <<"Address of val "<< &val <<' '<< ptr;
cout <<"Value of val "<< val <<' '<< *ptr;
Two Key Operators
& (ampersand) - Read as 'Address of' operator
Eg. &val ~ Address of val.
* (asterisk) - Read as 'Value at address' operator or dereference operator
Eg. *ptr ~ Value at the address contained in ptr.
Remember * in *ptr is different from int* ptr.
int* ptr statement tells the compiler to declare an integer pointer variable.
While *ptr statement tells the compiler to dereference the pointer that gives the content of the memory address stored in ptr.
Working of Pointers
Now since we have the address of val variable in ptr, we can now access and manipulate the data stored at the memory address contained in ptr.
Below is the implementation of a simple program using pointer:
xxxxxxxxxx
using namespace std;
int main(){
int val = 100;
int* ptr = &val;
cout << val << endl;
*ptr = val / 10;
cout << val << endl;
return 0;
}
Thus not only we can access val with *ptr but also can change the data (or reassign) to any value of the same data type.
Pointers Extended
Since a pointer is a variable, it does occupy a space in memory and we can even store this address into another pointer variable, which would be called pointer to pointer. This way we can create a pointer to pointer to pointer to pointer and so on. For now, we would stick to a pointer to a pointer.
The declarative syntax of pointer to a pointer is given below:
xxxxxxxxxx
int val = 100;
int *ptr = &val; //pointer to integer
int **d_ptr = &ptr;//pointer to pointer which points to an integer
We can refer to the ptr contents as
cout << *d_ptr << ptr << &val; //eg 65545 65545 65545 i.e address of val
Since *d_ptr value is an address (address of val) thus we can access the actual data of val through the following statement.
xxxxxxxxxx
cout << "value of val"<< val << *ptr << **d_ptr;
//prints the value of val i.e 100
To manipulate the content of val through d_ptr we can write as **d_ptr = 2000;
Function Returning More Than One Value
We are aware that normally a function can return at most one value at a time. What if we need to return more than one value from a function? The Naive approach would be to make that many functions return different values. The other handy option is to use pointers making code more efficient
Without Pointers
xxxxxxxxxx
using namespace std;
int areaOfRectangle(int l, int b){
return l*b;
}
int perimeterOfRectangle(int l, int b){
return 2*(l+b);
}
int main(){
int l = 20, b = 30;
int area = areaOfRectangle(l, b);
int peri = perimeterOFRectangle(l, b);
cout << area << endl;
cout << peri << endl;
return 0;
}
With Pointers
xxxxxxxxxx
using namespace std;
Void arePeri(int l, int b, int* area, int* peri){
*area = l*b;
*peri = 2 * (l + b);
}
int main(){
int l = 20, b = 30;
int area;
int peri;
areaPeri(l, b, &area, &peri);
cout<<area<<endl;
cout<<peri<<endl;
return 0;
}
Types of Pointers
The types of pointers which should be known to a programmer are:
Null pointer
When a pointer doesn’t point to any valid memory location we should make to point it to null (i.e absence of value). int *ptr = NULL;
Constant pointer
When a pointer needs to point to only one memory location throughout its lifetime i.e it should be changed, then we can declare the pointer as constant.
xxxxxxxxxx
int val = 100;
int *const ptr = &val;//constant pointer
Void pointer
When we are not sure what the pointer is gonna point to .i.e would it point to an int or float or char? In such a situation, we should declare the pointer as a void pointer and explicitly make it point to a variable of any data type as desirable.
xxxxxxxxxx
int age = 20;
float height = 6.1;
void* ptr = NULL; // making it point to NULL
ptr = (int *)&age; // making it point to an integer variable
cout << *ptr <<endl; // prints the value of age
ptr = (float*)&height: //making it point to a float variable
cout << *ptr <<endl; //prints the value of height
Dangling pointer
When a pointer is trying to point to a memory location that is not available or inaccessible or freed (using a free function). Then the pointer is called a dangling pointer.
xxxxxxxxxx
int val = 100;
int *ptr = &val;
cout << *ptr; //prints 100
free(ptr);
cout << *ptr; //error
Pointers Arithmetic
An awesome feature of pointers is that they can move in memory to and fro. They jump forward or backward with each step equal to the memory size they are pointing to. For eg.
xxxxxxxxxx
int val = 10;
int *ptr = &val;
cout << ptr <<endl; //eg 65534
ptr++;
//prints 65538 (as typical int is of 4 bytes thus it jumps 4 bytes //i.e 65534 + 1 * size of integer type = 65534 + 4).
cout << ptr <<endl;
ptr = ptr - 2;
//prints 65530
//(65538 - 2 * size of integer type = 65538 - 2*4 = 65538 - 8).
cout << ptr<<endl;
Advantages of Pointers
The major advantages of pointers are:
- Makes the function return more than one variable at the same time.
- Makes code way shorter, compact resulting in increased speed of execution.
- Dynamic memory allocation and deallocation are possible only with the use of pointers.
- To implement various data structures (eg. Linked Lists, Trees, et)
Conclusion
Thus we can sum up by saying that a pointer is a construct that can point to a memory location and indirectly access and modify the contents inside it. From making function return multiple values to dynamic memory allocation pointers have shown their superpowers. Thus if a solution could be approached with the use of pointers, it should be solved with the use of pointers making code more efficient.
Opinions expressed by DZone contributors are their own.
Comments