C interview Questions

Q.1) what do we mean by data type in C?

Data types are the keywords, which are used for assigning a type to a variable or a function that is declaring a variable or a function of a specific type. The type of a variable determines:

  • how much space it occupies in memory.
  • its representation inside a memory.
  • range of values that can be stored in memory.

Data type is used to define a variable before its use. For details please refer data types in C.

Q.2) what are different data types in C?

Data types in c language can be broadly classified as:

  1. Primitive Data Types             integer, float, double, char, void
  2. User Defined Data Types    :  enum, structure, union, array, pointers

Q.3) what are structures?

Structure is a user defined data type that is aggregated data type which is used to store data of different types (Heterogeneous).

Example:

Below is the structure employee declared with two data members’ employee_id of integer type and name which is of character type.

  struct employee    {  
     int employee_id;    
   char name;
   };  
  • To access the data members or variables declared in the structure we create an object to the structure

          struct employee emp;
To access employee_id we write:             emp.employee_id;

  • And if its pointer then         

             struct employee *emp
To access we write:                                   emp->employee_id;

Note:

  • In case of structure the variables are declared not defined that is memory is not allocated for the members of the structures.
  • Memory are allocated once we create the object for the structure.
  • For more details please refer : structure in C

Q.4) what is Union?

A union is also user defined aggregated data type available in C that enables us to store different data in the same memory location. We can define a union with many members, but only one member can contain a value at any given time. Unions provide an efficient way of using the same memory location for multi-purpose.

They are accessed in same way as that of structure but only one member can be accessed at a time.

Union use scenario:

Well, there are certain scenarios where we want to use only one of the members at a time. So in that case, using a union is a wiser option rather than using a structure. This will save us memory.

Unions are particularly useful in embedded programming or in situations where direct access to the hardware/memory is needed.

Unions allow data members which are mutually exclusive to share the same memory. This is quite important when memory is scarcer, such as in embedded systems.

Few of the examples are:

  • In case of IP version, it can either be IPV4 or IPV6, so we can use unions to save memory.
  • The Gender can either be male or female.

Another usefulness of union is to provide the user with API which allows access of same data in multiple ways.

union ipv4addr {
  unsigned int address;
  char      octets[4];
};  

So one can access the whole 32 bits address or just an octet.

We have a union inside the structure to know which member of the union is active.

For more details please refer: Union in C

Q.5) what is difference between structure and Union?

The basic difference between structure and Union are as follows:

                            Structure                                  Union
The size of the structure is sum of sizes of all the members of it.The size of Union is the size of the largest member of it.
All the members will have its own memory allocated.All the members will share the same memory area.
Individual members can be accessed at once.Only one member can be accessed at a time.
Altering the value of a member will not affect other members of the structure.  Altering the value of any one of the member will alter other member values.  

Q.6) what is structure padding?

  • Structure padding means adding extra bytes to the member of the structure.
  • The main reason for doing such alignment (placing the member at a particular location/address) is to optimize the performance of the processor in terms of reading and writing at a particular memory location.
  • Most modern processors will work efficiently when data is stored at an address that is multiple of its size.
  • For example, in the case of a 32-bit processor which reads 32 bits at a time, it will work efficiently when the data is stored at an address that is multiple of 4.
  • In general, the size of the structure is multiple of its largest members.
  • It’s always good practice to declare fields in structure either ascending or descending order of their size to minimize the waste of memory.
  • Structure padding can be disabled by #pragma pack(1)
  • Where n is the alignment bytes and valid values are 1, 2, 4, 8 and the default value is 8.

Example:


struct abc
{
   char a;
   char b;
   int c;
}obj;

Thus, the total size of the structure is char a(1 byte) + char b(1 byte) + 2 bytes(padding) + int c (4 bytes) = 8 bytes.

Memory alignment (without structural padding)

untitled image

Since it is a 32-bit machine hence in one cycle 4 bytes will read. So to access the integer it needs two cycles.

Memory alignment (with structural padding)

untitled image

Thus, the total size of the structure is char a(1 byte) + char b(1 byte) + 2 bytes(padding) + int c (4 bytes) = 8 bytes.

Thus, to access integer c, just one cycle is needed, increasing the optimization in accessing the member’s structure.

This is the significance of structure padding.

For more details please refer: structure padding in C

Q.7) what is need of bit field in C?

The main use of bit field in C is memory saving.

Example:

In case of structure we have two members and each of them is a Boolean flag that is it just requires two bit. But in normal scenario if we declare like below

struct {  
unsigned int width_flag;
  unsigned int height_flag;
} status;

Then the memory allocated is 8 bytes but we only need two bits, in that case we can use bit filed in structures.

struct {  
unsigned int width_flag : 1;
  unsigned int height_flag: 1; }
status;

Thus we can say we use bit field in structure for memory saving. Like in the above case 4 bytes will be used after padding. Thus 4 bytes of memory is saved.

For more details please refer: Bit field in C

Q.8) what is difference between call by value and call by address?

Call-by-value:

In this method, a new copy of the variable is created at the called function that is at formal parameters. Since in this case a new copy of the variable is being created, thus any changes made inside the called function is not reflected outside the functions that is at the caller function.

It copies the actual value of the argument into the formal parameters of the function.

Example:

#include <stdio.h>

void fun(int val) ==> called function with formal parameter "val"
{
  val++;
  printf("\n The value inside the called function is %d\n",val );
}

int main() ==> caller function
{
  int a = 10;
  printf("\n The value of 'a' before is %d\n",a );
  fun(a); ==> actual parameter "a"
  printf("\n The value of 'a' after is %d\n",a );
  return 0;
}

Output:


The value of 'a' before is 10

The value inside the called function is 11

The value of 'a' after is 10

We can see above that value change is not reflected outside the called function(main()).

Call-by-address:

In this method, the address of the actual argument is copied to the formal argument of the function. The address is used to access the memory locations of the actual parameters in the called function.

Since the address of the actual argument is used in the called function, thus any changes made inside the called function are reflected even in the caller function.

In this the formal parameter must be pointer variable

Example:

#include <stdio.h>

void call_by_reference (int *number) ==>called function 
{
   printf("\n Value before adding is: %d", *number);
   *number = *number + 5;
   printf("\n Value after addition is: %d", *number);
}

int main() ==>caller function
{
  int num = 10;
  printf("\n Value before calling the function is: %d", num);
  call_by_reference (&num);
  printf("\n Value after calling the function is: %d\n", num);
  return 0;
}

Output:

Value before calling the function is: 10
Value before adding is: 10
Value after addition is: 15
Value after calling the function is: 15

In the above example, we can see that the value of the variable “num” is modified in the called function and the same value is reflected outside in the called function as both the actual and formal parameters refers to the same address.

Passing a structure will put the entire structure onto the stack but if we use pass by address that is if we pass a pointer to structure then only 4 bytes of memory is consumed. Thus with pass-by-address, we tend to save memory.

It is one of the application of pointers.

For more details please refer: call-by-value and call-by-address

Q.9) When to use call-by-value and call-by-address()?

The selection of the argument passing depends on the situation.

  • If the data object is small, such as a built-in data type or a particular field of an array or of a structure then pass it by call by value.
  • If the data object is an array, call by address should be choice.
  • If the data object is a good-sized structure, call by address should be choice to save the time and space needed to copy a structure.
  • If a variable is not set at the caller function and wish to update the variable at the called function and read the same value in caller function, then call by reference is the only choice.

For details please refer: use case and example for call-by-value and call-by-address

Q.10) What is pointer?

A Pointer is a special variable that stores the address of another variable rather than storing the values. Thus, with the help of pointers, any variable can be accessed by its address.

Accessing a variable by its address is faster than accessing it by its name as the compiler is to first get the address of that variable and in the second cycle need to access that address.

Pointers are used to access memory and manipulate the address.

What does address of a memory location mean?

Whenever a variable is defined in C language, memory is allocated to that variable in which the value will be stored. The address can be checked with the ampersand(&) symbol.

If var is the name of the variable, its address can be fetched with &var.

Example:

#include <stdio.h>

int main ()
{
  int var = 5;
  printf ("\n The memory address of the variable var is: %x\n", &var);
  return 0;
}

Output:
The address of the variable var is: 15e490ac

For more detail, please refer: pointer and its declaration, initialization and dereferencing

Q.11) What is double pointer?

Pointer is a variable that is used to store the address of other variables of a similar datatype. In the C programming language, there is a provision to store the address of the pointer variable in another variable. This variable is known as a pointer to a pointer variable and is also known as a double pointer.

#include <stdio.h>

