A pointer is a variable that contains the memory address of another variable, array, or string. When a pointer contains the address of something, it is said to be pointing at that thing. When a pointer points at something, it receives the right to access the content of that memory address. The question now is—why do we need pointers at all?
We need them because they do the following:
- Facilitate the dynamic allocation of memory
- Provide an alternative way to access a data type (apart from variable names, you can access the content of a variable through pointers)
- Make it possible to return more than one value from a function
For example, consider an i integer variable:
int i;
When you define an integer variable, two bytes will be allocated to it in memory. This set of two bytes can be accessed by a memory address. The value assigned to the variable is stored inside that memory location, as shown in the following diagram:
In the preceding diagram, 1000 represents the memory address of the i variable. Though, in reality, memory address is quite big and is in hex format, for the sake of simplicity, I am taking a small integer number, 1000. The value of 10 is stored inside the memory address, 1000.
Now, a j integer pointer can be defined as follows:
int *j;
This j integer pointer can point to the i integer through the following statement:
j=&i;
The & (ampersand) symbol represents the address, and the address of i will be assigned to the j pointer, as shown in the following diagram. The 2000 address is assumed to be the address of the j pointer and the address of the i pointer, that is, 1000, is stored inside the memory location assigned to the j pointer, as shown in the following diagram:
The address of the i integer can be displayed by the following statements:
printf("Address of i is %d\n", &i);
printf("Address of i is %d\n", j);
To display the contents of i, we can use the following statements:
printf("Value of i is %d\n", i);
printf("Value of i is %d\n", *j);
We can also define a pointer to an integer pointer by means of the following statement:
int **k;
This pointer to a k integer pointer can point to a j integer pointer using the following statement:
k=&j;
Through the previous statement, the address of the j pointer will be assigned to the pointer to a k integer pointer, as shown in the following diagram. The value of 3000 is assumed to be the memory address of k:
Now, when you display the value of k, it will display the address of j:
printf("Address of j =%d %d \n",&j,k);
To display the address of i through k, we need to use *k, because *k means that it will display the contents of the memory address pointed at by k. Now, k is pointing at j and the content in j is the address of i:
printf("Address of i = %d %d %d\n",&i,j,*k);
Similarly, to display the value of i through k, **k has to be used as follows:
printf("Value of i is %d %d %d %d \n",i,*(&i),*j,**k);
Using pointers enables us to access content precisely from desired memory locations. But allocating memory through pointers and not releasing it when the job is done may lead to a problem called memory leak. A memory leak is a sort of resource leak. A memory leak can allow unauthorized access of the memory content to hackers and may also block some content from being accessed even though it is present.
Now, let's begin with the first recipe of this chapter.