Saturday, August 6, 2016

Function Pointers

Pre-requisites for going ahead with this tutorial :

  • Pointers Basics (Pointer to Int,Char)
  • Pointers and Arrays
     

Since we have already dealt with pointers well enough and seen their usage with primitive data types such as int,char and also with arrays, In this section , we will move one more step further and see the usage of pointers with functions.

Let us revisit it very briefly.

int value;       // value is a variable of an integer type

int *value;     // * value is a variable of an integer type or value is a pointer to an integer

This is how we read a pointer variable. The same holds good with a function pointer too.

We all know the basic prototype of a function declaration.

                      int operation(int , int);

The statement above is just a normal prototype of a function which accepts 2 integer values as their arguments and returns an integer.

                     int (*operation)(int,int);

The above statement can be read as- 


  • operation is a pointer to a function taking 2 integer arguments and returning an integer, or in simple words- operation is a function pointer with 2 integer arguments.

As a pointer to an integer stores the address of some other variable, similarly pointer to a function stores the address of some other function, or more precisely , the base address of some other function.


So, one question that may arise is that why do we need a function pointer? What is the use of it?

By now , you must have got the understanding that knowing the address of a variable does a lot of help in C programming and we can't just by-pass or ignore them. So is the function pointer. Knowing the address of a function helps a lot in C programming and saves a lot of efforts.

How?


It helps us in getting the flexibility while using functions. It makes our program look more short and precise and eliminates the overhead of calling the multiple functions multiple number of times with the same set of parameters.

Let us first see a basic example of the usage of function pointer.

Here ,operation is a pointer to a function which takes 2 integer arguments.

 
The function which it points to is bigger(int,int). As in case of a normal variable pointer where we can access the contents of a variable by dereferencing it, the same applies here, and the statement above the printf() statement shows how to dereference a function pointer. However, dereferencing can also be done by simply calling the function pointer without any *(asterisk) operator as below.
                                  int large= operation(2,3)

Output :


 
The above example is an extremely simple one which explains the basic usage of a function pointer. However, the same function pointer can be used to point to various other functions as well. 

Let's see one more example :

 
The function pointer stores the address of different functions depending upon the input value provided by the user. After the choice is made as to which function the function pointer is going to point to, we can dereference the function pointer with the same set of arguments.

Output :

 
Function Pointer as an argument to another function- We could have even passed the function pointer as one of the parameters into another function. Let's take our first example and modify it by passing the function pointer as an argument into a third function.

Instead of directly dereferencing the function pointer and storing the output in a variable, we are passing the function pointer into a third function and then storing the return value of this function in a variable.

 

Here , the function perform() accepts a function pointer as an argument and returns the value obtained as a result of the functionality of the (*operation)(int,int) function pointer which points to the address of the function bigger, and in turn returns the larger of the two passed values.

Output :

 
We can make use of typedef to make the above stuff look a little simpler. At the same time, usage of typedef may also seem to be confusing at the first sight. So, you have to get used to it.

Remember that by using typedef, you are eliminating the need to put in the data type and return type while passing the function pointer as an argument

Let's modify the above example :


Keep in mind the following thing to not get confused with typedef statement in the above scenario-

int (*operation)(int,int); // This is how you declare function pointer.

To make use of typedef , you don't need to get too much of trouble . You can just do the following:-

typedef int (*oper)(int,int); //The words in bold are all that you need to take care of.
 


After this , all you have to do is the following to declare a function pointer:-

oper operation;   //operation is analogous to a variable and oper is analogous to a data type for that variable


It's as simple as declaring a variable. Now , to point to any function, you just need to do that in the way you assign an address to a pointer variable.

operation=bigger; // It looks as if you are assigning the value of bigger to operation
operation=&bigger; // This is also the same, and it looks as if you are assigning the base address of bigger to the pointer variable operation

<<<Function pointer gives you so much of flexibility that at places, you can just include & or eliminate it, or use * or eliminate it.>>>

Output :

Such an application of a function pointer , of passing it as an argument, can be found in the standard library function qsort(3), which is used to sort an array.

Returning a function pointer from another function - Function pointers can also be returned from another function just like a normal variable is returned.
This looks even more complicated,but can again be simplified by making use of typedef.
We will take a look at how function pointers can be returned from another function :
The function pointer operation() points to the function bigger() or sum() depending on the parameter num in the perform() function. After pointing to one of the functions, this function pointer is returned from function perform().

Output :


So, This is all I have to offer from the section on Function Pointers. You are encouraged to explore more on this topic by looking at various examples which really help in code optimization and increase efficiency .