int main ()
{
   int var = 10;
   int *ptr = &var;
   
   int **double_ptr = &ptr;
   
   printf ("\n The address of the variable var is: %p\n", &var);
   printf ("\n The address stored by ptr is: %p\n", ptr);
   printf ("\n The address of ptr itself is: %p\n", &ptr);
   printf ("\n The value stored by ptr is: %d\n", *ptr);
   
   printf ("\n The address stored by double_ptr is: %p\n", double_ptr);
   printf ("\n The value stored by double_ptr is: %d\n", **double_ptr);
   return 0;
}

Output:

 The address of the variable var is: 0x7ffdf5da6e4c

 The address stored by ptr is: 0x7ffdf5da6e4c
 The address of ptr itself is: 0x7ffdf5da6e50

 The value stored by ptr is: 10

 The address stored by double_ptr is: 0x7ffdf5da6e50

 The value stored by double_ptr is: 10

Pictorial Representation:

  • Pointer variable “ptr” stores the address of the variable “var” which is “x”.
  • *ptr gives us the value stored at the address “x”.
  • Similarly, now the pointer to pointer variable “double_ptr” stores the address of pointer variable “ptr” and the value at the address of “ptr” is the address of variable “var”. Thus *ptr prints the address of “var”.
  • Thus *double_ptr means the address of variable “var”. Hence, the value at the address *double_ptr is 10. Thus **double_ptr prints 10.

Q.12) what is dangling pointer?

A dangling pointer is a pointer which points to the nonexistent memory location that is memory that is deallocated(invalid memory location).

It refers to something on the stack but nothing on the heap.

Example:

#include <stdio.h>              

int *fun()                      
{                                 
  int x = 5;                       
  x++;                           
  return &x;                      
}                                
                                 
int main()
{
   int * ret =fun();
   printf("\n Value is %d",*ret);
   return 0;
}

Output:

Some compilers may give the output as 6 while some may throw a warning:

main.c:7:10: warning: function returns address of local variable [-Wreturn-local-addr]
   return &x;
          ^~

Even though the value is 6 and there is no error, in the future if some other entity gets the same address and so the value of ret will be overwritten. Thus there will be inconsistency and loss of data.

This problem can be solved by making variable ‘x’ as static.

Q.13) what is memory Leak?

It means the memory which is allocated is not being freed that is something on heap but nothing on stack.

#include <stdio.h>

int main()
{
  char *ptr = malloc(8);
  ptr = "techaccess";
  
  return 0;
}

Once the main() reaches the end of the block, the variable on the stack that is ‘ptr’ goes out of scope but the memory allocated with malloc() is not freed, leading to memory wastage.

Q.14) Explain different storage class in C?

In C language, each variable has a storage class which decides:

  • scope
  • visibility and lifetime of that variable.
  • It also states the initialization value.

In C we have four different storage classes as mentioned below:

  • auto
  • static
  • extern
  • register

auto:

  • Scope: They have scope within the function block in which they are defined.
  • Lifetime: Variables defined with auto storage class have a lifetime until the end of the function/method block in which they are defined.
  • Default initial value: They are initialized to garbage value by default by the compiler.
  • The default storage class for any local variable is auto.
  • These variables are allocated automatically at run time.
  • They are automatically freed upon exiting the block.
  • They are preceded by keyword auto. Example: auto int i
  • They are stored in the stack section of memory.

Static:

  • Scope: They have scope within the function block in which they are defined.
  • Lifetime: Until the whole program does not finish execution.
  • Default initial value: They are initialized to 0 by default by the compiler.
  • This storage class is like telling the compiler that this variable is needed throughout the lifetime of the program, unlike the local variable which goes out of scope upon exiting from the block.
  • They can be initialized only once but can be declared multiple times.
  • They are stored in the data section of memory.

It is one of the storage classes which can be associated with three different entities:

  • local variables
  • global variables
  • Function

Local variables:

If any local variables of a function are preceded by a keyword static, it is initialized only once when the function is called for the first time; it maintains its value between the invocations of function calls.

Such variable existence is till the lifetime of the program unlike non-static local variable whose existence is till the function is completed that is creating and destroying it each time it comes into and goes out of scope.

The static variable can maintain its state between the flow controls among frequent context switch.

Static local variables are useful in co-routines (re-entrant function) where we have two routines and flow control is cooperatively passed to each other without returning.

Example:

Reading and parsing a file:

We have one routine which reads few characters from file and sends to second routines which are responsible for parsing. Once the parsing is done again the control goes back to first routine which does the reading and resend a new data for parsing.

But the routine responsible for reading must maintains its previous state that is from which characters to read in new cycle. Thus we can use a static variable which can maintain its state between the flow control among reading and parsing routines.

Global variable:

If any global variable is made static, its scope is restricted to the file in which it is declared. We cannot access it in other file unlike non static global variable which can be accessed to other file using extern.

They are assigned 0 (zero) as default value by the compiler.

Static Function:

If any function is made static, means its scope is restricted to the same file. Even with the help of extern, we cannot access them.

Another use is that we can use same function name in two different files. As by making any function as static, since its scope is restricted to same file (internal linkage), thus we can have same function name.

Extern keyword: extern

  • The extern keyword is used with a variable to inform the compiler that this variable is defined somewhere else.
  • It does not allocate any storage/memory for the variables.
  • The extern variable can be initialized outside the block that should be global. This variable or function has an external linkage that is defined somewhere else in the program or all together in a new file.
  • They are stored in the data segment of the memory.

Example:
Extern variable within the same file

#include <stdio.h>
/* Global variable "a" defined */
int a;
int main()
{
  /* This is just a declaration, no memory allocated */
  extern int a;
  printf("\n The value of a is : %d\n",a);
  return 0;
}

Output:
The value of a is :0

Extern variable in different file

file1.cfile2.c
#include <stdio.h>

/* Global variable “a” defined and initialized */
int a = 7;
int main()
{
fun1();
printf (“\n The value of a is:%d\n”,a);
return 0;
}
#include <stdio.h>
#include “file1.c”

/* extern variable, just declared */
extern int a;

void fun1 (void)
{
a = a + 10;
printf (“\n The value of a is:%d\n”,a);
}

Output:

[aprakash@wtl-lview-6 packetlogic2]$ gcc file1.c file2.c</p>
[aprakash@wtl-lview-6 packetlogic2]$ ./a.out

The value of a is: 17
The value of a is: 17

By default all the functions have external linkages, that’s the reason we do not explicitly make the function fun1() in the first program as extern.

Note:

  • extern int a; just declared not defined
  • extern int a = 10 ; both declared and defined.

GOOD USE CASE:

One use of extern can be in the case of mutex variable, such that it needs global access that is required by many files then in one of the files it can be defined (initialized) and with the help of extern can be accessed in other files too.

Register variable:

  • Scope: They have scope within the function block in which they are defined.
  • Lifetime: Variables defined with register storage class have a lifetime until the end of the function/method block in which they are defined.
  • Default initial value: They are initialized to garbage value by default by the compiler.
  • Register variables are stored in the register of the CPU and not in the memory.
  • Accessing a variable stored in the register is faster than accessing the variable stored in memory.
  • All the variables cannot be stored in the register as there is a limited set of CPU registers.
  • It is most advantageous to use a register for storing pointers. If we use a normal variable then the compiler will fetch the address in the first CPU cycle and then in the second cycle, it goes to that particular address in the main memory. Thus, using the register saves the CPU cycle.
  • Since the register variables are not stored in memory, we cannot use the unary(&) operator on them. Unary operators are used to fetch memory addresses.
  • Example : register int

For more details with good example, please refer: Storage class in C.

Q.15) Explain the memory layout of C program?

The different memory layout of C program is:

  • Code segment or Text Segment
  • Data Segment
  • Heap Segment
  • Stack Segment

Stack segment:

The stack section is used to store automatic variables (non-static local variables) and the calling environment each time a function is called. In the stack section, variable spaces are allocated dynamically by moving up and down the stack pointer which indicates the top of the stack. When a variable goes out of scope, the stack pointer simply goes up and the variable space is no longer usable.

Also all recursive function calls are added to stack. Data is added or removed in a last-in-first-out manner to stack.

Heap Segment:

Heap segment is also part of RAM where dynamically allocated variables are stored. In C language dynamic memory allocation is done by using malloc() and calloc() functions.

The stack and heap are traditionally located at opposite ends of the process’s virtual address space.

Data segment:

