Pointers in C++

Pointers in C++




Pointers

As you know every variable is a location of computer’s memory where the value of the variable is stored. When you declare a variable, a part of memory is allocated to store it. The location of this part of memory is specified by the address of the variable. The address of the memory is a numeric value. This address can be accessed by using variable’s identifier (its name). You can see this address by using the address-of operator (&) in front of the variable:

int a;
cout << "The address of \"a\" variable is " << &a;

This is the output when code is executed:

The address of “a” variable is 0016FE18

The output of this code will be different on different computers.

A pointer is a variable. Its’ value is the address of the other variable in the memory. The declaration of the pointer is the same as the declaration of a simple variable except of use of * in declaration:

data_type* identifier;

Here are some examples of declaring different pointers:

//pointer to int
int* p;
//pointer to double
double* d;
//pointer to float
float* f;

You can assign a value to a pointer by using address-of (&) operator:

int a;
cout << "The address of \"a\" variable is " << &a << endl;

//pointer to int
int* p;

p = &a;// now p is equal to the address of 'a' variable
cout << "The value of \"p\" variable is " << p;

The value of pointer p is equal to the address of variable a in computer’s memory:

The address of “a” variable is 0028FBFC
The value of “p” variable is 0028FBFC

This can be represented by the following image:

If you want to get the value stored in the memory by using a pointer, you have to use unary dereference operator (*) in front of the pointer identifier. This operator will return the value stored in the specified address:

int a = 10;
//pointer to int
int* p;
p = &a;// now p is equal to the address of 'a' variable
cout << "The value stored in memory location " << p << " is " << *p << endl;

The output is:

The value stored in memory location 001CFA10 is 10

You can use pointers in your programs for a lot of reasons. Here we will discuss some important operations that can be done using pointers:

Dynamic allocation of memory

C++ provides the possibility to make manual management of memory. This means that you can allocate memory for the variable manually.

One of the simple tasks that lead to the need of the dynamic allocation of memory can be represented by the following scenario:

“Ask user to enter the number of elements.
Take input from user.
Display all the entered elements”.

In this case the program doesn’t “know” how many elements will be entered by the user before execution. The program has to allocate memory for input during runtime after user’s input of number of elements.

For dynamic allocation of memory C++ offers operator new:

new data_type;

If you want to allocate memory for an array, you will have to use the following syntax:

new data_type[size_of_array];

Here is the solution of the task described above:

int* arr;//pointer to int
int n;//number of elements
cout << "Please, enter the number of elements for input" << endl; cin >> n; // get n

arr = new int[n];//allocate memory for array of int of size n
//get user input
cout << "Enter " << n << " elements" << endl; //get elements in loop for (int i = 0; i != n; ++i) cin >> arr[i];
cout << "You entered :" << endl;
for (int i = 0; i != n; ++i)
	cout << "arr[" << i << "] = " << arr[i] << endl;

This code provides the following output:

Please, enter the number of elements for input
5
Enter 5 elements
1
2
3
4
0
You entered:
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 0

The dynamic allocation of memory will be discussed later in “C++ Dynamic Memory” topic.

You must release the memory using operator delete if you have allocated it manually using new operator:

delete pointer; for single object and
delete[] pointer; for an array of objects

Pointer Arithmetic

As you already know from this article, pointers have numeric values. You can use the following arithmetic operations with pointers: ++, –, + and -.
The increment operator (++) will increment the value of pointer according to the pointer’s type. The address will be incremented by the size of pointer’s type. So, the pointer will change its value and will store the address of the next element of the pointer’s type. For example, we have a pointer to an integer array:

int* a;
a = new int [3];

Initially this pointer stores the value of the start address of the memory:

If we will increment a:

++a;

It will change its value to the next integer in the array:

The decrement operator (–) decrements the value of the pointer and it stores the address of the previous element of the pointer’s type. If we decrement the “a” pointer again:

--a;

It will store the address of the previous element again:

You can add or subtract an integer value from a pointer. The addition of a value N to a pointer will forward the pointer to the next N elements of the pointer’s type. For example, we can increment the value of pointer a by 2:

