c interview questions

C interview questions, your interviewer might ask

Q) What is the difference between const and macro?

Answer:

  1. The const keyword is handled by the compiler, in another hand, a macro is handled by the preprocessor directive.
  2. const is a qualifier that is modified the behavior of the identifier but macro is preprocessor directive.
  3. There is type checking is occurred with a const keyword but does not occur with #define.
  4. const is scoped by C block, #define applies to a file.
  5. const can be passed as a parameter (as a pointer) to the function. In the case of call by reference, it prevents modifying the passed object value.

 

Q) What is a volatile variable in C?

Answer:

The volatile keyword is a type qualifier that prevents the objects from the compiler optimization. According to C standard, an object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. You can also say that the value of the volatile-qualified object can be changed at any time without any action being taken by the code.

If an object is qualified by the volatile qualifier, the compiler reloads the value from memory each time it is accessed by the program that means it prevents from cache a variable into a register. Reading the value from memory is the only way to check the unpredictable change of the value.

 

Q) Can we have a volatile pointer?

Ans:

Yes, we can create a volatile pointer in C language.
int * volatile piData; // piData is a volatile pointer to an integer.

 

Q) The Proper place to use the volatile keyword?

Ans:

Here I am pointing some important places where we need to use the volatile keyword.

  • Accessing the memory-mapped peripherals register or hardware status register.
#define COM_STATUS_BIT  0x00000006

uint32_t const volatile * const pStatusReg = (uint32_t*)0x00020000;


unit32_t GetRecvData()
{
    //Code to recv data
    while (((*pStatusReg)  & COM_STATUS_BIT) == 0)
    {
        // Wait untill flag does not set
    }

    return RecvData;
}
  • Sharing the global variables or buffers between the multiple threads.
  • Accessing the global variables in an interrupt routine or signal handler.
volatile int giFlag = 0;

ISR(void)
{
    giFlag = 1;
}

int main(void)
{

    while (!giFlag)
    {
        //do some work
    }

    return 0;
}

 

 

Q) What is the difference between the const and volatile qualifiers in C?

Answer:

The const keyword is compiler-enforced and says that the program could not change the value of the object that means it makes the object nonmodifiable type.
e.g,
const int a = 0;
if you will try to modify the value of “a”, you will get the compiler error because “a” is qualified with const keyword that prevents to change the value of the integer variable.

In another side volatile prevent from any compiler optimization and says that the value of the object can be changed by something that is beyond the control of the program and so that compiler will not make any assumption about the object.
e.g,
volatile int a;

When the compiler sees the above declaration then it avoids making any assumption regarding the “a” and in every iteration read the value from the address which is assigned to the variable.

 

Q) Can a variable be both constant and volatile in C?

Answer:

Yes, we can use both constant and volatile together. One of the great use of volatile and const keyword together is at the time of accessing the GPIO registers. In the case of GPIO, its value can be changed by the ‘external factors’ (if a switch or any output device is attached with GPIO), if it is configured as an input. In that situation, volatile plays an important role and ensures that the compiler always read the value from the GPIO address and avoid to make any assumption.

After using the volatile keyword, you will get the proper value whenever you are accessing the ports but still here is one more problem because the pointer is not const type so it might be your program change the pointing address of the pointer. So we have to create a constant pointer with the volatile keyword.

Syntax of declaration,

int volatile * const PortRegister;
How to read the above declaration,
int volatile * const PortRegister;
 |     |     |   |    |
 |     |     |   |    +------> PortRegister is a
 |     |     |   +-----------> constant
 |     |     +---------------> pointer to a
 |     +---------------------> volatile
 +---------------------------> integer

 

Consider a simple below example:

#define PORTX 0x00020000 // Address of the GPIO

uint32_t volatile * const pcPortReg = (uint32_t *) PORTX;

The pcPortReg is a constant pointer to a volatile unsigned integer, using *pcPortReg we can access the memory-mapped register.