Data segment stores program data. This data could be in form of initialized or uninitialized variables, and it could be local or global. Data segment is further divided into four sub-data segments (initialized data segment, uninitialized or. bss data segment, stack, and heap) to store variables depending upon if they are local or global, and initialized or uninitialized.

Note:

We cannot have two variables with same name in Data section.

Initialized Data Segment:

The Initialized Data Segment is the portion of memory space which contains global variables and static variables that are initialized by the code.

Initialized data or simply data segment stores all global, static, constant, and external variables (declared with extern keyword) that are initialized beforehand.

Uninitialized Data Segment or bss segment:

Contrary to initialized data segment, uninitialized data or .bss segment stores all uninitialized global, static, constant and external variables (declared with extern keyword). Global, external, and static variable are by default initialized to zero.

bss is abbreviated as block starting symbol.

program memory layout

Q.16) what is difference between malloc() and calloc()?

The three major difference between malloc() and calloc() are:

malloc() calloc()
It return pointer to the base address allocated of size n
void *malloc(size_t n)
It returns a pointer to contiguous array of n object of specified size.
void *calloc(size_t n , size_t size). That is it returns address of n blocks of array each of length size.
The memory allocated are uninitialized.Memory allocated are initialized to 0.
It is faster than calloc()calloc() takes a longer time as it has to do extra steps of initializing the memory to 0.

Note:

  • If the size passed to malloc is 0, then it either returns NULL or a unique pointer value which can be passed to free. In my system it returns some special pointer.
  • Same applies to calloc with both field and any one field set to 0.
  • A call to calloc() is equivalent to a call to malloc() followed by one to memset().  calloc(m, n) is essentially equivalent to

            p = malloc (m * n);

            memset(p, 0, m * n);

  • Memory allocation by malloc() is faster as calloc() does extra steps of initializing the memory to 0.

But if we use (malloc + memset) as equivalent to calloc(), then calloc() is faster as in case of calloc() only one instruction is used (one system call or library call) whereas in (malloc() + memset) we use two instructions, thus two system call/library calls.

  • Calloc has two arguments whereas malloc has only because many a times we wanted a number (“n”) of uniform objects of particular size (“size”). Database application, for instance, will have such requirement. Proper planning for the values of “n” and “size” can lead to good memory utilization. That is uniform block of memory of specific size is achieved with calloc
  • Both returns a void pointer which can be type casted to any pointer type.
  • If it fails it return NULL.

Actually, the right thing to say is that these two functions are memory managers and not memory allocators. Memory allocation is done by OS specific routines (SYSTEM CALL) (like brk() and sbrk()).

Q.17) What are brk() and sbrk() used for? How are they different from malloc ()?

  • malloc() is a library call which internally uses another system call to allocate memory dynamically on the heap.
  • It returns uninitialized memory of n bytes.

                Syntax: void* ptr =malloc (size_t n);

  • On failure it returns NULL.

Internally malloc() uses a system call brk() and sbrk() that is the brk() and sbrk() subroutines dynamically change the amount of space allocated for the data segment of the calling process.

brk():

  • It stands for break. It states the location specified by its parameter where the program would break. It changes the allocated region accordingly.
  • The break value specifies the maximum space that can be allocated.
  •  If the program tries to access a memory beyond this region, there is an abnormal termination of a process that is signal SIGSEGV is generated.
  • Attempts to set the program break below its initial value (i.e., below &end) are likely to result in unexpected behavior, such as a segmentation fault (the SIGSEGV signal) when trying to access data in now non-existent parts of the initialized or uninitialized data segments.
  • The precise upper limit on where the program break can be set depends on a range of factors, including:
    • The process resource limit for the size of the data segment (RLIMIT_DATA)
    • The location of memory mappings, shared memory segments, and shared libraries.
  • The break value is the address of the first location beyond the current end of the data region.
  • The amount of available space increases as the break value increases.
  • The amount of space is initialized to a value of 0 at the time it is used. The break value is automatically rounded to that of the page size depending upon the processor architecture.

Return Value:

It returns 0 on success and -1 on failure.

Syntax:

int brk(void * end_data_segment)

Sbrk():

  • It stand for space increment after program break address.
  • It is used to increase or decrease the available space by specifying the increment parameter or decrement parameter as its argument.
  • It returns the old break value on success and -1 on failure.
  • In other words, if we have increased the program break, then the return value is a pointer to the start of the newly allocated block of memory.

Syntax:

   void *sbrk(intptr_t increment);

Reference:

Q.18) is the cast to malloc () required at all?

In C, we don’t need to cast the return value of malloc. The pointer to void returned by malloc is automatically converted to the correct type. However, if we want our code to compile with a C++ compiler, a cast is needed.

Q.19) what is the common problem with malloc()?

The most common source of problems with malloc () are

 1. Writing more data to a malloc’ed region than it was allocated to hold.

 2. malloc (strlen (string)) instead of (strlen(string) + 1).

 3. Using pointers to memory that has been freed.

 4. Freeing pointers twice.

 5. Freeing pointers not obtained from malloc.

 6. Trying to realloc a null pointer.

Q.20) How does free () work?

Any memory allocated using malloc () realloc () must be freed using free (). In general, for every call to malloc (), there should be a corresponding call to free (). When we call free (), the memory pointed to by the passed pointer is freed. However, the value of the pointer in the caller remains unchanged. It’s a good practice to set the pointer to NULL after freeing it to prevent accidental usage.

The malloc() implementation keeps track of the size of each block as it is allocated, so it is not required to remind it of the size when freeing it using free().Unfortunately there is no standard or portable way to know how big an allocated block is using the pointer to the block.

There is a special block which holds metadata in the pointer variable which holds the size.

Q.21) what is realloc() in C?

This is used to change the size of the memory pointed by *ptr to new size specified by second parameter (size).

                                    void *realloc(void *ptr, size_t size)

Parameters:

  • ptr — This is the pointer to a memory block previously allocated with malloc, calloc or realloc to be reallocated.
  • size — This is the new size for the memory block, in bytes.

Note:

  • If the first parameter is NULL, then realloc() behaves like a malloc and allocates a memory of specified size of second parameter and there is no question of copying the content of first to new memory.
  • If the second parameter that is size is 0, then the behavior is implementation defined and can return NULL or returns or a behavior is as if some non-negative value were supplied, except that pointer should not be used to access an objects.
  • If a NULL is returned, free(NULL) does not causes any issue or if address is returned, again no issue in using with free.
  • In case of realloc() we should make sure that we don’t overwrite the old pointer too early.
  int *p= malloc(10)
  if(p==NULL)
     printf(“Failure “);
  else
     printf(“Success “);

   Realloc:
  ------------
  p =realloc(p,20)
    We should not do like this because if the realloc fails then we lose the original p pointer.

 int *temp = realloc(p,20)
  if(!temp)
    printf(Failed”);
   else
  {
      p =temp;
      free(temp);
  }

Internal working of realloc():

  • If there is enough free space behind the current block to fulfill the request, extend the current block and return a pointer to the beginning of the block which is same as that of old one. In this case old block is not freed.
  • Else if there is a large enough free block elsewhere, then allocate that block, copy the data from the old block over, old block is freed automatically and return a pointer to the beginning of the new block.
  • The rest of the block of new memory will be uninitialized.
  • Else report failure by returning NULL and if it fails the old memory will be as it is neither freed nor moved.
  • If success it returns address of the new block (if not tailed after the old one) or same address as that of old one is returned.
  • It fails if there is not enough memory to allocate, the memory should be continuous.

Return Value

This function returns a pointer to the newly allocated memory, or NULL if the request fails. If fails old memory is as it is.

Q.22) does extern in a function declaration mean anything?

The extern in a function’s declaration is sometimes used to indicate that the function’s definition is in some other source file, but there is no difference between extern int function_name(); and int function_name();

This is because by default all the function have external linkage that is extern attached to it.

Q.23) what is the importance of void pointer?

Void pointer is a generic pointer which can hold the address of any type of variable be it int, float, char etc.

Since in this case we do not know the type of address thus before dereferencing we need to typecast it accordingly.

There is no way the compiler can know (or guess?) what type of data is pointed to by the void pointer. So to take the data pointed to by a void pointer we typecast it with the correct type of the data hold inside the void pointers location. 

#include 
void main()
{
    int a=10;
    float b=35.75;
    void *ptr;
    ptr=&a; 
    printf("The value of integer variable is= %d",*( (int*) ptr) );
    ptr=&b; 
    printf("The value of float variable is= %f",*( (float*) ptr) );
}

A void pointer can be really useful if the programmer is not sure about the data type of data inputted by the end user.

Q.24) what is constant pointer?