a = a + 2;

This will change pointer “a” to store address of the 3rd element of the array:

Pointers as parameters of a function

When you pass a variable to the function, you just pass the value of the variable. But you can’t change the variable itself from the function.
But sometimes the possibility to change variables from the function is very useful. You can do it by passing the address of the variable to the function. This means that the parameter of the function is a pointer. And the function will access the location of memory where the variable’s value is stored. Take a look on this example:

void changeA(int* a)
{
	(*a) = 10;
}

We can try to change variable from the function:

int *k= new int;
(*k) = 2;//setting value to k
cout << "k before calling function " << *k <<  endl;
changeA(k);
cout << "k after calling function " << *k << endl;

K variable is changed in function:

k before calling function 2
k after calling function 10

Passing an array to function

You can pass an array to function as a pointer. It can to be done because the array’s name is pointer to the start of the array. So, if you declare an array:

int myArr[5];

myArr is pointer to the start of the array.

We can create a function to calculate the sum of array’s elements. This function will take 2 parameters: a pointer and the size of the array:

int sum(int* arr, int size)
{
	int sum = 0;
	for (int i = 0; i != size; ++i)
		sum += arr[i];
	return sum;
}

Now we can initialize array with some values in function main:

for (int i = 0; i != 5; ++i)
	myArr[i] = i;

And after this we can call function to calculate the sum of array’s elements:

cout << "Sum of myArr's elements is " << sum(myArr, 5);

Here, “sum(myArr, 5)” array myArr is passed to the function sum by using pointer to the first element of the array.

Return Pointer to Array from Function

You can return an array from the function exactly in the same way as you pass an array to function – by using pointers. You have to specify the return type of the function as pointer to the same type as the type of array’s elements:

type* function_name(parameters list);

For example, we want to change all the elements of an int array to the Opposite. In this case, we can create the following function:

int* changeArray(int* arr, int size)
{
	//get copy of array's elements
	int* copy = new int[size];
	for (int i = 0; i != size; ++i)
		copy[i] = arr[i];
	//changing the elements sign
	for (int i = 0; i != size; ++i)
		copy[i] *= -1;
	//return array from function
	return copy;
}

Now we can call this function in this way:

int* newArr;
//call function that returns an array of int
newArr = changeArray(myArr, 5);
cout << " newArr contains:" << endl;
for (int i = 0; i != 5; ++i)
	cout << "newArr[" << i << "] = "  << newArr[i] << endl;

This function returns new array of integers:

newArr contains:
newArr[0] = 0
newArr[1] = -1
newArr[2] = -2
newArr[3] = -3
newArr[4] = -4

near, far and huge pointers

The near, far and huge pointers are pointers that have to be used to deal with segmented memory architecture. They are relevant to the 16 bit Intel Architecture, so they are not used with the most part of the modern computers. 16 bits compilers (Turbo C++, Borland C++) support different types of pointers: the type of pointers is different by the memory location it can point up. The memory location in this case is calculated by using segment register and offset register. Both registers have size of 16 bits. The address is calculating by the following formula:

Address = SegmentRegister << 4 + OffsetRegister

Near pointer is only 16 bits wide. It holds only the offset address. That’s why it can access only memory with the maximum 0xFFFF offset in the current segment.

Far pointer is 32 bits wide. It holds the segment address (16 bits) and the offset address (16 bits). Far pointer can point to any segment and any offset in this segment. You can create a far pointer by using MK_FP(segment, offset) macro:

int far * farIntptr = (int far * )MK_FP(0xA000, 0x1234);

Using a far pointer for segment 0xA000 you can access address in range from 0xA0000 up to 0xAFFFF. If you will try to increase the pointer’s offset value 0xFFFF it will be changed to zero.

Huge pointer is 32 bits wide too. The main difference from the far pointer is that you can change the pointer’s segment address. For example, if you will try to increment the pointer with address 0xAFFFF – you will change its segment address to 0xB000. Huge pointer can be created by using MK_FP(segment, offset) macro too:

int huge * hugeIntPtr = (int huge * )MK_FP(0xA000, 0xFFF0);

Pointer to function

