Sunday, May 29, 2016

Pointers - I


A pointer is nothing but a variable , but the speciality of this variable is that it stores the address location of another variable. So, it means that we can have a normal variable which is located at some particular address in the memory, and then we can also have another variable which can actually let us know the address where the previous variable is stored.

Let us understand it in a more clear way with the help of an example:-

Here, we have defined 5 variables in total.4 of them are normal integer variables holding some values and the 5th one is a pointer to an integer.

<< When you declare a pointer as int *p, you read it as p is a pointer to an integer.>>

Then, before every printf() statement, we are assigning the value of p to each and every integer variable. Let's see how the output follows :-


What we observe here is that p is pointing to a different location each and every time.This is so because we are making the pointer variable *p point to a different variable each and every time.

The above code and output have a lot to say. Let us discuss them one by one.



  1. The memory address values are in Hexadecimal format. It's because we have used the format specifier as %p .
  2. The difference between any 2 consecutive address values is 4 Bytes. What does this mean? Is it because the integer size is 4 bytes?? 

    --Absolutely right. Each integer value occupies 4 Bytes of space in memory, hence the next variable's address is 4 Bytes after it.---


  3. Size of a pointer to an integer is 4 Bytes.
  4. What if the variables used were char type, which are only 1 Bytes wide?
    --Let's see it.

                              And then the output is:-


Is everything alright?? The difference between address locations of 2 consecutive variables is only 1 Byte, as expected. But wait !!!

Why is the size of p still 4??

Well, The answer is the size of a pointer is always fixed for a particular architecture, no matter whether that is a pointer to an integer , a pointer to a character ,a pointer to a float variable or a pointer to a double variable.

Since the above code has been executed on an x86-based 32-bit machine, the size of a pointer is 4 Bytes.
On a 64-bit machine, the size of a pointer will be 8 Bytes. Similarly, on a 16-bit machine, the size of a pointer will be 2 Bytes.

<<However, the above statement is not strictly true, and a little bit of Googling will probably make you aware of the fact.>>

 
Referencing and dereferencing of a pointer -

.
.
.
void func()
{
             int a=10,*p,b;
             p=&a; //p is referencing a with the help of & operator

          //Since 'p' has already referenced 'a', we can access the value stored at the address location pointed to by 'p' by dereferencing it.
            printf (“ value at the address pointed to by p is \n”,*p); //Here, p is being dereferenced with the //help of * operator
}
.
.
And then the output of the printf() statement will show us the value 10, which we got by dereferencing the pointer 'p'.

<< & is known as the reference operator, and is used to access the “address of” the variable it is being used with.
* is known as the dereference operator , and is used to access the “value pointed by” the pointer it is being used with.>>


We can actually alter the value of a variable by altering the value while dereferencing the pointer.
For example, in the above piece of code, if we do the following :-
.
.
*p=*p+5;
printf(“ value of a is %d\n”,a); //a becomes 15
.
.
.
printf() will display the output of 'a' as 15, because the value has been changed by dereferencing the pointer to the variable 'a'.


What happens if we try to dereference some pointer which has just been declared but not initialized?

What happens if we try to dereference some pointer which has been initialized to be NULL?

Let's see both these scenarios with a small piece of code.


Here, 'p' is a pointer which is un-initialized,which means that this pointer may point to any random location containing some garbage value or it may be an invalid location at all.

'q' is a pointer initialized with NULL value. This surely contains no valid location since it has been initialized as NULL.


As seen in the output, p is pointing to some unknown location containing some unknown value.

q is not pointing to any location. So, it's logically an act of stupidity to dereference this pointer ( though we can do it here and we usually keep doing it throughout life by mistake ;) ).
GCC throws the exception as “Segmentation fault” in this case.

In case of dereferencing p, GCC may throw “Segmentation fault” error too. It just depends on what value is present on that randomly assigned location. If nothing is present, then “Segmentation fault” will definitely appear .

One more thing that may seem surprising to some people is that on executing the code for subsequent number of times, the memory address location changes. Why does this happen?

For those who have this query , they may tend to understand that the address is that of the Physical memory, then why should it change again and again?? Shouldn't it remain static?

The answer is that this address is not the Physical address(i.e., the RAM address), this is rather known as Virtual address. Each time you execute the binary file, you are actually starting a process, and each process has its own virtual address space which is translated from the Physical address space with the help of an MMU (memory management unit) in an OS-based system.
So, for every execution of the same code, the virtual address changes because you actually start a new process each time.

We will discuss memory management along with the address translation from Physical to Virtual in more detail in the OS section.

No comments:

Post a Comment