A constant pointer is one whose address cannot be modified but value can be modified.

Example:

In the case of malloc() we get an address of the memory allocated, thus this memory should not be lost since we need to deallocate that memory. This can be achieved by constant pointer.

Syntax:

                int a 10; int b =20;

                int *cosnt ptr  = &a;

                ptr =&b; //Error

Q.25) what is pointer to constant?

Pointer to constant means, the address can be changed but its value cannot be changed.

Example:

In the case of getting the length of the string, the string should be passed pointer to constant to function thus making function helpless to change the length of given string.

Syntax:

              int const *variable_name;

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

              *ptr =100; //error    Or in the case of copy constructer in c++.

For more details , please refer: constant pointer and pointer to constant

Q.26) what is const char * const pointer?

In this case neither the address nor the value can be modified.

This is a constant pointer to constant char! One cannot change the value pointed to by p nor the pointer.

Q.27) what is function pointer and array of function pointer?

  • Pointer is nothing but a variable which holds address; similarly, function pointer is a concept where a pointer holds the address of the function to be executed.
  • It is a mechanism to achieve CALLBACK.
  • In this we do not call the function rather is called by the system automatically upon certain predefined conditions that is event and this call is done at run time.
  • Example, we have inbuilt function called atexit() which is called by the system automatically at the end of the program.

Callback Mechanism:

If the reference of a function is passed as an argument to another function to call it, it is known as the callback function. This is achieved using a function pointer when the address of the function is passed to another function to call it.

Syntax:

  • Creating the function pointer

    int (*ptr) (int, int)

  • Assigning a function address to the pointer

                ptr =fun;

                Equivalent of above two line is

                 void (*ptr)(int, int) = fun;

  •  Calling the function

                      (*ptr)(3,4)

In the above example fun is a function responsible for addition of two numbers.

Array of function pointer:

   Syntax:

  1. Creating:    int (*ptr[]) (int, int)
  2. Assigning the function pointer with the address of the function

                 ptr[0]=add;

                 ptr[1]=sub;

      3. Calling the function

               (*ptr[0]) (4,3)

                (*ptr[1]) (4,3)

Returning a function pointer:

float GetPtr2(const char opCode)
{
   if(opCode == '+')
      return &Plus;
   else
      return &Minus;
 }
void Return_A_Function_Pointer()
{
    float (*pt2Function)(float, float) = NULL;

   pt2Function=GetPtr2('+');   
   (*pt2Function)(2, 4);


   pt2Function=GetPtr2('-');
   (*pt2Function)(2, 4);
}

Example:

#include <stdio.h>

int add (int num1, int num2)
{
    return num1 + num2;
}

int main ()
{
    //Declare a function pointer    
    int (*ptr) (int, int);
    //Assign function address to pointer
    ptr = fun;
    //Call function pointer
    int ret = (ptr) (3,4);
    printf("\n The sum is: %d", ret);
   
  return 0;
}

For more details, please refer: function pointer in C

Q.28) Differentiate between enum and macro?

  • It stands for enumerated type and is a user-defined data type that represents an integer constant. It is used to assign a name to the integer constant which makes the program more readable and easy to maintain.
  • The starting value of names in the enum starts with 0 and plus one for the next and so on.
  • Names can also be associated with custom user-defined values.
  • This is a run time entity.

Syntax:

enum <enum_name> <list of name>

Example:

#include <stdio.h>

enum days {sun,mon,tue,wed};
int main()
{
int x=sun;
printf(“%d”,x);
retuen 0;
}
It will have resulted as 0

Application:

enum is used for values that are not going to change (e.g., days of the week, colors in a rainbow, number of cards in a deck, etc.​).

enum is commonly used in switch-case statements

Some of the common difference between enum and macro are as follows:

                            Enum                             Macro
It is a run time entity.It is a preprocessor and is a compile time enity
It is faster and less overhead as values are assigned implicitly.In case of macro we need to assign values explicitly.
  

For more details, please refer: enum , macro and inline function in C

Q.29) what are compilation steps in C program?

In a C program we have four steps of compilation

  • Preprocessor
  • Compilation
  • Assembly
  • Linking and Loading
  • Execution

Preprocessor:
This is the first phase of any C compilation. Its processes included files called file inclusion, conditional compilation instructions, and macros.

It converts C source code in expanded source code or a high-level language into pure high-level language.

Compilation:
It is the second phase. It takes the output of the preprocessor that is a pure high-level language and generates assembler source code.

Assembler:
It is the third stage of compilation. It takes the assembly source code and produces a relocatable code which is called an object or machine file which is of the same name as that of the program with extension dot o(.o).

Every machine has a different architecture, so the input fed to each machine should be understood by the machine and the compiler does not worry about that point. So it’s the assembler that makes the compiler machine-independent.

Loading:
Using a Loader program, the executable code is loaded into CPU for execution. In the assembler phase, a relocatable code is generated. This is the responsibility of the loader to load the code at the proper place on the machine.

For example: Say in the code we have goto statement( goto 100) which is nothing but 100th line in the code but in the machine this may be present at address 1000, so it is responsibility of the loader to change these address. So loader is the one which correct these addresses.

Linking:
It is the final stage of compilation. It takes one or more object files or libraries as input and combines them to produce a single (usually executable) file or a new library.

Multiple units of object codes are linked to together in this step.

Execution:
And finally, the executable is executed or run to get the desired result.

hello_world.c -> Preprocessor -> hello_world.i -> Compiler -> hello_world.s -> Assembler -> hello_world.o

Diag-1: Phase of C compilation

Q.30) what is preprocessor and its directives?

It is the first stage of our program compilation and its command are refereed as preprocessor directives.

It processes include-files, conditional compilation instructions and macros.

It converts C source code in expanded source code.

Some of the common directives are:

1) #include

2) Conditional compilation: advantage portability

3) #pragma

4) Macro

Conditional compilation:

These are special directives that allow us to selectively compile portion of our source code.

Advantage is portability: we can make the compiler to skip over part of source code by inserting the preprocessor directives called conditional compilation.

#pragma

This is an implementation defined directives that allows various instruction to be passed to the compiler

Some of the pragma directives in turbo c++ compiler are

i) #pragma startup:

It allows programmer to specify the function to be called first even before main();

Syntax: #pragma startup fun1

ii) #pragma exit:

It will call the function just before the program terminates.

Syntax: #pragma exit fun2

iii) #pragma warn:

We can turn on or off warning message using this pragma.

iv) #pragma pack(1) :

This is used to avoid structure padding

Q.31) what is reentrant function?

A function is said to be reentrant if it is accessed by more than one thread or task concurrently without any fear of data loss or corruption.

Such function can be interrupted in the middle of their execution and returns back safely that is re-entered before its previous execution completes execution.

Ideally re-entrant function should use local variable so that at each call, a new copy of variable is created and hence the variable is not lost or corrupted.

If any global variable or a static variable is there, then such variable must be safeguarded by external mechanism like locking or a semaphore.

Such functions are called as pure function.

This is practically very advantageous in the embedded field where memory is concern and interrupts can occur at any point of time. In such case it’s better to have reentrant function so that it can be used by more than one process/task/thread, with each function having its own copy of data.

A function should satisfy the following condition to be reentrant:

  • It uses all the shared variable in an atomic way, means it should not be interrupted.
  • It does not call non-reentrant function.
  • It does not use the hardware in a non-atomic way.

When to use reentrant function:

  • Function which are in context to interrupt in embedded filed.
  • Function which will be called by multiple threads/task must be reentrant.

Q.32) what is thread safe?

A function is said to be thread safe if its function correctly even if it is accessed by multiple threads at the same time.

The basic difference between thread safe and reentrant function is that in case of re-entrant function, it is termed as safe only if each thread/task uses its own copy (local variable) where as in function is said to be thread safe if is accessed by multiple threads/task and each thread does not have the independent copy of shared variable. Safety is achieved by some external mechanism like mutex or semaphore.

Thread safe are always reentrant function but not all re-entrant function is thread safe.

Few of the ways by which we can achieve thread safety are:

  • Mutual Exclusion.
  • Atomic operation (Cannot be interrupted)
  • Re-entrancy
  • Thread local storage that is each thread will have its own copy of data.

Example of THREAD SAFE ENTRANCY:

void swap(int *x, int *y)
{
    int t;
    t = *x;
    *x = *y;
    *y = t;
}

Q33) what is difference between macro and function?

1) Macro: It result in text substitution and it is a preprocessor directive.

2) Function: Function result in call i.e. has a run time context.

3) Macros cannot enforce types whereas function does.

