Sunday, Dec 10th

Last update12:59:40 PM GMT

Pointers: complicated stuff made easy !!

Write e-mail

Array and Pointers are two things that are almost always explained one after the other everywhere. You so often come across terms like Pointers, Pointer to Pointer, Pointer to Array, Array of Pointers that all sound similar and if you are not very clear about the difference between them, it is quite sure that you will fall in the trap and get confused like anything.

argaiv1865

I strictly suggest you to have read the previous article on Arrays and Pointers to have better understanding of what is going to follow. The concept of Pointer is not so difficult to understand and I believe it has been quite effectively explained by me in the preceding articles.

You already know if we have an array like int array[10] and we wish to access the ith element, we can do so using:

int x= array[i] or int x= *(array + i)

Now we will move to little more complicated concepts. We will start with Array of Pointers and then we will move further to Double Pointer and then lesser used Pointer to Array.

Array of Pointers

Suppose we again have a 2-D array:

int my_array[4][5]. //Assume we have filled it as well with integer elements, or else the values will be undefined.

For my_array, my_array[i][j] is a syntactically a legal reference to the integer item in ith row and jth column.

As we said before, a 2-D array is one 1-D array whose each element is again a 1-D array. What we do now is that we declare an array of pointers. This is how we do it:

int * new_array[4];

Its easy to deduce that what we mean here is an array of 4 pointers. What is each of the four pointers pointing to..?

Well nothing till now because I haven’t initialized them till now, but they should point to some integer that is for sure (because that is what we have told the compiler).We need to set aside some memory for each of these 4 pointers.

We can do it like below:


for (int i=0;j<4;j++)
*(new_array + i) = (int *) malloc (5 * sizeof(int));

As you see above, for each of the 4 integer pointers a memory size equivalent to 5 integers has been set aside. That means in the above memory assignment we could have assigned variable memory to each of the 4 pointers like *(new_array + 0) assigned memory=5 integers; *(new_array + 1) assigned memory =6 integers and this way. We could not have achieved this with static 2-D array implementation.

Dereferencing any of the 4 pointers say the ith one: *(new_array + i) will give us the address to which this ith pointer is pointing to. And what is it pointing to. Well the ith pointer is pointing to the starting address of a contagious block of 5 integers we allocated to it above. So to reach the jth integer (j ranging from 0 to 4) of these 5 integers, we need to move the pointer j locations ahead and then dereference it. Hence to reach the jth element we will have to use somthing like below:

int x = *(*(new_array + i) + j);

See array of pointers in action below:

void printUsingPointers( int **p, int n_rows, int n_cols )
{
int i, j;
printf("Output Using Pointer to Pointer i.e.\n");
for( i = 0; i < n_rows; i++ )
{
    for( j = 0; j < n_cols; j++ )
    {
       printf("%2d ", *(*(p+i) + j ) );
    }
   }
} 
int main()
{
printf("Using array of pointers - Half Dynamic\n");
int *array[4];
int i; 
for( i = 0; i < 4; i++ )
*(array+i) = (int *)malloc( 3*sizeof( int ) ); 
*(*(array + 0) + 0) = 0; *(*(array + 0) + 1) = 1;*(*(array + 0) + 2) = 2;
*(*(array + 1) + 0) = 3; *(*(array + 1) + 1) = 4;*(*(array + 1) + 2) = 5;
*(*(array + 2) + 0) = 6; *(*(array + 2) + 1) = 7;*(*(array + 2) + 2) = 8;
*(*(array + 3) + 0) = 9; *(*(array + 3) + 1) = 10;*(*(array + 3) + 2) = 11;
printUsingPointers( array, 4, 3 );
}

Note that in the above function we have passed array as the parameter which is basically the starting address of this array of integer pointers. So if we point a pointer to this address it will be of type int** p (like in the function printUsingPointers). This is because p here is not pointing to address of an integer, rather it is pointing to address of the first pointer of the array of pointers, which in turn is pointing to the address of an integer. This is what we call a double pointer which we will explain below:

Also note here that every 2D array holds direct correspondence to a double pointer. In whatever discussion we did so far for a 2D array and what will follow we can replace *(*(array + i) + j) notation by array[i][j] as they both mean the same. However to illustrate the use of pointers more clearly I will preferably use the pointer notation. 

DOUBLE POINTER

We saw above in case of array of pointers, how to set aside memory to store integers for each of pointer of the array. Correct?

But the above implementation was just half-dynamic. Using a double pointer we can fully dynamicise it. ;-)

Now suppose we have a pointer to a pointer and we set aside memory to this double pointer to store 4 integer pointers, then we have this double pointer pointing to an array of 4 integer pointers. Fine till here!! Now what we do: For each of these 4 integer pointers we allocate memory equivalent to 3 integers. Of course its not necessary, we could have set aside memory equal to 3 integers for the first pointer in the array and 2 integers for the second pointer in the array and so on. So this way we have a hypothetical dynamic 2D array. Dont we? ;-)

This what I touched and left in the previous article when I was discussing 2D arrays.

See it below and you will understand.

printf("Using Pointer to Pointer - Fully Dynamic\n");
int **array2;
array2 = (int **)malloc( 4* sizeof( int * ) ); //memory assigned = 4 integer pointers
// each row is a 1D array
//each integer pointer assigned memory = 3 integers
for( i = 0; i < 4; i++ )
*(array2+i) = (int *)malloc( 3*sizeof( int ) );
array2[0][0] = 0; array2[0][1] = 2; array2[0][2] = 3; //using array notation this time

array2[1][0] = 0, array2[1][1] = 2, array2[1][2] = 3;
array2[2][0] = 0, array2[2][1] = 2, array2[2][2] = 3;
array2[3][0] = 0, array2[3][1] = 2, array2[3][2] = 3;
printUsingPointers( array2, 4, 3 );

The output function will remain same as before.

So the above one is a fully dynamic 2-D array where we can  have runtime control over the no. of rows and the no. of columns.

Pointer to Array

Pointers, of course, can be "pointed at" any type of data object, including arrays.Suppose we have a 2D array

int my_array[2][3];

We can declare a pointer to an array and make it point to the first flat array out of the two arrays (each of 3 integers).

int (*p)[3]; //pointer to an array of 3 integers declared.
p= &my_array[0][0]; //p points to the first row of the array my_array[0][0] to my_array[0][2]
p++; //Now p will point to the starting address of the second row now my_array[1][0] to my_array[1][2]

Pointer to array are extremely rare and I do not remember myself having used them at any time.

If you have difficulty in memorizing what notation is for pointer to array and array of pointer, try this :

int (*array)[4] : (, and ) operators have higher priority because it is on the left of the [,]. So, it is a POINTER to [4].
So, it means it is a pointer to array.

int *array[4] : [,] have higher priority than *, so, it is ARRAY of pointers.
It is not pointer, it is ARRAY.

Share this post



Add comment

Please refrain from using slang or abusive language in the comments.
To avoid waiting for your comment to be published after being reviewed, please log in as a registered user.


Security code
Refresh

Web Hosting