*pcPortReg = value; // Write value to the port
value = *pcPortReg; // Read value from the port

 

Q) How to set, clear, toggle and checking a single bit in C?

Ans:

Setting N-th Bit

Setting an N-th bit means that if the N-th bit is 0, then set it to 1 and if it is 1 then leave it unchanged. In C, bitwise OR operator (|) use to set a bit of integral data type. As we know that | (Bitwise OR operator) evaluates a new integral value in which each bit position is 1 only when operand’s (integer type) has a 1 in that position.

In simple words, you can say that “Bitwise OR ” of two bits is always one if any one of them is one.

That means,

0 | 0 = 0
1 | 0 = 1
0 | 1 = 1
1 | 1 = 1

 

Algorithm to set the bits:
Number | = (1UL << nth Position);

Clearing a Bit

Clearing a bit means that if N-th bit is 1, then clear it to 0 and if it is 0 then leave it unchanged. Bitwise AND operator (&) use to clear a bit of integral data type. “AND” of two bits is always zero if any one of them is zero.

That means,
0 & 0 = 0
1 & 0 = 0
0 & 1 = 0
1 & 1 = 1

 

Algorithm to clear the bit:

To clear the nth bit, first, you need to invert the string of bits then AND it with the number.

Number  &=  ~(1UL << nth Position);

 

Checking a Bit

To check the nth bit, shift the ‘1’ nth position toward the left and then “AND” it with the number.

An algorithm to check the bit
Bit = Number & (1UL << nth)

 

If you want to learn more about the c language, here 10 Free days  C video course for you.

 

Toggling a Bit

Toggling a bit means that if the N-th bit is 1, then change it to 0 and if it is 0 then change it to 1. Bitwise XOR (^) operator use to toggle the bit of an integral data type. To toggle the nth bit shift the ‘1’ nth position toward the left and “XOR” it.

That means,
0 ^ 0 = 0
1 ^ 0 = 1
0 ^ 1 = 1
1 ^ 1 = 0
An algorithm to toggle the bits
Number  ^=  (1UL << nth Position);

 

Q) Detect if two Integers have opposite Signs (Bit Manipulation)

Ans:

Let the given integers are “a” and “b”. The EX-OR of sign bit (MSB) of “a” and “b” will be 1 if the sign bit of “a” is different from the sign bit of “b”. In other words, we can say, EX-OR of “a” and “b” will be negative if “a” and “b” have the opposite signs.

bool CheckOppositeSign(int a, int b)
{
    bool bRetValue = 0;

    bRetValue = ((a ^ b) < 0); // true if a and b have opposite signs

    return bRetValue;
}

 

Note: bool exists in the current C – C99.

 

Q) Write an Efficient C Program to Reverse Bits of a Number?

Ans:

There are a lot of ways to reverse the bits of a number, here I am describing three general methods to reverse the bits.

Method 1:

In this method, we will check the set bits of num and run the loop through all the bits of an integer. If we find the ith bits of num is set then just put 1 at the ((INT_BITS – 1) – ith ) position of tmp, where INT_BITS is the number of bits of an integer.

#define CHAR_BITS  8  // size of character
#define INT_BITS  ( sizeof(int) * CHAR_BITS)


//bit reversal function
unsigned int ReverseTheBits(unsigned int num)
{
    unsigned int iLoop = 0;
    unsigned int tmp = 0;         //  Assign num to the tmp
    int iNumberLopp = (INT_BITS - 1);

    for(; iLoop < iNumberLopp; ++iLoop)
    {

        if((num & (1 << iLoop))) // check set bits of num
        {
            tmp |= 1 << ((INT_BITS - 1) - iLoop); //putting the set bits of num in tmp
        }
    }

    return tmp;
}

 

Method 2:

It is a simple algorithm to reverse bits of the 32-bit integer. This algorithm uses the eight constant value for reversing the bits and takes five simple steps.

In the below section, I am describing the functioning of each step.