Q34) what do you mean by typedef?

The typedef is an advance feature in C language which allows us to create an alias or new name for an existing type or user defined type.

It makes our program loose coupling.

Example: struct employee

{

     int empid;

     char name;

};

typedef struct employee EMP

This whenever we need to declare variable of type struct employee we can write:

EMP variable name;

A) int x;

B) typedef int x;

B is more preferred over A because tomorrow if we want to change the type of variable i.e. x then we can simply write typedef newdatatype x;

There are three main reasons for using typedefs:

  • It makes the writing of complicated declarations a lot easier. This helps in eliminating a lot of clutter in the code.
  • It helps in achieving portability in programs. That is, if we use typedefs for data types that are machine dependent, only the typedefs need to change when the program is ported to a new platform.
  • It helps in providing better documentation for a program. For example, a node of a doubly linked list is better understood as ptrToList than just a pointer to a complicated structure.

For more details and example , please refer: typedef in C

Q.35) what is a NULL pointer? How is it different from an uninitialized pointer? How is a NULL pointer defined?

  • A NULL pointer is the one which does not point to any object or function.
  • Pointer which is initialized with NULL value is referred as NULL pointer.

A null pointer is very different from an uninitialized pointer. A null pointer does not point to any object or function; but an uninitialized pointer can point anywhere. This is also known as Wild pointer. It may contain a garbage value.

There is usually a null pointer for each type of a pointer, and the internal values of these null pointers for different pointer types may be different, it’s up to the compiler.

The & operator will never yield a null pointer, nor will a successful call to malloc () (malloc () does return a null pointer when it fails).

NULL pointer can be defined as:

                                                    #define NULL ((void *) 0)

                                                    NULL and 0 are interchangeable in pointer contexts.

This is same as NULL macro.

#define NULL 0
it means the macro NULL will be replaced by 0 while preprocessing
But the NULL pointer means it points to nowhere i.e. contains 0. 


NULL macro is defined in stdio.h/stddef.h and represents a zero. Any pointer pointing to 0x0 locations is null pointer that is base address of the memory segment.

Null pointer is a pointer which has 0 or NULL value stored and points to nowhere still it points to 0x00 i.e. the first memory location of the OS.

Null pointer! = Uninitialized pointer because an uninitialized pointer can point anywhere in the memory location …but a NULL pointer surely points to nowhere (but still behind the scene we can say that it only points to 0x00).

Importance of NULL Pointer:

A null pointer should not be confused with an uninitialized pointer: a null pointer is guaranteed to compare unequal to any valid pointer, whereas depending on the language and implementation an uninitialized pointer might have either an indeterminate (random or meaningless) value or might be initialized to an initial constant (possibly but not necessarily NULL).

Q.36) what is Null Pointer Assignment Error?

It occurs when user tries to assign a value to the pointer which is currently pointing to null
If in our program, a pointer gets wild and tries to point to a location that it should not point, we will get Null Pointer Assignment error.

Q.37) what are reference counters with respect to pointers?

A pointer which points to an object that no longer exists is termed as Dangling pointer. It’s a pointer referring to an area of memory that has been deallocated. Dereferencing such a pointer usually produces garbage.

Using reference counters which keep track of how many pointers are pointing to this memory location can prevent such issues. The reference counts are incremented when a new pointer starts to point to the memory location and decremented when they no longer need to point to that memory. When the reference count reaches zero, the memory can be safely freed. Also, once freed, the corresponding pointer must be set to NULL.

Q.38) what does pointer contain?

Since addresses are always whole numbers, pointers always contain whole numbers.

Q.39) what operations are valid on pointers? When does one get the Illegal use of pointer in function error?

Pointer is a variable which holds the address of another variable that it points to an address in a memory. The following arithmetic operations are valid to be performed on pointers.

  • Assignment Operator(=)
  • Increment Operator(++)
  • Decrement Operator(–)
  • Addition(+)
  • Subtraction(-)
  • Comparision Operator(==, <, >, !=, <=, >=)
#include <stdio.h>
int main()
 {
   int myarray[5] = {2, 4,6, 8,10};
   int* myptr = NULL;
   myptr = myarray;
   printf("\n First element in the array :%d", *myptr);
   myptr ++;
   printf("\n Next element in the array :%d", *myptr);
   myptr +=1;
   printf("\n Next element in the array :%d", *myptr);
   myptr--;
   printf("\n Previous element in the array :%d", *myptr);
   myptr -= 1;
   printf("\n Previous element in the array :%d", *myptr);
  
   return 0;
 }

Output:

First element in the array :2
Next element in the array :4
Next element in the array :6
Previous element in the array :4
Previous element in the array :2

Note that the increment operator ++ increments the pointer and points to the next element in the array. Similarly, the decrement operator decrements the pointer variable by 1 so that it points to the previous element in the array.

We also use + and – operators. First, we have added 1 to the pointer variable. The result shows that it points to the next element in the array. Similarly, – operator makes the pointer variable to point to the previous element in the array.

Apart from these arithmetic operators, we can also use comparison operators like ==, < and > but multiplication or division operator cannot be used.

For more details, please refer: Pointer arithmetic and address arithmetic

Q.40) Why is sizeof () an operator and not a function?

sizeof () is a compile time operator. To calculate the size of an object, we need the type information. This type information is available only at compile time. At the end of the compilation phase, the resulting object code doesn’t have (or not required to have) the type information.

Of course, type information can be stored to access it at run-time, but these results in bigger object code and less performance. And most of the time, we don’t need it. All the runtime environments that support run time type identification (RTTI) will retain type information even after compilation phase. But, if something can be done in compilation time itself, why do it at run time?

Q.41) what is the purpose of a function prototype?

A function prototype tells the compiler to expect a given function to be used in a given way. That is, it tells the compiler the nature of the parameters passed to the function (the quantity, type and order) and the nature of the value returned by the function.

Having a function porotype before its definition is referred as forward declaration.

Q.42) what are inline functions?

Inline functions are like a normal functions with the keyword inline and the body of the function is substituted at the place of function rather than calling the function and maintaining the stack that is there is no context switching, its just the expansion of the function each time it is called.

These are generally for short function and its a request to the compiler not a compulsion.

The biggest advantage of inline function is that there is no call to the function and hence no overhead of context switching like saving the current context onto stack and restore once function has completed execution.

But with inline the size of the code increases because the function is expanded at function call

Good time to use inline functions is

1. There is a time critical function.

2. that is not called often.

3. Its small.

Remember that inline functions take more space than normal functions.

Some typical reasons why inlining is sometimes not done are:

 1. The function calls itself, that is, is recursive.

 2. The function contains loops such as for(;;) or while().

 3. The function size is too large.

Example:

#include <stdio.h>

inline int sqr(int x)
{
   int y;
   y = x * x;
   return y;
}
int main()
{
   int a =3, b;
   b = sqr(a);
   cout <<b;
   return 0;
}

Here, the statement b = sqr(a) is a function call to sqr().

But since we have declared it as inline, the compiler replaces the statement with the executable statement of the function (b = a *a).

Q.43) Difference between a macro and inline function?

                 Inline Function                   Macro
Inline replaces a call to a function with the body of the functionA macro on the other hand, is expanded by the preprocessor before compilation, so it’s just like text substitution
Inline functions follow all the protocols of type safety enforced on normal functions. Argument types are checked, and necessary conversions are performed correctly. The compiler performs return type checking, function signature before putting inline function into symbol table.No such thing, hence, macros are more error prone as compared to inline functions. The parameters are not typed (the macro works for any objects of arithmetic type). No error checking is done during compilation. E.g. We can pass strings to a macro that does some integer arithmetic
They are parsed by the compilerThey are expanded by the preprocessor at pre-compile time.
Inline functions may or may not be expanded by the compiler. It is the compiler’s decision whether to expand the function inline or not.Macros are always expanded.

Q.44) Difference between inline function and normal function?

            Normal function                    Inline function
In case of ordinary function, when
calling the function, the scope jumps to  the function and after return jumps
back to the function call statement resulting in some extra execution time   Link: http://www.programmerinterview.com/index.php/c-cplusplus/inline-vs-macro/
While in case of inline function the scope doesn’t really jumps to the function saving some execution time.  However, while making any function inline we are just sending request to make the function inline, It completely depends on the compiler that it will treat the function as inline or some ordinary function.
with a regular function, a normal function call is generatedAn inline function and a regular function is that wherever the compiler finds a call to an inline function, it writes a copy of the compiled function definition. 
It  takes less spaceinline functions take more space

Q.45) how can we find how many arguments a function was passed?

