Monday, February 4, 2019

Understanding Pointers - Part 2 - Usage and Pointer Arithmatic

In Part 1 of this lesson, we explored the definition of pointers. We also saw how to declare pointers of various types and how to use * operator to print the values stored at an address assigned to a pointer.

Having made ourselves familiar with basic pointer syntax, we can now go ahead and start looking into how pointers are used in day to day programming and while doing this we shall also learn another key concept related to pointers called Pointer Arithmatic.

We shall do this by going through a series of example programs. I would encourage you to type each example program in your favorite editor and compile and run the program.

This will make you more and more comfortable with pointers as we go forward.

Have a look at the program below:-

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int *ptr = NULL;
    
    ptr = (int *) malloc ( sizeof(int) * 10 );
    
    if ( NULL == ptr )
    {
        printf("Unable to allocate memory, exiting\n");
        exit(EXIT_FAILURE);
    }
    
    printf("Starting Address of allocated memory space => 0x%x\n",ptr);
    
    ptr = ptr + 1;
    
    printf("Address after jumping one ahead => 0x%x\n",ptr);
    
    ptr = ptr - 1;
    
    printf("Address after jumping one back => 0x%x\n",ptr);
    
    free(ptr);
    
    exit(EXIT_SUCCESS);
}

In the above program, we have done a lot of new things that you didn't encounter in the first lesson. Let's go through this program line by line and understand what's happening.

  1. We declare a integer pointer 'ptr' and assign it a value of NULL. In the first lesson we didn't assign any of our pointers to NULL value to start with. But we should have as it is considered a good practice.
  2. Then we use the dynamic memory allocation function, malloc(), to allocate a memory space of size of 10 integers. If malloc() is successful, it shall return us a pointer which shall be stored in the pointer variable 'ptr'. As expected, the value in ptr is a memory address. This memory address is the starting address of the memory space allocated to us. The total length of this allocated space is the size of 10 integers, which on most machines is going to be 40 bytes - 4 bytes for each integer.
  3. The next block of code, we do some error handling. We check if malloc() was successful in allocating memory or not. If malloc() fails for any reason, it shall return a NULL value. It is always recommended that we check the return value of malloc() to see if we have really been allocated any memory or not. If malloc() does return a NULL, we exit the program after printing an error message.
  4. Next we print the value of the ptr. This shall be the starting address of the block of memory allocated to us.
  5. Next, we add 1 to ptr. This is the interesting part and our first leap into the world of pointer arithmatic. Normally if we add 1 to an integer variable, we shall get a value that is incremented by one. e.g. if I have an integer that stores a value 2 and I add 1 to it, I will get the value 3. But with pointers something different happens. In our case, when we increment 'ptr' by one, it jumps to the next integer address in the memory space. So after executing this line of code, ptr shall now be storing the address taken up by the next integer in our allocated memory. This address shall be 4 more in value than the starting address, because as we have already discussed, an integer takes up 4 bytes of space. 
  6. Next we print ptr. This, as we understood, in the last point, shall be the address of next integer in the allocated memory. It's value shall be 4 more than the starting address of allocated memory.
  7. Next we subtract 1 from ptr. We saw that when we added 1 to ptr, it jumped one integer ahead. Similarliy, if we subtract 1 from ptr, it should jump 1 integer back. That's what happens. ptr will jump back 1 integer and and shall now again be pointing to the starting address of allocated memory, where it was pointing originally.
  8. Next we print the value of the ptr.
  9. Next, we call the free() function to release the allocated memory. This is again a very important step. You should release any dynamically allocated memory as soon as you have no more use for it.
  10. We exit the program.
Here is the output that I get when I run the above program:

Starting Address of allocated memory space => 0xa32a98

Address after jumping one ahead => 0xa32a9c

Address after jumping one back => 0xa32a98

Note, than after jumping the pointer one step ahead, we get an address that has a value 4 greater than the starting address. This indicates that an integer is allocated 4 bytes on my system.

In the last program, we dynamically allocated some memory from heap and showcased pointer increment and decrement operations. We can also use pointer arithmatic operations on memory declared on stack or some global or static memory. And this is actually how pointer arithmatic is most commonly used.

Let's check out another program where we use memory allocated on stack.

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int arr[5] = {1,2,3,4,5};
    int *ptr = NULL;

    ptr = &arr[0];
    printf("Value stored at Address [0x%x] => %d \n", ptr, *ptr);

    ptr++;

    printf("Value stored at Address [0x%x] => %d \n", ptr, *ptr);


    ptr++;

    printf("Value stored at Address [0x%x] => %d \n", ptr, *ptr);


    ptr++;

    printf("Value stored at Address [0x%x] => %d \n", ptr, *ptr);


    exit(EXIT_SUCCESS);
}

Here is the output that I get when I run the above program:-
Value stored at Address [0x61ff18] => 1
Value stored at Address [0x61ff1c] => 2
Value stored at Address [0x61ff20] => 3
Value stored at Address [0x61ff24] => 4

In the above program, we declare an array of 5 integers. We take a pointer to an integer at point it to the address of first element of the array.

Then, we keep incrementing the pointer by one and printing the address stored in the pointer and value stored at that address.

I hope you have got a little sense of how we can use pointers in our programs.

We shall elaborate on the uses of Pointer arithmatic more in the next part of this lesson.

No comments:

Post a Comment