In the following article we are going through the main concept of pointers in C+. Frankly speaking, misunderstanding the basics of painters principle leads often to aversion of C++ language. Moreover, lack the sense of feeling what we are doing, how the data flows, make developing time longer, since extra debugging time has to be incorporated.
Before we start dig into the principle. We can consider following simple anecdote and capture some better feeling what is a pointer.
Let us assume you live in big city and instead of using smartphone or mobile devices you have “old fashioned” book with all the bus routes in your city. You are exceptionally familiar with this book and know exactly how to find a bus, which takes you from the certain location of the city and deliver to destination. Each page of this book is numerated and contains complete information about the time table for certain bus stop. Your friend asked you to give him an exact time for a bus (for example nr: bus_29) which takes him in evening time from point A and deliver to point B. You know how to provide correct data but it takes a while. After 5 min you come with the answer and say to four friend: You have a bus 7.29PM. You closed a book and wait for the response. Your friend replied: OK, however asked again: But what is the time for the next time? To answer this question you need to repeat the same process again. It takes also 5 min. You come with the answer: Next bus is 8.03PM. This time however you are a bit smarter and do not close the book “completely”. You leave your finger on the page you nearly checked. Your friend is satisfied with the answer but he has not exhausted the enquiry. Do we have some bus between 6 and 7pm? This time to come with the answer is sufficiently faster for you since you have your finger on the page containing the information you are looking for. You come with answer: We have only one bus between 6 and 7pm. It leaves point A at 6.16PM. Your friend is now happy and says: Perfect, thanks I do not have any more questions. You remove your finger, close the book and put that in the bag.
Now we can draw some analogies. Your finger which you left in the book on certain page is the pointer. The number of the page is the memory address, Informations (time table for the bus), which are included on page are values under certain address (in our example certain number of book page).
As you can see, the pointer (you finger) speed up the process to get the data you looked for.
Clarification and simple example
In computer science we say that the pointer is the variable (our finger) which holds memory address (page of the book). That’s it.
To be more precise we can say that the main difference between variable and pointer is that, the variable holds the numerical value, however the pointer holds the address (hexadecimal value, which is understood by compiler as an address. By “giving” to a compiler special operator : (*) — dereferencing operator, compiler understands that stored hexadecimal value is an address). The address points to the variable name, defined during initialization or later by ordinary assignment to the address of variable.
Now we approach correct definition. The author of the book you checked for your friend, followed some certain policy and wrote the the time table (value or data) for the bus your friend asked on page 1000 (address of data). You remember you left your finger (pointer) on this page — page 1000 (address). Now we can write “pseudocode”:
bus_29 = time_table (… 6.16PM, 7.29PM, 9.03PM…)
your_finger = page 1000 (which contains the time table for bus29)
Now we can translate our pseudocode into C++ (here I applied some simplification and used only one time 7.29PM, which I expressed as 729. Normally, we could define time table as an array or vector, etc)
int bus_29 = 729;
int *ptr_bus_29 = &bus_29;
Just to give the overview what we have done.
int bus_29 = 729;
We define new variable, which name is a bus_29. Type of this variable is int. The value of the value is 729 (which in our case represents 7.29PM).
We can “ask” the compiler where the variable exists in memory. In order to do so we have to apply operator (&) — address operator, which returns the address of the variable.
std::cout << "address for bus_29 is : " << &bus_29 << std::endl;
//in our example we assume that this address equals 1000
Afterwards, we have to declare our pointer. Please note, the type of pointer has to be the same as the type of the value it points to, In our case also (int).
We use (*) — dereferencing operator, which returns the value stored in the address stored in the pointer variable.
// declaration of a pointer variable called ptr_bus_29
In order to use pointer, beside the declaration we need to initialize (assign to address). We can combine the declaration and initialization (assignment).
int *ptr_bus_29 = &bus_29;
Please, consider following example.
int bus_29 = 729;
int *ptr_bus_29 = &bus_29; //declaration and assignmentstd::cout << bus_29 << std::endl;
//prints (729)std::cout << &bus_29 << std::endl;
//prints the address of variable bus_29. In our case (1000)std::cout << *ptr_bus_29 << std::endl;
//prints value pointed by the ptr_bus_29, which in our case is (729)std::cout << ptr_bus_29 << std::endl;
//prints the content of variable (pointer) ptr_bus_29, which in our case is (1000)
Simple pointer arithmetic.
It is very valuable to see how we can use a pointer to traverse container (here we use an array. Array is a series of elements of the same type placed in contiguous memory locations). In following examples we use two arrays, one array holds the four value type of integer and other array which hold the value of string type. Please, take a look how we can traverse. In order to traverse the arrays (in below examples) we assign the pointer for the address of the first element of array. Incremental value of pointer address, shifts the position of pointed value in the array. As you know the integer occupies 4 bytes of memory, while the string 8 bytes. Compiler is smart enough and “understand” that adding (1) means just going to the next element of (in this case) array. Take a look for the address the pointer holds. When the pointer is integer type so the size increase (after incremental in for loop) by 4 bytes while for string size the address increases by 8 bytes.
Function pointer. Callback
In following paragraph we will discuss about pointer, which stores the address of function. This method is very useful while we use a callback.
Let us take a look of below picture, which depicts the simple machine memory. The addresses this time starts from 3000. Please note this memory location is not the same memory like for storage of variables. This “type” of memory is dedicated only for the code of your program. Anyway, we can assume that (in example below) the main function occupies 12 bytes (3 instructions), while calledFunction, callBack_1, callBack_2 occupies 8 bytes each (2 instructions). The function is a set of instructions (definition of function => what the function does), which are stored in contiguous block of memory.
When we call a function, we call the first instruction of the defined function (entry point). The name of the function is associated with the address of this entry point (which is also the address of our function).
The function pointer similar to variable pointer stores the address. This time however is not the address to variable but to the entry point of the function (address of the first instruction of called function).
Normally, the program runs sequentially, instruction by instruction. However we can change this routine (the program can jump to the other function), for example if we call the function from the other function.
In our case, when we call a function calledFunction (from main), we can call further other function (callBack_1 or callBack_2). This is done by sending (as a parameter) a function pointer. calledFunction, according to the received address of callback calls callBack_1 or callBack_2.
In this article I displayed some basic introduction to pointer in C++. Please, note that given examples do not exhaust the pointer domain. In next articles I will focus of dynamic allocation of memory and smart pointers.
Thank you for your time.