Any function which takes a variable number of arguments must be able to determine from the arguments themselves, how many of them there have been passed.

printf() and some similar functions achieve this by looking for the format string. This is also why these functions fail badly if the format string does not match the argument list. Some older compilers did provided a nargs() function, but it was never portable.

Q.46) Does C really have pass by address?

No. C uses pass by value, but it can pretend doing pass by address, by having functions that have pointer arguments and by using the & operator when calling the function. This way, the compiler will simulate this feature (like when we pass an array to a function, it actually passes a pointer instead). C does not have something like the formal pass by reference or C++ reference parameters.

Q.47) how will you decide whether to use pass by reference, by pointer and by value?

 The selection of the argument passing depends on the situation.

A function uses passed data without modifying it:

  • If the data object is small, such as a built-in data type or a small structure then pass it by value.
    • If the data object is an array, use a pointer because that is the only choice. Make the pointer a pointer to const.
    • If the data object is a good-sized structure, use a const pointer or a const reference to increase program efficiency. We save the time and space needed to copy a structure or a class design, make the pointer or reference const.
    • If the data object is a class object, use a const reference. The semantics of class design often require using a reference. The standard way to pass class object arguments is by reference.

A function modifies data in the calling function:

 If the data object is a built-in data type, use a pointer. If we spot a code like fixit(&x), where x is an int, it’s clear that this function intends to modify x.

  • If the data object is an array, use the only choice, a pointer.
    • If the data object is a structure, use a reference or a pointer.
    • If the data object is a class object, use a reference.

Q.48) what do lvalue and rvalue mean?

An lvalue is an expression that could appear on the left-hand sign of an assignment (An object that has a location). An rvalue is any expression that has a value (and that can appear on the right-hand sign of an assignment). The lvalue refers to the left-hand side of an assignment expression. It must always evaluate to a memory location. The rvalue represents the right-hand side of an assignment expression; it may have any meaningful combination of variables and constants.

Q.50) what does the term cast refer to? Why is it used?

Casting is a mechanism built into C that allows the programmer to force the conversion of data types. This may be needed because most C functions are very particular about the data types they process. A programmer may wish to override the default way the C compiler promotes data types

Q.51) what is type checking?

It is the process by which the C compiler ensures that functions and operators use data of the appropriate type(s). This form of check helps ensures the semantic correctness of the program.

Q.52) what is forward declaration?

forward declaration is the declaration of a method or variable before we implement and use it. The purpose of forward declarations is to save compilation time.

The forward declaration of a variable causes storage space to be set aside, so we can later set the value of that variable.

The forward declaration of a function is also called a “function prototype,” and is a declaration statement that tells the compiler what a function’s return type is, what the name of the function is, and the types its parameters.

Q.53) what is forward reference?

forward reference is the opposite. It refers to the use of an entity before its declaration. For example:

int first(int x) {
   if (x == 0) return 1;
   return second(x-1); // forward reference to second
}

int second(int x) {
   if (x == 0) return 0;
   return first(x-1);
}

Q.54) what is the difference between the declaration and the definition of a variable?

The definition is the one that actually allocates space, and provides an initialization value, if any. There can be many declarations, but there must be exactly one definition. A definition tells the compiler to set aside storage for the variable. A declaration makes the variable known to parts of the program that may wish to use it. A variable might be defined and declared in the same statement.

Q.55) Does C have Boolean variable type?

 No, C does not have a boolean variable type. One can use int, chars, #defines or enums to achieve the same in C.

#define TRUE 1 #define FALSE 0 enum bool {false, true};

An enum may be good if the debugger shows the names of enum constants when examining variables.

Q.56) when should a type cast be used?

There are two situations in which to use a type cast.

  • The first use is to change the type of an operand to an arithmetic operation so that the operation will be performed properly.
  • The second case is to cast pointer types to and from void * in order to interface with functions that expect or return void pointers.
  • For example, the following line type casts the return value of the call to malloc() to be a pointer to a foo structure. struct foo *p = (struct foo *) malloc(sizeof(struct foo));
  •  A type cast should not be used to override a const or volatile declaration. Overriding these type modifiers can cause the program to fail to run correctly. A type cast should not be used to turn a pointer to one type of structure or data type into another.

Q.57) Can we directly compare two structures using the == operator?

No, we cannot! The only way to compare two structures is to write our own function that compares the structures field by field. Also, the comparison should be only on fields that contain data (We would not want to compare the next fields of each structure!).

A byte by byte comparison (say using memcmp ()) will also fail. This is because the comparison might fonder on random bits present in unused “holes” in the structure (padding used to keep the alignment of the later fields correct). So a memcmp () of the two structure will almost never work. Also, any strings inside the structures must be compared using strcmp() for similar reasons.

There is also a very good reason why structures can be compared directly – unions! It is because of unions that structures cannot be compared for equality. The possibility that a structure might contain a union makes it hard to compare such structures; the compiler can’t tell what the union currently contains and so wouldn’t know how to compare the structures

If our structures don’t have stuff like floating point numbers, pointers, unions etc…, then we could possibly do a memset () before using the structure variables.

memset (&myStruct, 0, sizeof(myStruct)); This will set the whole structure (including the padding) to all-bits-zero. We can then do a memcmp () on two such structures. memcmp (&s1,&s2,sizeof(s1)); But this is very risky and can end up being a major bug in our code.

Q.58) what should go in header files? How to prevent a header file being included twice? Whats wrong with including more headers?

Generally, a header (.h) file should have (A header file need not have a .h extension, it’s just a convention):

1. Macro definitions (preprocessor #defines).

2. Structure, union, and enumeration declarations.

3. Any typedef declarations.

4. External function declarations.

5. Global variable declarations.

Put declarations / definitions in header files if they will be shared between several other files. If some of the definitions / declarations should be kept private to some .c file, don;t add it to the header files.

How does one prevent a header file from included twice?

Including header files twice can lead to multiple-definition errors. There are two methods to prevent a header file from included twice:

Method1

#ifndef HEADER_FILE

     #include <local.h>

#endif

 Method2

A line like #pragma once

grandfather.h
  #prgama once
struct emp {
int a;
}
parent.h  
#include<grandfather.h>    
  child.h  
#include <father.h> #include<grandfather.h>
In this example, the inclusion of grandparent.h in both parent.h and child.c would ordinarily cause a compilation error, because a struct with a given name can only be defined a single time in a given compilation. The #pragma once directive serves to avoid this by ignoring subsequent inclusions of grandparent.h

Q.59) So, what’s the difference between #include < a.h > and #include “a.h”?

The difference lies in the location where the preprocessor searches for the included file.

  • #include <a.h>

It searches in an implementation dependent manner that is it searches the pre-determined directories. This is normally used to include standard library header files.

  • #include “a.h”

It searches the same directories as the file containing the directives. This is normally used to include programmer’s headers files.

Q.60) what happens if we include unwanted headers?

We will end up increasing the size of your executables

Q.61) how can I return multiple values from a function?

There are multiple ways by which we can return multiple values from a function. Some of them are as follows:

Method 1: Using Array

  • If more than two variables of same type are to be returned, then we can use array.
  • Store each and every value to be returned in an array and return base address of that array.

Method 2: Using Pointer and One Return Statement

  • Pointer Variable can have updated directly using Value at [‘*’] Operator.
  • Usually Function can return single value.
  • If we need to return more than two variables, then update 1 variable directly using pointer and return second variable using ‘return Statement ‘. [ Call by Value + Call by Reference]

Method 3: Using Structure 

  • Construct a Structure containing values to be returned and then return the base address of the structure to the calling function

Q.62) How to write functions which accept two-dimensional arrays when the width is not known before hand?

Even one dimensional array can be access by pointer.

For accessing one dimensional array:

    arr[i] =   *(arr +i)

In the similar fashion we can access the 2-D array with the help of pointers:

   arr[i][j] =    *(*(arr +i) +j )

The other way we can access 2-D array is:

  arr[i] [j] =      *((*(arr)) + (i *NOC +j) )

 myfunc(&myarray[0][0], NO_OF_ROWS, NO_OF_COLUMNS);

 void myfunc(int *array_pointer, int no_of_rows, int no_of_columns)

 {  

     arr[i] [j] =      *(*arr+ (i *NOC +j) )

  }

Note:

Even 2-D array, the elements are stored in contagious memory location.

Q.63) Do Global variables start out as zero?

Uninitialized variables declared with the “static” keyword are initialized to zero. Such variables are implicitly initialized to the null pointer if they are pointers and to 0.0F if they are floating point numbers.

