Showing posts with label Pointers. Show all posts
Showing posts with label Pointers. Show all posts

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.

Monday, December 17, 2018

Understanding Pointers - Part 1 - Basics

Pointer is variable type in C Programming language, that is used to store a memory address. Being able to store a memory address in a variable and then use it turns out be a great asset when you are doing low level programming.


Basics

A Pointer is a variable type that stores a memory address.

Note: When we say 'memory', we will assume we are talking about the RAM, where your program is loaded before execution.

On Memory and addresses.

Before going further, we need to get some minimal basic understanding of memory. This is crucial to successful understanding and use of pointers in C.

Let's say that you have a 4 GB RAM installed in your computer. There are (4 * 1000 * 1000 * 1000) bytes in your RAM. Now, each byte stores some information. To access information stored in a particular byte or to store some information in a that byte, the CPU needs to identify that particular byte somehow. And for that, we have a memory address. Each byte is assigned a unique number that is called its address, its memory address.

Normally, from a programming prespective, we just need to remember that memory addresses are a set of sequential numbers, starting at some number and ending at another. 

So, a pointer variable basically stores a number. A number representing a particular location in your computer memory.

Declaring a pointer

To declare a pointer variable in your code, you must first need to decide what kind of variable is going to be stored at that memory address.

For example, you could have an integer stored at that memory address. Or it could be a character. Or a float. etc.

So, to declare a pointer in your code, you must know what's going to be stored at that address in memory.

To start with, we will deal with integers.

Let's say I have a integer variable, var, and I have assigned it a value of 10. Like this:

int var = 10;

Now, var is stored somewhere in memory. To know the memory address where var is stored, we would declare a pointer variable that stores an address of an integer. Then we would assign the address of var to the pointer variable. Look at the code below:

int var = 10; // var declared and assigned a value of 10
int *ptr;    // a pointer variable 'ptr' declared
ptr = &var;   // Value of var's memory address stored in ptr

Let's understand, step by step, what we did here.
  • First, we declared an integer variable var and we assigned it a value of 10.
  • Then, we declared a pointer variable ptr using the * operator. Using this syntax tells the compiler that 'ptr' is a pointer variable, that will store memory address of an integer.
  • Then, we assigned the address of var to ptr, using & operator. & operator is used to access the location of an object in C.
Here's a complete program, to print the address of var, using a pointer variable.

#include <stdio.h>
int main()
{
    int var = 10;
    int *ptr;
    
    ptr = &var;
    
    printf("0x%x",ptr);
}


Here is the output that I get when I run this program:

0x48d51dac

Try running this program on your computer and you may get a completely different memory address printed. That's ok.

The exact memory address assigned to any variable in our program, depends on a whole lot of factors and is out of scope of this lesson. As long as you were able to get some memory address printed, we are on the right track.

Note, how in the above program, I printed the ptr using a %x in printf. There's no special reason behind doing this. It's just more of a habit to represent memory addresses as hexadecimals.
We could have printed the memory address as an integer too. But, in the rest of the lesson, I shall print memory addresses in hexadecimal format as a convention.

Practicing declaring pointers

Now, remember I said that to declare a pointer we must know what kind of variable is going to be stored in the memory address represented by the pointer. To declare a pointer that stores address of an integer, we declared it like this:

int *ptr;

If we read the above statement backwards, we shall get some idea of how to declare a pointer variable. Let's read this statement backwards like this:

Address stored in ptr points to 'int' or 'integer'. Meaning, if you will go to the address stored in ptr, you will find an integer stored there.

Let's try another declaration:

int *newptr;

Reading the above declaration backwards -> Address stored in newptr points to 'integer'.

Another one:
char *ptr;

Reading this backwards -> Address stored in ptr points to a 'character'.

Now, let's declare a pointer that stores address of a float number.

float *ptr; // Address stored in ptr points to a floating point.

Let's write a program to declare different kind of pointers:

#include <stdio.h>
int main()
{
    int a = 10;
    char b = 'A';
    float c = 3.14159;
    double d = 2.71828182;
    
    int * ptr1;        // address stored at ptr1 points to integer
    char * ptr2;       // address stored at ptr1 points to character
    float * ptr3;      // address stored at ptr1 points to float
    double * ptr4;     // address stored at ptr1 points to double
    
    ptr1 = &a;
    ptr2 = &b;
    ptr3 = &c;
    ptr4 = &d;
    
    printf("0x%x \n", ptr1);
    printf("0x%x \n", ptr2);
    printf("0x%x \n", ptr3);
    printf("0x%x \n", ptr4);

    return 0; 

}


Here is the output that I get, when I run the above program:

0x215c78f0
0x215c78ef
0x215c78f4
0x215c78f8

I would encourage you to type this program in your favorite editor and compile and run it on your machine. This will make you more comfortable with pointer notation and then we can starting looking ahead at how we use pointers in C programming.

Printing the value stored at a memory address

We have understood that a pointer stores a memory address. We can use the * operator, to print the value stored at the memory address in a pointer.

Let's see how to do this:

int * ptr;
int a = 10;
ptr = &a;

printf("%d \n", *ptr);

As we can see, the * operator is used to access the value stored at the memory address in a pointer.

Once we apply the * operator to a pointer, we get the value at that memory address and we can use it, just like we use any other value in our program. Like, assigning it to another variable.

int * ptr;
int a = 10;
ptr = &a;     // ptr now stores the address of a
int b = *ptr; // b now gets the value stored at memory address of a, which is 10

Here's the full program:

#include <stdio.h>
int main()
{
    int *ptr;
    int a,b;
    
    a = 10;
    ptr = &a;
    
    b = *ptr;
    
    printf("a=%d b=%d \n",a,b);

    return 0; 

}


Here's the output that I get for the above program:-

a=10 b=10


I would encourage you to try running each of the example programs shown in this lesson. That's it for this lesson.

In the next lesson, we shall see how pointers are used in C language to accomplish various tasks and also learn about pointer arithmatic.