Steps 1:
num = (((num & 0xaaaaaaaa) >> 1) | ((num & 0x55555555) << 1));

This expression used to swap the bits.
Let an example, suppose num is 0100, after the above expression it will be 1000.

Steps 2:
num = (((num & 0xcccccccc) >> 2) | ((num & 0x33333333) << 2));

Above expression uses to swap the 2 bits of a nibble. Suppose num is 10 00, after the above expression, it will be 00 01.

Steps 3:
num = (((num & 0xf0f0f0f0) >> 4) | ((num & 0x0f0f0f0f) << 4));

An expression used to swaps the nibbles. like if num is 0011 0010 then after the above expression it will be 0010 0011.

Steps 4:
num = (((num & 0xff00ff00) >> 8) | ((num & 0x00ff00ff) << 8));

This statement uses to swap the bytes of an integer. Let num is 00001000 00001100, after the above expression, it will be 00001100 00001000.

Steps 5:
((num >> 16) | (num << 16));

The above expression uses to swap the half-word of an integer. Means that if the num is 0000000011001110 1000100100000110 after the above result number will be 1000100100000110 0000000011001110.

//bit reversal function
unsigned int ReverseTheBits(register unsigned int x)
{
    x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
    x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
    x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
    x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));

    return((x >> 16) | (x << 16));

}

 

Third Method:

This is the simplest method to reverse the bits of an integer. In which we create a table of the hex value from 0 to 255. In this method, we are performing the AND operation of data with 0xFF to calculate the index of the array.

In this algorithm, we need to calculate the index of the array (look-up table) four times to get the appropriate value from the look-up table. After getting the corresponding value, we will perform the bit shifting operation to get the reverse value.

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

#define CHAR_BITS  8  // size of character

#define INT_BITS  ( sizeof(int) * CHAR_BITS)


//print data in binary
void PrintInBinary(unsigned n)
{
    short int iPos;

    for (iPos = (INT_BITS -1) ; iPos >= 0 ; iPos--)
    {
        (n & (1 << iPos))? printf("1"): printf("0");
    }

}

//Fastest (lookup table):

static const unsigned char TableBitReverse[] =
{
    0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
    0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
    0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
    0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
    0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
    0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
    0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
    0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
    0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
    0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
    0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
    0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
    0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
    0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
    0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
    0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};

int main()
{
    unsigned int data = 0;
    unsigned int Ret = 0;

    printf("Enter the number : ");
    scanf("%u",&data);


    printf("\n\nEntered Data is " );
    PrintInBinary(data);

    //Getting reverse value
    Ret =    (TableBitReverse[data & 0xff] << 24) |
             (TableBitReverse[(data >> 8) & 0xff] << 16) |
             (TableBitReverse[(data >> 16) & 0xff] << 8) |
             (TableBitReverse[(data >> 24) & 0xff]);

    printf("\n\nReverse Data is " );
    PrintInBinary(Ret);

    return 0;
}

 

Q) How to print a decimal number in binary format in C?

Ans:

#define CHAR_BITS  8  // size of character
#define INT_BITS  ( sizeof(int) * CHAR_BITS) //bits in integer


void PrintInBinary(unsigned n)
{
    char Pos = (INT_BITS -1);

    for (; Pos >= 0 ; --Pos)
    {
        (n & (1 << Pos))? printf("1"): printf("0");
    }

}

 

Q) What is the output of the below program?

#include <stdio.h>

int main()
{
    int data = 16;

    data = data >> 1;

    printf("%d\n", data );
    
    return 0;
}

Ans:

8

 

Q) What is the output of the below program?

#include <stdio.h>

int main()
{
    int c = 8 ^7;

    printf("%d\n", c);
}

Ans:

15

 

Q) What is the output of the below program?

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

int main()
{
    void *pvBuffer = NULL;

    pvBuffer = malloc(sizeof(int));

    *((int*)pvBuffer) = 0x00000000;

    *((int*)pvBuffer)|= 2;

    printf("OutPut = %d",*((int*)pvBuffer));

    free(pvBuffer);
    return 0;
}

Ans:

2

 

Q) Write a program swap two numbers without using the third variable?

Ans:

Let’s assume a, b two numbers, there are a lot of methods two swap two numbers without using the third variable.

Method 1( (Using Arithmetic Operators):

#include <stdio.h>

int main()
{
    int a = 10, b = 5;

    // algo to swap 'a' and 'b'
    a = a + b;  // a becomes 15
    b = a - b;  // b becomes 10
    a = a - b;  // fonally a becomes 5

    printf("After Swapping the value of: a = %d, b = %d\n\n", a, b);

    return 0;
}

 

Method 2 (Using Bitwise XOR Operator):

#include <stdio.h>

int main()
{
    int a = 10, b = 5;

    // algo to swap 'a' and 'b'
    a = a ^ b;  // a becomes (a ^ b)
    b = a ^ b;  // b = (a ^ b ^ b), b becomes a
    a = a ^ b;  // a = (a ^ b ^ a), a becomes b

    printf("After Swapping the value of: a = %d, b = %d\n\n", a, b);

    return 0;
}

 

Q) Write a program to check an integer is a power of 2?

Ans:

Here, I am writing a small algorithm to check the power of 2. If a number is a power of 2, function return 1.

int CheckPowerOftwo (unsigned int x)
{
  return ((x != 0) && (!(x & (x - 1))));
}

 

or

int CheckPowerOftwo (unsigned int x)
{
  return (x  && (!(x & (x - 1))));
}

 

Q) What is the output of the below code?

#include <stdio.h>

int main()
{
    int x = -30;

    x = x << 1;

    printf("%d\n", x);
}

Ans:

undefined behavior.

 

Q) What is the output of the below code?

#include <stdio.h>

int main()
{
    int x = -30;

    x = x >> 1;

    printf("%d\n", x);

    return 0;
}

Ans:

implementation-defined.

 

Q) Write a program to count set bits in an integer?

Ans:

unsigned int NumberSetBits(unsigned int n)
{
    unsigned int CountSetBits= 0;
    while (n)
    {
        CountSetBits += n & 1;
        n >>= 1;
    }
    return CountSetBits;
}

 

Q) When should we use pointers in a C program?

Answer:

  • To pass a large structure liked server request or response packet.
  • To implement the linked list and binary trees.
  • To play with GPIO or hardware register.
  • To get the address or update value from the function (call by reference)
  • To create a dynamic array.
  • To create a call back function using the function pointer.

Note: Besides it, lots of places where the need to use the pointer.

 

Q) What is void or generic pointers in C?

Ans:

A void pointer is a generic pointer. It has no associated data type that’s why it can store the address of any type of object and type-casted to any type.

According to C standard, the pointer to void shall have the same representation and alignment requirements as a pointer to a character type. A void pointer declaration is similar to the normal pointer, but the difference is that instead of data types we use the void keyword.

Syntax:

void * Pointer_Name;

 

Q) What is the advantage of a void pointer in C?

Ans:

There are following advantages of a void pointer in c.

  • Using the void pointer we can create a generic function that can take arguments of any data type. The memcpy and memmove library function are the best examples of the generic function, using these functions we can copy the data from the source to destination.
    e.g.

    void * memcpy ( void * dst, const void * src, size_t num );
  • We have already known that void pointer can be converted to another data type that is the reason malloc, calloc or realloc library function return void *. Due to the void * these functions are used to allocate memory to any data type.
  • Using the void * we can create a generic linked list. For more information see this link: How to create a generic Link List.

 

Q) What are dangling pointers?

Ans:

Generally, daggling pointers arise when the referencing object is deleted or deallocated, without changing the value of the pointers. It creates the problem because the pointer is still pointing the memory that is not available. When the user tries to dereference the daggling pointers than it shows the undefined behavior and can be the cause of the segmentation fault.

For example,

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

int main()
{
    int *piData = NULL;
    //creating integer of size 10.
    piData = malloc(sizeof(int)* 10);
    if(piData == NULL)
    {
        return 0;
    }
    //free the allocated memory
    free(piData);
    //piData is dangling pointer
    *piData = 10;
    
    return 0;
}

In simple word, we can say that dangling pointer is a pointer that not pointing a valid object of the appropriate type and it can be the cause of the undefined behavior.

 

Q) What is the wild pointer?

Ans:

A pointer that is not initialized properly prior to its first use is known as the wild pointer. Uninitialized pointers behavior is totally undefined because it may point some arbitrary location that can be the cause of the program crash, that’s is the reason it is called a wild pointer.

In other words, we can say every pointer in programming languages that are not initialized either by the compiler or programmer begins as a wild pointer.

Note: Generally, compilers warn about the wild pointer.

Syntax,

int *piData; //piData is wild pointer

 

Q) What is a NULL pointer?

Ans:

According to C standard, an integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer.

wild pointerSyntax,

int *piData = NULL; // piData is a null pointer

 

 

Q) What is a Function Pointer?

Ans:

A function pointer is similar to the other pointers but the only difference is that it points to a function instead of the variable.

In the other word, we can say, a function pointer is a type of pointer that store the address of a function and these pointed function can be invoked by function pointer in a program whenever required.

 

Q) How to declare a pointer to a function in c?

Ans:

The syntax for declaring function pointer is very straightforward. It seems difficult in beginning but once you are familiar with function pointer then it becomes easy.

The declaration of a pointer to a function is similar to the declaration of a function. That means the function pointer also requires a return type, declaration name, and argument list. One thing that you need to remember here is, whenever you declare the function pointer in the program then the declaration name is preceded by the * (Asterisk) symbol and enclosed in parenthesis.

For example,

void ( *fpData )( int );

 

For a better understanding, let’s take an example to describe the declaration of a function pointer in C.
e.g,

void ( *pfDisplayMessage) (const char *);

 

In above expression, pfDisplayMessage is a pointer to a function taking one argument, const char *, and returns void.

When we declare a pointer to function in c then there is a lot of importance of the bracket. If in the above example, I remove the bracket, then the meaning of the above expression will be change and it becomes void *pfDisplayMessage (const char *). It is a declaration of a function that takes the const character pointer as arguments and returns a void pointer.


Q) Where can the function pointers be used?

Ans:

There are a lot of places, where the function pointers can be used. Generally, function pointers are used in the implementation of the callback function, finite state machine and to provide the feature of polymorphism in C language …etc.

 

Q) What is the difference between array and pointer in c?

Ans:

Here is one important difference between array and pointer is the address of the element in an array is always fixed we cannot modify the address at execution time but in the case of pointer we can change the address of the pointer as per the requirement.

Consider the below example:
In the below example when trying to increment the address of the array then we will get the compiler error.

Note: When an array is passed to a function then it decays its pointer to the first element.

 

Q) What is the output of the C programming (Assumed int size is 4bytes)?

#include<stdio.h>

int main()
{
    int (*arr)[5][4];

    //Suppose integer size 4 bytes
    printf("*arr size %d", sizeof(*arr));

    return 0;
}

Ans:

*arr size 80

Explanation:

int (*arr)[5][4] is a pointer to an array. The total number of elements the 4*5 and if integer size is 4 bytes then the size of *arr will be 80.

 

Q) What is static memory allocation and dynamic memory allocation?

Ans:

According to C standard, there are four storage duration, static, thread (C11), automatic, and allocated. The storage duration determines the lifetime of the object.

The static memory allocation:

Static Allocation means, an object has external or internal linkage or declared with static storage-class. It’s initialized only once, prior to program startup and its lifetime is throughout the execution of the program. A global and static variable is an example of static memory allocation.

The dynamic memory allocation:

In C language, there are a lot of library functions (malloc, calloc, or realloc,..) which are used to allocate memory dynamically. One of the problems with dynamically allocated memory is that it is not destroyed by the compiler itself that means it is the responsibility of the user to deallocate the allocated memory.

When we allocate the memory using the memory management function, they return a pointer to the allocated memory block and the returned pointer is pointing to the beginning address of the memory block. If there is no space available, these functions return a null pointer.

 

Q) What is the memory leak in C?

Ans:

A memory leak is a common and dangerous problem. It is a type of resource leak. In C language, a memory leak occurs when you allocate a block of memory using the memory management function and forget to release it.

int main ()
{

    char * pBuffer = malloc(sizeof(char) * 20);

    /* Do some work */

    return 0; /*Not freeing the allocated memory*/
}

 

Note: once you allocate a memory than allocated memory does not allocate to another program or process until it gets free.

 

Q) What is the difference between malloc and calloc?

Ans:

A malloc and calloc are memory management functions. They are used to allocate memory dynamically. Basically, there is no actual difference between calloc and malloc except that the memory that is allocated by calloc is initialized with 0.

In C language,calloc function initialize the all allocated space bits with zero but malloc does not initialize the allocated memory. These both function also has a difference regarding their number of arguments, malloc takes one argument but calloc takes two.




Q) What is the purpose of realloc( )?

Ans:

The realloc function is used to resize the allocated block of memory. It takes two arguments first one is a pointer to previously allocated memory and the second one is the newly requested size.

The realloc function first deallocates the old object and allocates again with the newly specified size. If the new size is lesser to the old size, the contents of the newly allocated memory will be same as prior but if any bytes in the newly created object goes beyond the old size, the values of the exceeded size will be indeterminate.

Syntax:

void *realloc(void *ptr, size_t size);

 

Example code,

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

int main ()
{
    char *pcBuffer = NULL;
    /* Initial memory allocation */
    pcBuffer = malloc(8);
    if(pcBuffer == NULL)
    {
        return 0;
    }

    strcpy(pcBuffer, "aticle");
    printf("pcBuffer = %s\n", pcBuffer);

    /* Reallocating memory */
    pcBuffer = realloc(pcBuffer, 15);

    strcat(pcBuffer, "world");
    printf("pcBuffer = %s\n", pcBuffer);

    //free the allocated memory
    free(pcBuffer);

    return 0;
}

Output:
pcBuffer = aticle
pcBuffer = aticleworld

Note: It should be used for dynamically allocated memory but if a pointer is a null pointer, realloc behaves like the malloc function.

 

Q) What is the return value of malloc (0)?

Ans:

If the size of the requested space is zero, the behavior will be implementation-defined. The return value of the malloc could be a null pointer or it shows the behavior of that size is some nonzero value. It is suggested by the standard to not use the pointer to access an object that is returned by the malloc while size is zero.

 

Q) What is dynamic memory fragmentation?

Ans:

The memory management function is guaranteed that if memory is allocated, then it would be suitably aligned to any object which has the fundamental alignment. The fundamental alignment is less than or equal to the largest alignment that’s supported by the implementation without an alignment specification.

One of the major problems with dynamic memory allocation is fragmentation, basically, fragmentation occurred when the user does not use the memory efficiently. There are two types of fragmentation, external fragmentation, and internal fragmentation.

The external fragmentation is due to the small free blocks of memory (small memory hole) that is available on the free list but the program not able to use it. There are different types of free list allocation algorithms that used the free memory block efficiently.

To understand the external fragmentation, consider a scenario where a program has 3 contiguous blocks of memory and the user frees the middle block of memory. In that scenario, you will not get a memory, if the required block of memory is larger than a single block of memory (but smaller or equal to the aggregate of the block of memory).

External Fragmentation

The internal fragmentation is wasted of memory that is allocated for rounding up the allocated memory and in bookkeeping (infrastructure), the bookkeeping is used to keep the information of the allocated memory.

Whenever we called the malloc function then it reserves some extra bytes (depend on implementation and system) for bookkeeping. This extra byte is reserved for each call of malloc and becomes a cause of the internal fragmentation.

Internal fragmentation

For example,
See the below code, the programmer may think that the system will be allocated 8 *100 (800) bytes of memory but due to bookkeeping (if 8 bytes) system will be allocated 8*100 extra bytes. This is an internal fragmentation, where 50% of the heap waste.

//Only sample code.

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

char *acBuffer[100];

int main()
{
    int iLoop = 0;
    while(iLoop < 100)
    {
        acBuffer[iLoop ] =  malloc(8);
        ++iLoop;
    }
}

 

Q) How is the free work in C?

Ans:

When we call the memory management functions (malloc, calloc or realloc) then these functions keep extra bytes for bookkeeping.

Whenever we call the free function and pass the pointer that is pointing to allocated memory, the free function gets the bookkeeping information and release the allocated memory. Anyhow if you or your program change the value of the pointer that is pointing to the allocated address, the calling of the free function gives the undefined result.

 ____ The allocated block ____
/                             \
+--------+--------------------+
| Header | Your data area ... |
+--------+--------------------+
         ^
         |
       +-- Returned Address

 

For example,

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

int main()
{
    char *pcBuffer = NULL;
    pcBuffer  =  malloc(sizeof(char) *  16); //Allocate the memory

    pcBuffer++; //Increment the pointer

    free(pcBuffer); //Call free function to release the allocated memory

    return 0;
}

 

Q) How can you determine the size of an allocated portion of memory?

Ans:

In C language, we can calculate the size of the static array using the sizeof operator but there is no operator to calculate the size of the dynamically allocated memory.

Mainly there are two ways to get the size of allocated memory in every section of the code.

  • Create a global variable to store the size of the allocated memory.
  • Carry the length of allocated memory.

For example,

Suppose you need to create an integer array whose size is n. So to carry the array length of the array, you need to allocate the memory for n+1.

int *piArray = malloc ( sizeof(int) * (n+1) );

If memory is allocated successfully, assign n (size of the array) its 0 places.

piArray[0] = n;
    or
* piArray = n;

 

Now it’s time to create a copy of the original pointer but to left one location from the beginning.

int * pTmpArray = piArray +1;

Note: if you are new, see this article arithmetic operation on the pointer.

Now, whenever in a program you ever required the size of the array then you can get from copy pointer.

ArraySize = pTmpArray[-1];

 

After using the allocated memory don’t forget to deallocate the allocated memory.

free (piArray);

 

 

Q) What is the output of the below C code?

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

#define ALLOC_MEMORY 5

int main()
{
    int loop = 0;
    int *ptr = malloc(ALLOC_MEMORY *sizeof(int));
    if(ptr == NULL)
    {
        perror("fail to allocate memory");
        return -1;
    }

    for(loop=0; loop < ALLOC_MEMORY; ++loop)
    {
        *(ptr + loop) = loop;
    }

    printf(" %d",*ptr++);
    printf(" %d",(*ptr)++);
    printf(" %d",*ptr);
    printf(" %d",*++ptr);
    printf(" %d",++*ptr);

    free(ptr);

    return 0;
}

Ans:

0 1 2 2 3

Explanation:

1st printf:- *ptr++ means that it will increment the address and dereference that address but here the increment is a post increment so dereference first and after increment, so on the base address you get 0 (ptr is pointing to next location).

2nd printf:- (*ptr)++ = first dereference and than increment the value so on that location value is 1 is one is increment so you get 2 ( here pointer is not changed).

3rd printf:- *ptr mean when the pointer is pointing do dereference on that location so you get 2.

4th printf:- *++ptr mean the first pointer is increment after dereferencing so you get 2 (pointer is changed).

5th printf:- ++*ptr mean first dereference and than increment the value so you get as 3

 

 

Go C Interview Questions PART-3       

Go C Interview Questions PART-1

 

Recommended Articles for you: