Showing posts with label C language. Show all posts
Showing posts with label C language. Show all posts

Thursday, September 19, 2013

In fresher interview technical round, you may get confused with some object oriented "look a like" features of C language.




Sometimes C looks like to follow object oriented paradigm. Don’t get carried away withis idea. Current post focuses on this.

Star (*) Operator in C language acts both as pointer and multiplication. Then could we say that C supports Operator Overloading?

C language certainly does not obey operator overloading. In operator overloading, the function of the operator becomes different, but the arity of  the operator never changes. Here when * acts as a multiplier it is binary in nature, but when it acts as a pointer, it acts as a unary operator. Hence this example never follows the condition of operator overloading regarding the arity of the operator and so by citing this example, we cannot say that C supports operator overloading.

In C language, printf function takes different number and different nature of arguments in every time. Is it the example of Function Overloading?

No way! C does not support function overloading at all. The functions print() is capable of accepting different numbers of arguments due to an operator ellipsis which is represented as … (just three dots, nothing else!)
If we look at the prototype of printf, it would say something like

int printf(const char*, …);

The second parameter is the ellipsis and it uses four different predefined macros va_list, va_start, va_arg and va_end.  Ellipsis essentially says that there could be any number of arguments. This what printf() is backed with, certainly this is not a valid example of function overloading. Because in function overloading the numbers of arguments are specific, for example a function accepting two parameters can be made to accept three parameters (or so), but the instances, two or three are specific. Again in function overloading, the type of parameters can be changed, but once again the set is fixed like a function can act to accept a float and an int, but any data type with function overloading? Just forget it out.

So we are left with to demystify how printf() can accept any data type! This is done by parsing the first parameter of the printf that is const char* which is a string essentially. As we all know, this string contains different format specifiers like %d, %f etc, these specifiers peels out the knowledge that what is type of corresponding argument.

For example if we use

printf(“The results are = %d %f”, i_val, f_val);    

Then in the va_list macro, that is in the list of (v)ariable (a)rgument, there will be two arguments. By parsing the mandatory format string, the type of the first argument is computed as int and the second argument is fixed as float.

Now the question is where is this parsing algorithm present? This algorithm has been implanted within the definition of printf().

In the following post I will show how to use ellipsis operator with code examples.

Friday, September 13, 2013

Some Interview Questions for freshers on C language - Part 1


In this post I am giving my thoughts on some fundamental questions on C language which are expected to be asked in a standard interview session for freshers.


Q1. What are the two forms of #include?

There are two variants of #include. The one is #include<file> and the other one is #include”file”. In general the first form that is #include<file> is used to include system defined header files which are searched in the standard list of system directories. The second form i,e #include”file” is generally used to include user defined header files. These files are searched first in the current directory , if failed, then secondly in the standard list of system directories.
Both the forms of #include share a common property that is no escape sequence or commenting  styles are recognized within <file> or “file”. What I mean to say is that if I write #include <x/*y>, that means I want to include a file named x/*y.  Similarly writing #include<x\y\\z> is also perfect if the file x\y\\z is needed to be included.
   
Q2. What is the difference between Function and Subroutine?

The difference is indeed very thin and it depends on the context. In general Function is a piece of code with a name, inputs (arguments) and an output (return types). That is function should always return. Some programming languages are there which uniquely maps inputs to the corresponding outputs. But surely C is not such.  There is also a convention (but not a very strict one) that a function should not change any global variable. In C language, a function is always a realistic part of the code.
Subroutine is just a piece of any sorts of code with a definite entry and exit point. It should not return anything and a subroutine can always change global variables. These are generally used for conceptual purposes like in psudocodes.

Q3. What are register variables?

Registers are faster than memories to access. Hence when we declare a variable with a register key word, the compiler gets to know that the variable can be put to registers. Now whether the variables will be put into the register indeed or not, that depends on the compiler and the number and size of the registers for the corresponding hardware.
In general, the variables which are to be used with high frequencies (like loop variables) are the perfect choice for declaring as register, because the gain in speed would be considerable in those cases.
It is not allowed to access the address of the register variables as accessing the address of the register is illegal.
It is perfectly all right to declare a pointer as register because a register can always store the address of other variables if the size of the register permits that to do.

Q4. What is the difference between Scope and Lifetime?

Scope of a variable is defined as the block of code from where we can refer or access it. On the other hand the life time of a variable is defined as the time in between allocating memory for it and relinquishing the memory from it.  Let us have an example

void func1(void){
int x = 5;
// do other stuffs
}
void func2(void){
int y = 10;
func1();
//do other stuffs
}

In the above example scope of x is func1 and scope of y is func2. Now when we call func1 from func2, then inside func1, scope of y is ended but the life time of y still persists,  because the memory for y is still not relinquished.

Q5. What is your thoughts on the memory model of C with respect to the storage classes?

The entire memory (with respect to C program) can be divided into four logical segments. Data, Stack, Code and Heap.  The Code area contains all the instructions of the current program code. Data contains the Static and Extern variables. Auto variables are stored in Stack. The Heap area will be occupied by dynamically allocated variables. Lastly the Register variables will find its place CPU registers.  
  
 In the next post I will be expressing my thoughts on different questions which may be asked to judge the level  of efficiency of a fresher on the topic of Pointers 

Wednesday, August 8, 2012

An interesting discussion about malloc( ) and calloc( )


What are malloc( ) and calloc( )?

Simply putting they are the predefined functions in C language.
Malloc( ) and calloc( ) are two such functions which are used for more or less identical purpose and that is to allocate memories for any variable dynamically during execution time of the program.

Give me a brief of malloc( ).

So as I have said malloc is a function; malloc must have three valid components as all other functions do have. These are (a) function name (b) function arguments and (c) function return type, that is, malloc must have a signature or prototype. Now what is the prototype of malloc? It is like following:

(void*) malloc(unsigned int) [Note: The actual prototype is slightly different than this, but for the time being this simplification will work]

It shows that the function name is malloc itself, it expects an unsigned integer as argument and it returns a void pointer or generic pointer.  So let us discuss a bit about them.

As per the prototype, malloc expects an unsigned integer. To assimilate this, let us recall why should we use malloc? Malloc is used to allocate a chunk of memory at program run time dynamically. So we must let malloc know what the size of that chunk of memory is. Suppose we want malloc to allocate a chunk of memory where we can store 10 integers. In this case, we actually want malloc to allocate 20 bytes of memory (if we are running our program on windows). And we do it by supplying the size 20 as an argument. So the unsigned integer that is passed to malloc is actually the requirement of memory in bytes; and it is evident that the memory requirement cannot be negative any time, so the data type is unsigned.     

Now what that void pointer is doing at the beginning as return type? To understand this, we have to recall that a function gives a feedback to its caller through the return type. So after allocating the memory (I admit, you do not how) malloc has to return the base pointer, I,e, the address of the starting location of the memory chunk allocated. Though void pointer, malloc actually returns this base address.

I am sure you will scream out “why void?” Wait a minute. Answer me, who has written this malloc function? Is it you or someone else? Obviously it is not you, malloc function is written by someone else. Now the original developer of malloc had no idea for which purpose you would be using this malloc. Currently, you can use malloc to allocate memory for storing some integers, or some floats or some structures defined by you. There are so many options and those options are equally likely for you. You as a programmer currently know that this malloc is being used for storing some integers or whatever else, but the original programmer had no idea about that. So malloc returns void pointer or generic pointer, a special one which can point to any type of memory generically. So it is your responsibility to properly type cast this void pointer. If you are using it to store some integers, cast void* as int*, if you are using malloc to store some Node type structures, then cast it to Struct Node*. Got it?

One last point still exists. You must have seen malloc argument to contain sizeof(), right? Why it is so?
As I have mentioned that the memory requirement is informed through the argument, it is highly possible that the memory requirement may change as the OS changes. For example in one system you may require 20 bytes to store 10 integers, while it may be 40 bytes in other system or OS. So if I hardcode my memory requirement as 20 or 40 for any specific platform, it won’t suffice the scenarios generated by other systems. So to meet the portability issue, that may rise up later, we as a programmer should not deal with the memory requirement directly. We should inform the compiler that  that we need to store n number of elements only and let the compiler decide what the size of each such element is by using sizeof.

So we should call malloc with an argument (n * sizeof(int)) if we want to store n number of integers. By doing this, we are actually letting the C compiler to calculate the memory requirement (under the current OS) of one element and multiplying this with n, compiler can compute the exact memory requirement as per the current system.

As a good programmer you should never hardcode your memory requirement, it may end up in a serious problem if your program gets ported to any other OS.

Look at the following example for clear undestanding:

To store 15 characters, do like

char *pointerToCharArray;
int size = 15;
pointerToCharArray = (char*)malloc(size*sizeof(char));

To store n numbers of MyStructure type of structure, do like

struct MyStructure *pointerToMyStructureArray;
pointerToMyStructureArray = (struct MyStructure*)malloc(n*sizeof(struct MyStructure));

To store k numbers of integers, do like

int* point;
point = (int*)malloc(k*sizeof(int));

Once you are done with these, you can use your pointer (like pointerToCharArray or pointerToMyStructureArray or point as seen in the examples) like an array with indexing. That means now point[5] will give you the integer stored at 5th index of point or the sixth integer stored within the memory chunk, base address of which, is being pointed by a pointer point.

Huh! I finish it off here!    

So what is calloc then? How it is different from malloc?

Calloc is another function which, like malloc, is used for dynamic memory allocations.

Malloc if called to allocate a memory space that can store 10 integers (under windows),occupies the memory as a single chunk of 20 bytes, where calloc, if called for the same purpose, occupies 20 bytes, but not as a single chunk of memory, rather , it occupies 10 blocks of memory, each having 2 bytes (as it is under windows, as we have supposed). Hence calloc has the following prototype:

(void*) calloc(unsigned int, unsigned int)

The first unsigned int is for number of elements that you want to store and the second unsigned int is for memory allocation needed for storing a single element.

This is why calloc can occupy the memory space with multiple blocks, each of equal size. The void* is doing the same thing as that of malloc

So look at the following example for clear understanding:

To store 15 characters, do like

char *pointerToCharArray;
int size = 15;
pointerToCharArray = (char*)calloc(size, sizeof(char));

To store n numbers of MyStructure type of structure, do like

struct MyStructure *pointerToMyStructureArray;
pointerToMyStructureArray = (struct MyStructure*)calloc(n, sizeof(struct MyStructure));

To store k numbers of integers, do like

int* point;
point = (int*)calloc(k, sizeof(int));

So the syntactical difference is malloc takes one argument, while calloc takes two. But you need to have an idea why it is so. I think the above discussion tells you that.

Another point of difference is like following:
Malloc allocates the memory chunk and initializes the memory with garbage values, whereas calloc allocates the multiple block of memory chunks and initializes those with 0s (zeros)

So we come to an end of this discussion. I am open to clear your doubts if any.