Local variables start out containing garbage, unless they are explicitly initialized. Memory obtained with malloc () and realloc () is likely to contain junk, and must be initialized. Memory obtained with calloc() is all-bits-0, but this is not necessarily useful for pointer or floating-point values (This is in contrast to Global pointers and Global floating point numbers, which start as zeroes of the right type).

Q.64) what is volatile keyword?

Volatile is a keyword attached to variable which indicates to the compiler that the value of the variable can be changed any point during the lifetime of the variable that is its value is un deterministic. Its value can be changed even by code which is beyond the scope of current code.

It’s an indication to the compiler not to optimize the data.

Example1:

One best example would when we compile our code with optimization flag set, then the compiler will keep the variable in cache and does not refer to memory for reading the value and it may end up reading the wrong value because of compiler optimization. To avoid this, we can use volatile variable which are used during compilation.

Example2:

System time is measured by a system clock which is typically implemented as a simple count of the number ticks occurred since any arbitrary point.

This tick is governed by board hardware used by the kernel and it can change at any point of time like when the system boots up. Hence it is advisable to have such variable for system time as volatile.

Example3:

The second example could be variable used in ISR routine as interrupts can occur at any point of time and can modify the value.

The code reading data port must be declared as volatile in order to fetch latest data available at the port. Failing to declare variable as volatile, the compiler will optimize the code in such a way that it will read the port only once and keeps using the same value in a temporary register to speed up the program (speed optimization). In general, an ISR used to update these data port when there is an interrupt due to availability of new data.

Const volatile:

Any variable that is preceded by const volatile means its value cannot be changed based on the current scope of the program but can be modifiable from outside.

It is used in situations like a read-only hardware register, or an output of another thread. Volatile means it may be changed by something external to the current thread and Const means that we do not write to it (in that program that is using the const declaration).

Example:

“extern const volatile int real_time_clock;”

Where real_time_clock may be modifiable by hardware, but cannot be assigned to, incremented, or decremented

Q.65) when should the register modifier be used?

The register modifier hints to the compiler that the variable will be heavily used and should be kept in the CPU’ s registers, if possible, so that it can be accessed faster.

There are several restrictions on the use of the register modifier.

  • First, the variable must be of a type that can be held in the CPU’s register. This usually means a single value of a size less than or equal to the size of an integer. Some machines have registers that can hold floating-point numbers as well.
  •  Second, because the variable might not be stored in memory, its address cannot be taken with the unary & operator. An attempt to do so is flagged as an error by the compiler.
  •  Some additional rules affect how useful the register modifier is. Because the number of registers is limited, and because some registers can hold only certain types of data (such as pointers or floating-point numbers), the number and types of register modifiers that will actually have any effect are dependent on what machine the program will run on.
  • Also, in some cases, it might actually be slower to keep a variable in a register because that register then becomes unavailable for other purposes or because the variable isn’t used enough to justify the overhead of loading and storing it.
  •  So when the register modifier should be used? The answer is never, with most modern compilers. Early C compilers did not keep any variables in registers unless directed to do so, and the register modifier was a valuable addition to the language. C compiler design has advanced to the point, however, where the compiler will usually make better decisions than the programmer about which variables should be stored in registers. In fact, many compilers actually ignore the register modifier, which is perfectly legal, because it is only a hint and not a directive.

If the register variable declaration fails, it moves to auto variable automatically.

Q.66) Is there any difference between char *a and char a[]?

There is a lot of difference for char a[] = “string”; char *a = “string”; The declaration char a[] asks for space for 7 characters and see that its known by the name “a”.

In contrast, the declaration char *a, asks for a place that holds a pointer, to be known by the name “a”. This pointer “a” can point anywhere. In this case it’s pointing to an anonymous array of 7 characters, which does not have any name in particular. It’s just present in memory with a pointer keeping track of its location.

It is crucial to know that a[3] generates different code depending on whether a is an array or a pointer. When the compiler sees the expression a[3] and if a is an array, it starts at the location “a”, goes three elements past it, and returns the character there.

When it sees the expression a[3] and if a is a pointer, it starts at the location “a”, gets the pointer value there, adds 3 to the pointer value, and gets the character pointed to by that value. If a is an array, a[3] is three places past a.

If a is a pointer, then a[3] is three places past the memory location pointed to by a. In the example above, both a[3] and a[3] return the same character, but the way they do it is different!

Doing something like this would be illegal.

char *p = “hello, world!”;

 p[0] = ‘H’;

It is very much like pointer to constant string placed at read only section of memory.

Q.67) How does the function strtok () work?

strtok () is the only standard function available for “tokenizing” strings. The strtok () function can be used to parse a string into tokens. The first call to strtok () should have the string as its first argument. Subsequent calls should have the first argument set to NULL.

Each call returns a pointer to the next token or NULL when no more tokens are found. If a token end with a delimiter, this delimiting character is overwritten with a “\0” and a pointer to the next character is saved for the next call to strtok (). The delimiter string delim may be different for each call. The strtok_r() function works the same as the strtok() function, but instead of using a static buffer it uses a pointer to a user allocated char* pointer. This pointer must be the same while parsing the same string.

Q.68) what is the prototype of main ()? Can main () return a structure?

The right declaration of main () is

  • int main(void)
  • int main(int argc, char *argv[])
  • int main(int argc, char *argv[], char *env[]) //Compiler dependent, non-standard C.

 In C, main () cannot return anything other than an int. something like void main () is illegal. There are only three valid return values from main () – 0, EXIT_SUCCESS, and EXIT_FAILURE, the latter two are defined in <stdlib.h>

NOTE:

main can be called recursively until Runtime error: Stack overflow

Q.69) How to print the arguments received by main ()?

Here is some code

 main(int argc, char*argv[])

  {

     int i; for(i=0; i<argc; i++)

       {

           printf(“\n[%s]\n”, argv[i]);

       }

 }

Q.69) what is assert?

Assert.h is a header file in the standard library of the C programming language that define the C preprocessor macro assert. The macro implements an assertion which can be used to verify assumption made by the program and print the diagnostic message if the assumption fails.

Parameter:

  • Expression: This can be a variable or any C expression. If expression evaluates to TRUE, assert () does nothing. If expression evaluates to FALSE, assert () displays an error message on stderr (standard error stream to display error messages and diagnostics) and aborts program execution.
  • assert(5>3)

Return value:

This macro does not return any value

Q.70) how does the structure of the program effects the overall efficiency of the program?

This can be illustrated with the example of a 2-Dimenisonal array. Even in case of 2-D array, the elements are stored in sequential order.

Any 2-Dimenisonal array can be accessed in two ways:

  • Row wise
  • Column wise

When an array is accessed in row wise fashion, then it is considered to be more efficient in terms of accessing the memory location.

Cache plays an important role in enhancing the speed at which any memory location is accessed. In today’s standard architecture, cache uses what is called “spatial locality” that is if we access any cell in a memory then it is very likely that we would even access the next cell and so on.

Keeping the above points into consideration, if we access the arr[0][0], the compiler would cache the next cell that is a[0][1] and complete row and if cache space permits even the second row would be cached.

As we know that accessing the cache is way faster than accessing the memory location, hence if the 2-D array is accessed in row wise, it would enhance the overall efficiency of the program due to cache.

If the array is accessed in column wise, then we may experience lot of cache miss and we need to fetch the data from the main memory which is an overhead in terms of speed/time.

Q.71) what is memory overlapping?

In general memory overlapping in C is referred as writing into same memory location more than once.

We can understand this better with one the library calls of C language that is memcpy.

Syntax for memcpy:

    void *memcpy (void *dest, void *src, size_n size);

It returns pointer to destination.

Let’s us see how this function has an issue of memory overlapping.

#include <stdio.h> 
#include <string.h> 

int main() 
{ 
   char csrc[100] = "techaccess"; 
   memcpy(csrc + 5, csrc, 7); 
   printf("%s", csrc); 
   return 0; 
}
Output:
techatechate

In the above example we can see that there is a memory overlap. Even function like strcpy (), strcat(), sprintf() and sscanf() suffers from memory overlap issue.

If the same logic is put for memmove(), it works well that is it does not have any memory overlap issue, since in this case, the source are first copied into temporary buffer and then copied to destination.

The same program with memmove() where there is no memory overlapping

#include <stdio.h> 
#include <string.h> 

int main() 
{ 
   char csrc[100] = "techaccess"; 
   memmove(csrc + 5, csrc, 7); 
   printf("%s", csrc); 
   return 0; 
}

Output:

techatechacc

Q.72) How do u avoid memory overlapping problem ?