In case of any doubt or if you need any clarification on any of the topics, get in touch by posting a comment.




Pointers - III - (Arithmetic Operations on Pointers)


Arithmetic operations on Pointers- Let us see how the pointers behave on performing arithmetic operations such as addition and subtraction on them.
We will take an example where we add 10 to a pointer, and then subtract 10 from the same.



Let us see the output.

 
As we can see , on adding 10 to ptr, ptr has gone 40 bytes away from its previous location.

Since ptr is a pointer to an int and int stores 4 Bytes, adding 10 adds to a total of 10*4= 40 Bytes. Same with subtraction.

For a pointer to a char, same rule holds good and adding/subtracting 10 will render to a total addition/subtraction of 10*1=10 Bytes to/from the address location.

What about an arithmetic operation on a void * pointer?
The behaviour is same as a pointer to a char. However, such an operation is not recommended as per the C standards. Explore it for more info.

++,-- operations on pointers- You must have been familiar with the usage of ++(increment) and –(decrement) operations by now in both pre- and post- form with normal variables.

Now let us perform these operations on pointers and see the outputs. Remember that the rules of operators' precedence will apply here.


Various such operations are possible :-
Consider 'ptr' as a pointer , following are some operations possible on ptr.
  • *ptr++
  • *(ptr++)
  • (*ptr)++
  • ++(*ptr)
  • ++*ptr
  • *++ptr
  • *(++ptr)

We will demonstrate this with the help of a simple and short program :

Let us see the output :


Keeping in place various rules of operators' precedence and post & pre increment, the above output seems quite logical.
*ptr++ and *(ptr++) are the same, because evaluation is simply done right-to-left in when no parenthesis is used. But , when a parenthesis is used as in (*ptr)++,and ++(*ptr), the parenthesis is evaluated first, which is again as per the operators' precedence rule.
++*ptr , *++ptr and *(++ptr) show output as expected. Last two expressions are the same.

Please note in the above snapshot that after the expression, *++ptr, z becomes 10. This is not because of linear increment of z from the value of 5 onwards. This 10 is the value stored in y, whose address is now being pointed to by ptr as a result of total increment by 4 Bytes so far.

This is all from the section of Arithmetic Operations on Pointers. Publish comments and let me know if you have any doubt or need any clarification on any of the topics on this Blog.


Sunday, May 29, 2016

Pointers - II


We have discussed pointers pointing to different data types. Now Let us deal with void pointers.

Void pointers- Void pointers are those pointers which can store memory address values for variables of all the data types. In other words, if you declare a void pointer, then you can point it to the address of a character variable, an integer variable, a float variable or a user-defined data type variable such as struct .

Let us understand this with an example :-

 
In the above code, void pointer 'p' is made to point to each and every variable of different data types. We will now see how easily it just gives us the address location of each and every variable without throwing any “incompatible pointer type” warning , which normally appears when pointer of some data type points to address location of a variable of a different data type. This warning will never appear when working with a void pointer.



So far, so good. Now let us deal with a few more things. When we can obtain the address location of a particular variable, then we should also be able to access the value on that location.

In short, When we can reference a void pointer, then we should be able to dereference it too. Can't we?? Ok, let's see. We will take a short program and see whether it is possible or not.


Let us try compiling it .


As seen in the snapshot above, it throws error. Then, What's the solution to it? How to dereference the pointer to read the value at that location?

This can be done by typecasting the pointer to the data type which this pointer is pointing to.
In the above program, we can access the value of that location by typecasting 'p' to 'char'.
 
In the above program, the pointer 'p' has been typecast to a char pointer.

Syntax for typecasting a pointer is – *((data_type*) pointer)

Let us try compiling it and checking the value .

 
So, the program builds successfully and when the binary file is executed, we get the correct value at the location pointed by 'p'.
In the above code, we can also typecast 'p' to int pointer and get the correct expected result by dereferencing. It is because 'int' stores 4 Bytes and we are pointing to a char variable which is only 1 Byte.


Let us see the output.


 
No difference in the output.


But it's not the other way round. Let us understand it with the following example :-

We will store a 32-bit hexadecimal value in an 'int' variable and then try to dereference it with a pointer typecast to 'char'.


 
Let us observe the output.

 
Some of you might have been able to guess it right as to why we didn't get the desired output.

It's simply because 'char' only can only store upto 1 byte.

Since our value was 0xabcd4030 and 'char' only stores 1 Byte,Why did we get '30' as the value and why not 'ab'?

The answer to this question lies in a concept called endianness, which varies from architecture to architecture. This machine is a Little Endian. So we got '30' as the output. If you build and execute the same program on a machine with Big Endian format, you will get 'ab' as the output.

We will discuss endianness in detail in a later section.

<<<ptr1-ptr2, if both int, will give the number of locations(and not Bytes) both the pointers are apart from each other based on the data type.>>>
This will be illustrated more in a later section.



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.

Sunday, May 8, 2016

Storage Classes in C


When a variable is declared in C, it is assigned a storage class which tells about the scope and the lifetime of that variable.

Like variables, functions in C have a storage class and scope. All functions in C are external by default and are accessible to all source files. However, functions may also be declared to be of static class.

There are 4 storage classes in C-

  1. Auto
  2. Register
  3. Static
  4. Extern


1. Auto – When a local variable is declared, it is assigned “Auto” storage class by default.The scope of this variable is within the function where it has been declared. The lifetime of such a variable is from the beginning of the function declaration/definition till the end of the function. This variable gets allocated to the Stack frame of the function in which it has been defined.


void func1()

{

.

.

.

int var1; // by default, it is assigned Auto storage class

auto int var2;

.

.

}

Both the variables in the above function reside in the Auto storage class.

2.Register- When the definition of a variable is prefixed with the keyword “register”, it is assigned to Register storage class. Such a variable resides in the CPU Register , and not in the main memory. Such variables which reside in the Register can be fetched/accessed very fast. Scope,Lifetime and default initialization are same as that in Auto.



Void func2()
 {
     .
     .
    register int var3; //var3 is stored in Register storage class
     . 
} 

Variables which are frequently used are put into register. Sometimes, Compiler plays the game of optimization and puts those variables in register which are being frequently used/accessed in a program. Sometimes, such an option is undesirable when this variable is supposed to be updated very frequently, viz., while reading the value of some sensor in an embedded system.This sensor value needs to be updated every time. So we can't risk of letting such an optimization by the compiler go unnoticed. So in such a case, the Programmer must make sure that such a variable stays in the main memory (RAM) rather than the Register.   “volatile” keyword is used for the same.

void func2()
 

{

       .

       .

       volatile int var3; //var3 will be strictly allocated in RAM

       .

}


3.Static- When a Global variable is declared , it gets assigned to Static storage class by default. A local variable can also be made Static by prefixing its declaration with “static” keyword. Static variables are initialized only once at run time and they are not again re- initialized when the function(where static variable has been declared) is called.Once initialized, they stay in existence till the end of the program. Let us see it with the following examples ,one without static variable and one with static variable.



 

The output is as follows:-

 

we get the output as 6 all the three times when func() is called.

Now , let's make this variable 'y' as static.

 


'y' has been declared as static which means that this will go to the Static storage class, and initialization of the variable will happen only once , and not all the time whenever func() is called. Hence , we get the output as follows because y is initialized to 5 only once, and in subsequent calls to func(), 'y' retains its previous value.

 


 Returning address of a local variable from a function :-

In a function returning a pointer, we cannot return the address of a local variable . If we do so, the variable , whose address is being returned, will no longer be valid when the function exits. This is because , by default a local variable is assigned Auto storage class, and the scope and lifetime of such a variable is within the function and as long as the function is running.

So , How to overcome this issue?

It's simple. We can force that local variable to not get assigned in Auto storage class. We can assign them to Static storage class by prefixing “static” with the declaration of that variable.

The scope of a local static variable is inside the function and the scope of the global static variable is throughout the program.


4. Extern- extern is used to give a reference of a global variable which has been defined in a separate file and is visible to all the program files. When the declaration of a variable is preceded with “extern”, the definition of that variable can't happen in that same file because it points to the presence of definition in a separate file.

When we have multiple files and we define a global variable or function which will be used in other files also, then “extern” will be used in another file to give reference of defined variable or function. In other words, “extern” is used to declare a global variable or function in another files.



Main.c                      odd_even.c



int a=20;                       extern int a; // extern storage class

                                      //int a; //goes to extern by default
void main()                    void odd_even()
{                                    {
odd_even();                       if (a%2==0)
}                                              printf(“Even number\n”);
                                         else
                                                printf(“Odd number\n”);
                                     }
Here usage of “extern” means that the variable 'a' has been defined in some other file.

The two files need to be compiled as follows:-

gcc main.c odd_even.c -o a.out

Scope of an “extern” variable lies across the programs.

Global uninitialized variables go to extern storage class by default.By default, they have static duration with external linkage.