C++ provides possibility to create and use pointers to the functions. There are several reasons to use pointers to the function. One use is when you want to give user a possibility to choose how a particular part of an algorithm or a function will work. It means that you can pass a pointer to a function as a parameter to another function.

Take a look on the following example. You have 2 functions that return minimum and maximum value from 2 integers:

int min(int a, int b)
{
	if (a < b) return a; return b; } int max(int a, int b) { if (a > b)
		return a;
	return b;
}

Now you can declare a pointer to a function. The common syntax used for such a declaration is:

functionReturnType (*pointerIdentifier) (listOfFunctionsParameters);

For example, the pointer to the both min and max functions will look like below:

int(*funPtr)(int, int);

Now we can use a pointer to a function as a parameter of another function – getArrayExtremum. getArrayExtremum function will be able to determine the greatest or the smallest element of an integer array:

int getArrayExtremum(int* arr, int size, int(*funPtr)(int, int))
{
	int extremum = arr[0];
	for (int i = 1; i != size; ++i)
		extremum = funPtr(extremum, arr[i]);
	return extremum;
}

This function takes 3 parameters – the 1st one is a pointer to an integer array, the 2nd is the size of the array and the last one is a pointer to a function that will make a decision about getting the extremum.

Now we can get minimum and maximum element of an array by using the same function – getArrayExtremum:

//declare a pointer to function that takes 2 integers as a parameter and returns an integer
int(*funPtr)(int, int);

//declare and initialize an array of integers
int newArrOfInt[] = {-2, 4, 4, 0, -5, 8, 3,2};
funPtr = min; //now funPtr points up function min

//get minimum element of this array by using pointer to min function as the 3rd parameter
int minEl = getArrayExtremum(newArrOfInt, 8, funPtr);

cout << "The minimum of the array is " << minEl << endl;

funPtr = max; //now funPtr points up function max

//get maximum element of this array by using pointer to max function as the 3rd parameter
int maxEl = getArrayExtremum(newArrOfInt, 8, funPtr);

cout << "The maximum of the array is " << maxEl << endl;

const Pointer

There are 3 ways to use const keyword with pointers:

Pointer to Constant Data

A pointer to constant data that will not allow modifying data using pointer. It can be declared in the following way:

const type* ptr

or

type const* ptr;

Example:

const int*  constData;

Pointer with Constant Address

A pointer with the constant address can be declared in the following way:

type * const ptr = memoryAddress;

Example:

int t = 7;
int* const constAddres = &t;

Pointer with Constant Data and Constant Address

A pointer with constant data and constant address can be declared in the following way:

const type * const constDataConstAddress = memoryAddress;

or

type const * const constDataConstAddress = memoryAddress

Double and Triple pointer. Multiple indirection

Double and triple pointer is a kind of multiple indirection. A double pointer is a pointer to pointer. It means that this pointer stores the address of another pointer that points to a variable. Take a look on example:

int a = 10;
cout << "The address of \"a\" variable is " << &a << endl;

//pointer to int
int* p;
	
p = &a;// now p is equal to the address of 'a' variable
cout << "The value of \"p\" variable is " << p << endl;
//pointer to pointer
int** doublePtr = &p;
cout << "The value of \"doublePtr\" variable is " << doublePtr << endl;

It can be represented by the following image:

If you want to get the value referenced by a double pointer you will have to use the dereference operator twice:

cout << "Value for **doublePtr " << ** doublePtr;

Double and triple pointers are often used for 2 reasons – passing a pointer to a function and dynamic allocation of memory for 2D and 3D arrays. The use of pointers for dynamic memory allocation is described in C++ Dynamic Memory.

To understand how double pointers are used with functions, we can examine the following example: you have a function with pointer inside it:

void function1()
{
	int *p = new int; // a pointer to int
	(*p) = 10;
	//pass pointer p by reference to function2
	function2(&p); 
}

And in the function1 you want to pass pointer “p” to another function – function2 by reference:

function2(&p);

In this case the function2’s parameter must be a pointer to pointer:

void function2(int** p2)
{
	(**p2)+= 10;
}

 

Translate ยป