This can be solved by using memmove() function If the same logic is put for memmove(), it works well that is it does not have any memory overlap issue, since in this case, the source are first copied into temporary buffer and then copied to destination.

User-defined memove:

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

void fun(char *dst, char *src, int size)
{
    char *temp = malloc(size);
    int i = 0;
    for (i =0; i<size; i ++)
      temp[i] = *src++;
    
    i =0;
    for ( i =0;i<size; i++)
    dst[i] = temp[i];
    
}

int main()
{
    char src[12]= "techaccess";
    char dst[10];
    fun(src+5, src, 7);
    printf("\n %s", src);
    return 0;
}

Q.73) how we will know that Heap is full?

Heap area of memory is responsible for dynamic memory allocation. This allocation is done with the library calls that is malloc.

This library call may fail in the below scenarios:

  • If the memory asked for allocation in a single attempt is more than the implementation logic for malloc. It’s a kind of input validation failure
  • If the system is running low on memory or process has exceeded its maximum segment size. The process is out of virtual memory that is mapping to actual memory demanded is too large.
  • If we pass 0 as the number of bytes to be allocated, but it depends upon implementation, in few case it may return special pointer.

Thus once we allocate memory and if malloc fails then one of the reason for failure may be Heap area of memory is full.

Q.74) what is core dump, state its usefulness?

  • It represents the process address space at the time of program getting terminated unexpectedly.
  • That is what was the stack segment (local variable), data segment, what was the state of the registers that is content of program counter, stack pointer, memory related information.
  • The core dump contains the full image of our application’s address space, including code, stack and heap (malloc’d objects etc.)
  • Thus in short they capture the state of the process at the time of abnormal termination.

Generally, the core dump files are too large, we can set the size with command setrlimit at the risk that core dump may be incomplete.

Few of the important information present are:

  • The processor’s state
  • The processor register’s contents
  • Memory management information
  • The program’s counter and stack pointer
  • Operating system and processor information and flags

It’s very useful while debugging the cause of the abnormal termination of the program that is root cause of program getting crashed.

Q.75) what is wild pointer?

Un-initialized pointers are referred as wild pointers that is they can point to any arbitrary location and accessing such pointer may cause a program to crash or behave abnormally.

Q.76) what is dup() system call?

This is used to create a new file descriptor for the existing file descriptor which is nothing but a copy of the existing FD, hence both the file descriptors can be used interchangeably, and new file descriptor is like an alias to the old one.

They share the file offset and status flags.

int dup (int oldfd);

int dup2 (int oldfd, int newfd);

Q.77) what is stack corruption?

Stack corruption means certain memory location at stack are accessed and modified which should not have been that is unintentional access of memory location of stack. Since the data are corrupted or accessed at stack, it is termed as stack corruption.

Few of the scenarios are:

  • In the case of stack overflow that is all the stack memory is eaten up like in the case of recursive function without a proper base condition. Like main function calling to itself.
  • When the array is accessed out of bound, it may crash or may give us junk values.
  • Using a pointer which is already freed or with pointer with garbage values.

Q.78) Difference between exit and return 0?

Exit () is used to come out from the program where as we use return statement to return from the function.

Q.79) what is system call and how does it work internally?

System call is like a function which need to be invoked to avail the functionalities which is being provided by the kernel.

Whenever a system call is invoked, the control passes from user space to kernel space. It’s a software interrupt.

Internal working of a system call:

  • As an end user, it is very much like calling a normal function.
  • There is a table maintained in the kernel called system call table where each entry contains the system call number and its corresponding address for system call system routine.
  • A proper system call number along with other arguments must be passed to kernel to invoke the system call routine.
  • A system calls first invoke the C library wrapper function which places the system call number to appropriate register.
  • Same C library then invokes the trap instruction which switches the control from user mode to kernel mode.
  • Once the control reaches the kernel, kernel calls a trap handler whose responsibility is invoke appropriate system call system routine after validating the arguments passed to it.
  • Once the system call system routine is over, the control is passed to trap handler which returns the control back to the wrapper function in the user mode.
  • Based upon the return value from the trap handler, wrapper function sets the error number and returns -1 to indicate any error.

Q.80) what is linking and types of linking?

Linking is one the stage of the compilation where all the different object files and the static libraries are assembled together into a new library or an executable.

The program which does this linking is termed as linker.

For example, in the case of any C program, we have a say header file string.h, this contain the prototype of the function and macro definition that need to be accessed by multiple source files.

There is multiple library function which are present inside this header file such as strcpy (), strcat () which can directly be used in our program by including the appropriate header files.

Thus libraries can be defined as collection of multiple object files that is pre compiled source code which can be used by our program directly by providing reusable function, classes and data structures etc.

Typically, C functions and C++ classes’ methods which can be shared by more than one application are broken out of the application source code and are compiled and bundled into library.

One of the advantages of having library is that we don’t need to state each object separately while linking, we can directly link the library.

Again this library can be of two types:

  • Static library
  • Dynamic libraries

Static libraries:

This is a library of object files which becomes the part of the application. They have the extension that is “.a” file.

This library is resolved at compile time.

One of the example is openssl library that is libcrypto.a which has object files related to encryption and decryption.

Dynamic libraries:

This type of libraries is resolved at run time with the extension “.so” files.

We will see two types of linking in details:

                 Static Linking                Dynamic linking
In static linking, the linking of the libraries is done at the compile time.In this case, the libraries are linked at run time.
In this case the libraries becomes a part of the executables.In this libraries does not become part of the executables, rather it is placed externally at some location, and just the reference is made by our application at run time.
Since the libraries does become part of executables, leading to larger size of executables and thus occupying more space.The size of executables is less and thus occupy less space on memory.
In static, each application will have its own copy of data.Whereas in case of dynamic libraries, each application will access the same libraries places externally.
Static linking is faster as it does not need to resolve any external references and no dynamic querying of any symbols.Whereas in dynamic linking is slower as it has to resolve external references to libraries as they are not part of executables and also involves lot of system calls which is an overhead.
Since the libraries are part of executables, thus we hardly see any compatibility issuesDynamic linked programs are dependent on having a compatible library. Since they are not part of executables, we may face compatibility issue. If the compiler changes the libraries like may be any library function is prototype is changed.
If there is any changes or upgrade of libraries, even the main program need to re-compiled.There is no need to recompile the main program upon upgradation of existing libraries.
This is done by a program called linkerThis is handled by Operating system.

Advantages of Static linking:

  • Static linking is faster than dynamic linking.
  • Since the libraries are part of executables, there is virtually no or rare compatibility issues.

Disadvantages of Static linking:

  • Size is more.
  • Main program need recompiled on making change in libraries.

Advantages of Dynamic Linking:

  • Main program does not need to recompile on making any changes in libraries.
  • Only one copy of the shared library is kept in memory, making it much faster to compile programs and significantly reducing the size of the executable program
  • Dynamic linking load time will be reduced if the shared library code is already present in memory

Disadvantages of dynamic linking:

  • Speed is less because of external references.
  • Potential compatibility issues if a library is changed without recompiling the library into memory

Q.81) what is cross compiler?

A cross compiler is a compiler which is capable of producing an executable for a platform which is different from the one on which it is running. Direct compilation on the target code may not be feasible. It is necessary to produce executables for many platforms from a single development host

Q.82) what is tail recursion?

Tail recursion means the recursive function is at the end of the function that is no more instruction after the recursive call.

Q.83) what is softlink and its advantages?

  • Softlink is like a shortcut that is actual link to the original file.
  • They have a different inode number.
  • They can work even for directories.
  • If the original file is deleted, softlink also becomes inaccessible.
  • Any changes to each other are reflected on others.

Few of the examples are:

  • Creating a shortcut for any directories/files on desktop that is it gives an easy interface for that entity.
  • Suppose we have 3-4 files and each files need to consistent that is must be same, thus making a change in each of these files is time consuming and also becomes practically for large number of files and most important doing such changes on multiple files are prone to errors.
  • We have a softlink for multiple MIB files along with DPAPP folders.

Thus in all such cases we can create softlink.

Q.84) How do u determine the size of structure without using sizeof() operator?

This can be done with the help of a simple C program

#include <stdio.h>

struct student{
    int a;
    char *p;
    char z;
};

int main()
{
    struct student *p =NULL;
    
    p++;
    printf("\n size without sizeof(): %d\n", p);
    printf("\n size with sizeof(): %lu\n",sizeof(struct student));

    return 0;
}

Output:

 size without sizeof(): 24

 size with sizeof(): 24


Categories: Interview Preparation

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: