C Pointer Interview Questions

1) What is a void pointer or generic pointer?
  • void pointer is a generic pointer.
  • void pointer can point to any data type.
  • Any type of address can be assigned to a void pointer.
1.     int *i; float *f; doublt *d;
2.    void *v = i;
3.    v = f;
4.    v = d;
  • As shown in the above code, there is an int pointer, float pointer, and double pointer at line 1.
  • All pointer types can be assigned to void pointer as shown in line 2, 3 and 4.
  • void pointer should not be referenced directly using *v.
  • Typecasting is required to deference void pointer.
1.     int i = 5, k;
2.     int *ip = &i;
3.     void *v = ip;
4.     k = *(int*)v;
  • As shown above in line 4, type casting void pointer to integer pointer to deference it.
2) What is the use of void pointer?
  • Whenever the programmer is not specific about the type of data it has to refer, the void pointer is useful.
  • Ex. In malloc, calloc, realloc library functions, it allocates any data type of memory and returns a pointer to that memory. Now, that pointer is generic as malloc doesn’t know about the type of memory. malloc is just aware of the size of memory, not type. So, it returns void *(generic pointer). While dereferencing that pointer type casting should be done.
  • click here to see manual page of malloc, calloc and realloc, or run command man malloc, man calloc and ma realloc in terminal.
#include <stdio.h>
#include <stdlib.h>

int main()
{
        int *p;
        p = (int*) malloc(5*sizeof(int));
        p[0] = 1;
        p[1] = 2;
        p[2] = 3;
        p[3] = 4;

        printf("value of p[0]-%d, p[1]-%d, p[2]-%d, p[3]-%d\n", p[0], p[1], p[2], p[3]);
}
  • As shown above malloc returns void * but type casted to int * and assigned to p.
  • Allocated a total of 20 bytes of memory, 5*sizeof(int) =. 5*4 = 20(in 64-bit machine).
  • p[0],p[1],p[2],p[3] having 4 bytes each.
  • void pointer is widely used in dynamic data structure as shown in the above example.
3) What is the o/p of the below program in a 64-bit system?
#include<stdio.h>

int main()
{
        printf("%lu %lu %lu %lu %lu %lu %lu %lu %lu\n", sizeof(int), sizeof(char), sizeof(float), sizeof(double), sizeof(int *), sizeof(char *), sizeof(float *), sizeof(double *), sizeof(void *));
}
  • A) 4 1 4 8 8 8 8 8 8
  • B) 4 1 4 8 4 4 4 4 4

Correct Answer is : A

  • sizeof(int) and sizeof(float) = 4 bytes in a 64-bit machine.
  • sizeof(char) is 1 byte always.
  • sizeof(double) is 8 bytes in a 64-bit machine.
  • sizeof(pointer), the size of any type on the pointer in the 64-bit machine is 8 bytes. Even if it is a char type pointer, int type pointer, float type, double type, or void pointer. The size of the pointer variable is always the same.

4) Explain call by value and call by reference with examples.
//call by value
#include <stdio.h>

void swap(int a, int b)
{
        a = a + b;
        b = a - b;
        a = a - b;
        printf("In swap a=%d, b=%d\n", a, b);
}

int main()
{
        int a = 10, b = 20;
        swap(a,b);
        printf("In main After swap a=%d, b=%d\n", a, b);
}

o/p: 
In swap a=20, b=10
In main After swap a=10, b=20
  • call by value means passing directly variables as an argument to the function.
  • As shown in the above example, passed a and b directly to the function swap.
//call by reference
#include <stdio.h>

void swap(int *a, int *b)
{
        *a = *a + *b;
        *b = *a - *b;
        *a = *a - *b;
        printf("In swap a=%d, b=%d\n", *a, *b);
}

int main()
{
        int a = 10, b = 20;
        swap(&a,&b);
        printf("In main After swap a=%d, b=%d\n", a, b);
}

o/p:
In swap a=20, b=10
In main After swap a=20, b=10
  • call by reference means passing pointers/references of variables as an argument to the function.
  • As shown in the above example, passed addresses of a and b to the function swap.
5) What are the advantages of call-by-reference?
  • The first advantage is shown in the above examples. Values of function arguments can be updated in the calling function without returning.
  • In case of call by value.
    • If the swap function has to return two values to the function main, then it is not possible easily using call by value.
    • Value is swapped but those values are not updated in the main function.
  • In case of a call by reference.
    • Whatever value changes happen to the variables ‘a’ and ‘b’ in the swap function are updated in the main function as well.
    • Without returning values of ‘a’ and ‘b’, those are updated in the calling function.
  • The second advantage is Memory saving on the stack.
  • Passing function arguments consumes space on the called function stack.
  • If a large array or structure is passed as a function argument then it consumes that much stack memory for that called function.
  • let’s understand with below example.
#include<stdio.h>

struct ek{
char a[1000];
};

void fun_call_by_value(struct ek sa)
{
        printf("call by value %lu\n", sizeof(s));
}
void fun_call_by_ref(struct ek *sr)
{
        printf("call by reference %lu\n", sizeof(s));
}
int main()
{
        struct ek s;
        fun_call_by_value(s);
        fun_call_by_ref(&s);

}

o/p:

call by value 1000
call by reference 8
  • In the case of call by value, a structure that contains an array of 1000 is passed as a function argument. which consumes 1000 bytes of space in the stack of “fun_call_by_value”. if need to update structure values to the calling(main) function, the return also consumes space on the stack.
  • In the case of call by reference, the pointer of structure is passed as a function argument. which can consume only 8 bytes, And also no need to return if a programmer wants to update structure values to the calling(main) function. Because pointer “sr”(in fun_call_by_ref) refers to the same location as variable “s” of the main function.
  • Thus space is saved on the stack for called function in case of call by reference.
6) What are the advantages of call by value? or when call by value is preferred over a call by reference? What are the disadvantages of call by reference and how to overcome it?
  • Call by value:
    • Direct variables are passed as a function argument. Change of those variables in the called function doesn’t affect in calling function.
    • When there is small data or small variables that need to pass as a function argument and there is no need to update the change of data in the called function to the calling function then always call by values is safer and easy to implement.
  • Call by reference:
    • Variables addresses are passed as function arguments. Change of those variables in the called function affects in calling function’s original data.
    • If multiple variables are passed as a call by reference in multiple functions, those functions modify the values of those variables, then It is difficult to track which function has modified those.
    • It is directly modifying the original data which can be risky sometimes as the original data is modified by a called function. Need to handle this carefully as a programmer.
    • Whenever big data needs to pass as a function argument but no need to affect the original data in the calling function then use the const keyword which can be safer.
7) What is the dangling pointer?
int *ptr = (int*)malloc(sizeof(int)*5);
free(ptr);
  • As shown in the above example, ptr is pointing to the memory of 5 integers allocated by malloc.
  • ptr memory is deallocated using free.
  • But, ptr is pointing to the same memory which is deallocated.
  • Now if we deference ptr then it gives unpredictable behavior, memory corruption or the program may crash.
  • Pointer ptr is called a dangling pointer.
  • Memory is deallocated but the pointer is pointing to the same memory, which is not valid memory now. So, this kind of pointer is called a dangling pointer.
8) How to avoid dangling pointers?
  • After deallocating the memory assign pointer with NULL as shown below.
int *ptr = (int*)malloc(sizeof(int)*5);
free(ptr);
ptr = NULL;
  • Or assign that pointer to another location if needed.
  • NULL pointer deference is also a problem but error is predictable. So, better to assign it with NULL.
9) What is the wild pointer?
  • A pointer that is declared but not initialized is called a wild pointer.
  • If a pointer is declared but not initialized then it contains any garbage value.
  • Referencing this kind of pointer is an undefined behavior. in this scenario, may programs can crash.
10) How to avoid a wild pointer?
  • Always initialize to NULL or valid address while declaring the pointer.
  • As shown in the code snippet below, pointer p is initialized with NULL, and pointer q is initialized with the address of variable i.
int *p = NULL, int i;
int *q = &i;

Leave a Comment