C Interview Questions for Developers

Use our engineer-created questions to interview and hire the most qualified C developers for your organization.

C

Despite its age — it has been around since the 1970’s — C continues to be a popular first-time programming language and is used in a range of applications of every type, from game development to systems programming and embedded systems.

According to the CoderPad 2023 Developer survey, C is the 8th most in-demand language among technical recruiters and hiring managers.

We have developed practical coding tasks and interview questions tailored to evaluate developers’ C skills during coding interviews. Furthermore, we have compiled a set of best practices to ensure that your interview questions accurately gauge the candidates’ proficiency in C.

C example question

Help us design a parking lot

Hey candidate! Welcome to your interview. Boilerplate is provided. Feel free to change the code as you see fit. To run the code at any time, please hit the run button located in the top left corner.

Goals: Design a parking lot using object-oriented principles

Here are a few methods that you should be able to run:

  • Tell us how many spots are remaining
  • Tell us how many total spots are in the parking lot
  • Tell us when the parking lot is full
  • Tell us when the parking lot is empty
  • Tell us when certain spots are full e.g. when all motorcycle spots are taken
  • Tell us how many spots vans are taking up

Assumptions:

  • The parking lot can hold motorcycles, cars and vans
  • The parking lot has motorcycle spots, car spots and large spots
  • A motorcycle can park in any spot
  • A car can park in a single compact spot, or a regular spot
  • A van can park, but it will take up 3 regular spots
  • These are just a few assumptions. Feel free to ask your interviewer about more assumptions as needed

Junior C interview questions

Question:
What is the purpose of the #include directive in C, and how is it used?

Answer:
The #include directive is used to include header files in a C program. Header files contain declarations of functions, variables, and data types that are used in the program. The #include directive allows us to reuse code from other files by including their header files in our program.

Question:
There is a bug in the following code that is causing a segmentation fault. Can you identify and fix it?

#include <stdio.h>

int main() {
    int arr[5];

    for (int i = 0; i <= 5; i++) {
        arr[i] = i;
    }

    for (int i = 0; i <= 5; i++) {
        printf("%d ", arr[i]);
    }

    return 0;
}Code language: PHP (php)

Answer:
The bug in the code is an out-of-bounds access when assigning values to the arr array. In C, array indices start from 0, so the valid indices for an array of size 5 are from 0 to 4. To fix the code, we need to change the condition in both loops to i < 5 to stay within the bounds of the array.

#include <stdio.h>

int main() {
    int arr[5];

    for (int i = 0; i < 5; i++) {
        arr[i] = i;
    }

    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }

    return 0;
}Code language: PHP (php)

Question:
What is the difference between the malloc() and calloc() functions in C for dynamic memory allocation?

Answer:
The malloc() function is used to dynamically allocate memory in C. It takes the size of the memory block to allocate as a parameter and returns a pointer to the allocated memory. The malloc() function does not initialize the allocated memory, so the contents of the allocated memory block are undefined.

The calloc() function, on the other hand, is also used for dynamic memory allocation. It takes two parameters: the number of elements to allocate and the size of each element. The calloc() function initializes the allocated memory to zero, unlike malloc().

Question:
The following code is intended to swap the values of two variables. Identify and fix the issue.

#include <stdio.h>

void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 5;
    int y = 10;

    swap(x, y);

    printf("x = %d, y = %d", x, y);

    return 0;
}Code language: PHP (php)

Answer:
The issue with the code is that the swap() function is using pass-by-value, so the modifications made to a and b within the function do not affect the original variables x and y in the main() function. To fix this, we need to use pass-by-reference by passing the addresses of x and y to the swap() function using pointers.

#include <stdio.h>

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5;


 int y = 10;

    swap(&x, &y);

    printf("x = %d, y = %d", x, y);

    return 0;
}Code language: PHP (php)

Question:
What is the purpose of the typedef keyword in C, and how is it used?

Answer:
The typedef keyword in C is used to create an alias or a new name for an existing data type. It allows us to define custom type names that are more meaningful and self-explanatory. The typedef keyword is typically used in conjunction with structure, union, and enum declarations, but it can also be used with basic data types.

For example, we can use typedef to create a new name for int called CustomInt:

typedef int CustomInt;

After this typedef, CustomInt can be used as a synonym for int, and variables of type CustomInt can be declared.

Question:
The following code is intended to print all the even numbers between 1 and 10. Identify and fix the issue.

#include <stdio.h>

int main() {
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0)
            printf("%d ", i);
    }

    return 0;
}Code language: PHP (php)

Answer:
The issue with the code is that the printf() statement is not enclosed in curly braces, so only the immediately following statement is considered part of the loop. To fix this, we need to add curly braces around the printf() statement to ensure that it is executed for each iteration of the loop.

#include <stdio.h>

int main() {
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0) {
            printf("%d ", i);
        }
    }

    return 0;
}Code language: PHP (php)

Question:
What is the purpose of the sizeof operator in C, and how is it used?

Answer:
The sizeof operator in C is used to determine the size, in bytes, of a data type or a variable. It can be used to calculate the memory space occupied by a particular data type or to allocate the appropriate amount of memory dynamically.

For example, to determine the size of an integer (int), we can use sizeof(int), and to determine the size of a variable x, we can use sizeof(x).

Question:
Fix the code: The following code is intended to calculate the factorial of a number. Identify and fix the issue.

#include <stdio.h>

int factorial(int n) {
    if (n == 0)
        return 1;
    else
        return n * factorial(n - 1);
}

int main() {
    int num = 5;
    int result = factorial(num);

    printf("Factorial of %d is %dn", num, result);

    return 0;
}Code language: PHP (php)

Answer:
The code has a correct implementation for calculating the factorial of a number. However, there is no base case or handling for negative numbers. To fix this, we can add a check for negative numbers and return an error condition or handle it appropriately.

#include <stdio.h>

int factorial(int n) {
    if (n < 0) {
        printf("Error: Factorial not defined for negative numbersn");
        return -1; // or any other appropriate error value
    }
    else if (n == 0)
        return 1;
    else
        return n

 * factorial(n - 1);
}

int main() {
    int num = 5;
    int result = factorial(num);

    if (result != -1) {
        printf("Factorial of %d is %dn", num, result);
    }

    return 0;
}Code language: PHP (php)

Question:
What is the difference between ++i and i++ in C?

Answer:
Both ++i and i++ are increment operators in C. The difference lies in their behavior:

  • ++i is the pre-increment operator. It increments the value of i and then evaluates to the incremented value.
  • i++ is the post-increment operator. It increments the value of i but evaluates to the original value before the increment.

For example, if i is 5, then ++i would evaluate to 6 and i++ would evaluate to 5. The value of i after these operations would be 6 in both cases.

Question:
Fix the code: The following code is intended to print the ASCII values of lowercase letters. Identify and fix the issue.

#include <stdio.h>

int main() {
    char letter = 'a';

    while (letter <= 'z') {
        printf("ASCII value of %c is %dn", letter, letter);
        letter++;
    }

    return 0;
}Code language: PHP (php)

Answer:
The issue with the code is that the format specifier %d is used to print the ASCII value of the letter variable. However, the %c format specifier should be used to print the actual character. To fix this, we need to change the format specifier to %c in the printf() statement.

#include <stdio.h>

int main() {
    char letter = 'a';

    while (letter <= 'z') {
        printf("ASCII value of %c is %cn", letter, letter);
        letter++;
    }

    return 0;
}Code language: PHP (php)

These questions cover the basics of C and should provide a good starting point for a junior C developer.

Intermediate C interview questions

Question:
What is a function pointer in C? Provide an example of how it can be used.


Answer:
A function pointer is a variable that stores the address of a function in C. It allows us to call a function indirectly by using the function pointer. Here’s an example:

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int main() {
    int (*funcPtr)(int, int) = add; // Declare and initialize a function pointer

    int result = funcPtr(2, 3); // Call the function using the function pointer

    printf("Result: %dn", result);

    return 0;
}Code language: C/AL (cal)


In this example, we declare a function pointer funcPtr that points to the add function. We can then use the function pointer to call the add function indirectly by dereferencing and invoking the function pointer.

Question:
The following code is intended to swap the values of two variables using pointers. Identify and fix the issue.

#include <stdio.h>

void swap(int* a, int* b) {
    int* temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 5;
    int y = 10;

    swap(&x, &y);

    printf("x = %d, y = %dn", x, y);

    return 0;
}Code language: C/AL (cal)


Answer:
The issue with the code is that the `swap()` function is using pointers, but the pointers `a` and `b` are being reassigned to each other instead of swapping the values they point to. To fix this, we need to dereference the pointers and swap the values they point to.

#include <stdio.h>

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5;
    int y = 10;

    swap(&x, &y);

    printf("x = %d, y = %dn", x, y);

    return 0;
}Code language: C/AL (cal)


Question:
Explain the concept of dynamic memory allocation in C. How is it different from static memory allocation?

Answer:
Dynamic memory allocation in C allows us to allocate memory at runtime, rather than at compile-time like static memory allocation. It enables us to allocate memory dynamically based on the program’s needs.

In C, dynamic memory allocation is done using the malloc(), calloc(), and realloc() functions from the <stdlib.h> library. These functions allow us to allocate and deallocate memory as needed, using the heap.

Static memory allocation, on the other hand, occurs at compile-time and involves allocating memory for variables and arrays using keywords like int, char, or float within the program. The allocated memory remains fixed during the execution of the program.

Question:
The following code is intended to read a string of characters from the user. Identify and fix the issue.

#include <stdio.h>

#define MAX_SIZE 20

int main() {
    char str[MAX_SIZE];

    printf("Enter a string: ");
    gets(str);

    printf("Entered string: %sn", str);

    return 0;
}
Code language: C/AL (cal)


Answer:
The issue with the code is that the gets() function is used to read a string from the user, which is considered unsafe and deprecated due to the risk of buffer overflow. To fix this, we can use the safer alternative fgets() function.

#include <stdio.h>

#define MAX_SIZE 20

int main() {
    char str[MAX_SIZE];

    printf("Enter a string: ");
    fgets(str, MAX_SIZE, stdin);

    printf("Entered string: %sn", str);

    return 0;
}Code language: C/AL (cal)


Question:
What is the purpose of the volatile keyword in C? Provide an example scenario where it can be useful.

Answer:
The volatile keyword in C is used to indicate that a variable’s value can be changed unexpectedly by external sources, such as hardware or concurrent threads. It tells the compiler not to optimize or cache the variable.

One scenario where volatile can be useful is when working with memory-mapped I/O devices. The values of such devices can change asynchronously, and using the volatile keyword ensures that the compiler always fetches the latest value from memory instead of using a cached value.

#include <stdio.h>

volatile int* deviceAddress = (int*)0x12345678; // Memory-mapped I/O device address

int main() {
    int value = *deviceAddress; // Read the value from the device

    printf("Value: %dn", value);

    return 0;
}Code language: C/AL (cal)


In this example, deviceAddress is declared as a volatile pointer to an int, indicating that the value at that memory location can change unexpectedly. By using the volatile keyword, we ensure that the latest value is always read from the device.

Question:
The following code is intended to find the length of a string. Identify and fix the issue.

#include <stdio.h>

int stringLength(char str[]) {
    int length = 0;

    while (str[length] != "")
        length++;

    return length;
}

int main() {
    char str[] = "Hello, World!";
    int length = stringLength(str);
    printf("Length: %d\n", length);
    return 0;
}Code language: C/AL (cal)


Answer:

Strings in C are mainly arrays of characters, with the null character '\0' to indicate where the string ends.

The function stringLength tries to compare a single character (str[length]) with the value "". This value is an empty string: an array of character whose first element is the null character.

Comparing a single character with an array of characters may end with unpredictable results. The correct way is to compare two single characters, one of them is the null character : '\0'

#include <stdio.h>

int stringLength(char str[]) {
    int length = 0;

    while (str[length] != '\0')
        length++;

    return length;
}

int main() {
    char str[] = "Hello, World!";
    int length = stringLength(str);
    printf("Length: %d\n", length);
    return 0;
}Code language: C/AL (cal)


Question:
Explain the concept of recursion in C. Provide an example of a recursive function.

Answer:
Recursion is a programming technique where a function calls itself to solve a problem by breaking it down into smaller subproblems. In C, a recursive function consists of a base case and a recursive case.

Here’s an example of a recursive function to calculate the factorial of a number:

#include <stdio.h>

int factorial(int n) {
    if (n == 0)
        return 1;
    else
        return n * factorial(n - 1);
}

int main() {
    int num = 5;
    int result = factorial(num);

    printf("Factorial of %d is %dn", num, result);

    return 0;
}Code language: C/AL (cal)


In this example, the factorial() function calls itself with a smaller value (n - 1) until it reaches the base case (n == 0). The function calculates the factorial by multiplying n with the factorial of n - 1.

Question:
Fix the code: The following code is intended to reverse an integer array. Identify and fix the issue.

#include <stdio.h>

#define SIZE 6

void reverseArray(int arr[], int size) {
    int temp;
    for (int i = 0; i <= size / 2; i++) {
        temp = arr[i];
        arr[i] = arr[size - i];
        arr[size - i] = temp;
    }
}

int main() {
    int arr[SIZE] = {1, 2, 3, 4, 5, 6};

    reverseArray(arr, SIZE);

    printf("Reversed array: ");
    for (int i = 0; i < SIZE; i++)
        printf("%d ", arr[i]);

    printf("\n");
    return 0;
}
Code language: C/AL (cal)

Answer:
The issue with the code is that the loop in the reverseArray() function swaps elements incorrectly. The loop should iterate until i < size / 2, not i <= size / 2. Additionally, when swapping the elements, the index for the second element should be size - i - 1, not size - i. These fixes ensure that the swapping is done correctly.

#include <stdio.h>

#define SIZE 6

void reverseArray(int arr[], int size) {
    int temp;
    for (int i = 0; i < size / 2; i++) {
        temp = arr[i];
        arr[i] = arr[size - i - 1];
        arr[size - i - 1] = temp;
    }
}

int main() {
    int arr[SIZE] = {1, 2, 3, 4, 5, 6};

    reverseArray(arr, SIZE);

    printf("Reversed array: ");
    for (int i = 0; i < SIZE; i++)
        printf("%d ", arr[i]);

    printf("\n");
    return 0;
}
Code language: C/AL (cal)

Question:
Explain the concept of pointers in C. Provide an example of how pointers can be used to pass values by reference.

Answer:
Pointers in C are variables that store memory addresses. They allow us to indirectly access and manipulate data in memory. Pointers are useful for tasks like dynamic memory allocation, passing values by reference, and working with complex data structures.

Here’s an example of using pointers to pass values by reference:

#include <stdio.h>

void increment(int* num) {
    (*num)++;
}

int main() {
    int value = 5;

    printf("Before increment: %dn", value);

    increment(&value);

    printf("After increment: %dn", value);

    return 0;
}Code language: C/AL (cal)


In this example, the increment() function takes a pointer to an integer as a parameter. Inside the function, the value at the memory address pointed to by num is incremented by dereferencing the pointer. By passing the address of value using the & operator, we can modify the original value directly.

Question:
Fix the code: The following code is intended to check if a number is prime. Identify and fix the issue.

#include <stdio.h>
#include <stdbool.h>

bool isPrime(int num) {
    if (num < 2)
        return false;

    for

 (int i = 2; i < num; i++) {
        if (num % i == 0)
            return false;
    }

    return true;
}

int main() {
    int number = 17;

    if (isPrime(number))
        printf("%d is prime.n", number);
    else
        printf("%d is not prime.n", number);

    return 0;
}Code language: C/AL (cal)


Answer:
The issue with the code is in the for loop condition inside the isPrime() function. The loop should iterate until i <= num / 2, not i < num. Additionally, there is an optimization we can make to stop the loop earlier by checking until the square root of num.

#include <stdio.h>
#include <stdbool.h>
#include <math.h>

bool isPrime(int num) {
    if (num < 2)
        return false;

    for (int i = 2; i <= sqrt(num); i++) {
        if (num % i == 0)
            return false;
    }

    return true;
}

int main() {
    int number = 17;

    if (isPrime(number))
        printf("%d is prime.n", number);
    else
        printf("%d is not prime.n", number);

    return 0;
}
Code language: C/AL (cal)


In this corrected code, the isPrime() function uses the sqrt() function from the <math.h> library to limit the loop condition, improving the efficiency of prime number checking.

Senior C interview questions

Question:
The following code is intended to swap two integers using bitwise XOR. Identify and fix the issue.

#include <stdio.h>

void swap(int a, int b) {
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

int main() {
    int x = 10, y = 20;

    printf("Before swap: x = %d, y = %dn", x, y);

    swap(x, y);

    printf("After swap: x = %d, y = %dn", x, y);

    return 0;
}Code language: PHP (php)

Answer:
The issue with the code is that the swap() function is swapping the values of the local variables a and b, not the original variables x and y. To fix this, we need to pass the addresses of x and y as pointers and dereference them in the swap() function.

#include <stdio.h>

void swap(int* a, int* b) {
    *a = *a ^ *b;
    *b = *a ^ *b;
    *a = *a ^ *b;
}

int main() {
    int x = 10, y = 20;

    printf("Before swap: x = %d, y = %dn", x, y);

    swap(&x, &y);

    printf("After swap: x = %d, y = %dn", x, y);

    return 0;
}Code language: PHP (php)

In this corrected code, the swap() function takes pointers to a and b as parameters. By dereferencing the pointers using the * operator, we can modify the values of x and y directly.

Question:
Explain the concept of dynamic memory allocation in C. Provide an example of dynamically allocating memory for an integer array.

Answer:
Dynamic memory allocation in C allows programs to allocate memory at runtime as opposed to compile time. It is useful when the size of data structures or arrays is unknown or needs to be determined dynamically.

Here’s an example of dynamically allocating memory for an integer array:

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

int main() {
    int size;
    printf("Enter the size of the array: ");
    scanf("%d", &size);

    int* arr = (int*)malloc(size * sizeof(int));

    if (arr == NULL) {
        printf("Memory allocation failed.n");
        return 1;
    }

    for (int i = 0; i < size; i++) {
        printf("Enter element %d: ", i);
        scanf("%d", &arr[i]);
    }

    printf("Array elements: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }

    free(arr);

    return 0;
}Code language: PHP (php)

In this example, the program asks the user to enter the size of the array. It then dynamically allocates memory using malloc() and assigns the starting address of the allocated memory to the pointer variable arr. The user is prompted to enter the elements of the array, which are stored in the dynamically allocated memory. Finally, the memory is freed using free() to prevent memory leaks.

Question:
The following code is intended to read a binary file and print its contents as hexadecimal. Identify and fix the issue.

#include <stdio.h>

int main() {
    FILE* file = fopen

("data.bin", "rb");

    if (file == NULL) {
        printf("Failed to open the file.n");
        return 1;
    }

    unsigned char buffer[16];
    int bytesRead;

    while ((bytesRead = fread(buffer, sizeof(char), 16, file)) != 0) {
        for (int i = 0; i < bytesRead; i++) {
            printf("%02X ", buffer[i]);
        }

        printf("n");
    }

    fclose(file);

    return 0;
}Code language: PHP (php)

Answer:
The issue with the code is that the file is not closed if an error occurs during the fread() operation. To fix this, we need to add a fclose() statement inside the if block where the file is checked for NULL.

#include <stdio.h>

int main() {
    FILE* file = fopen("data.bin", "rb");

    if (file == NULL) {
        printf("Failed to open the file.n");
        return 1;
    }

    unsigned char buffer[16];
    int bytesRead;

    while ((bytesRead = fread(buffer, sizeof(char), 16, file)) != 0) {
        for (int i = 0; i < bytesRead; i++) {
            printf("%02X ", buffer[i]);
        }

        printf("n");
    }

    fclose(file);

    return 0;
}Code language: PHP (php)

In this corrected code, the fclose() function is called before the program exits in both the normal execution path and the error path, ensuring that the file is closed in all cases.

Question:
Explain the concept of a linked list in C. Provide an example of creating a linked list and traversing its elements.

Answer:
A linked list is a data structure that consists of nodes where each node contains a value and a pointer to the next node. The last node points to NULL, indicating the end of the list. Linked lists provide dynamic memory allocation, efficient insertions and deletions, and flexible size.

Here’s an example of creating a linked list and traversing its elements:

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

typedef struct Node {
    int data;
    struct Node* next;
} Node;

void printList(Node* head) {
    Node* current = head;
    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("n");
}

int main() {
    Node* head = NULL;
    Node* second = NULL;
    Node* third = NULL;

    head = (Node*)malloc(sizeof(Node));
    second = (Node*)malloc(sizeof(Node));
    third = (Node*)malloc(sizeof(Node));

    head->data = 1;
    head->next = second;

    second->data = 2;
    second->next = third;

    third->data = 3;
    third->next = NULL;

    printList(head);

    free(head);
    free(second);
    free(third);

    return 0;
}Code language: PHP (php)

In this example, we define a Node struct that contains an integer data field and a pointer to the next node. We create three nodes dynamically using malloc() and assign values to their data fields. We link the nodes together by setting the next pointers accordingly. Finally, we pass the head of the linked list to the printList() function, which traverses the list and prints the values. We must remember to free the dynamically allocated memory using free() to avoid memory leaks.

Question:
The following code is intended to sort an array of integers in ascending order using the bubble sort algorithm. Identify and fix the issue.

#include <stdio.h>

void bubbleSort(int arr[], int size) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = 0; j < size - i; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

int main() {
    int arr[] = {5, 2, 8, 1, 6};
    int size = sizeof(arr) / sizeof(arr[0]);

    printf("Before sorting: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }

    bubbleSort(arr, size);

    printf("nAfter sorting: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }

    return 0;
}Code language: PHP (php)

Answer:
The issue with the code is in the inner loop condition of the bubbleSort() function. The loop should iterate until j < size - i - 1, not j < size - i. This is because we are accessing arr[j + 1] in the loop body, so we need to ensure that j + 1 is a valid index.

#include <stdio.h>

void bubbleSort(int arr[], int size) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = 0; j < size - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

int main() {
    int arr[] = {5, 2, 8, 1, 6};
    int size = sizeof(arr) / sizeof(arr[0]);

    printf("Before sorting: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }

    bubbleSort(arr, size);

    printf("nAfter sorting: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }

    return 0;
}Code language: PHP (php)

In this corrected code, the inner loop condition is fixed to j < size - i - 1, ensuring that we don’t access elements beyond the array boundaries.

Question:
Explain the concept of dynamic memory allocation in C. Provide an example of allocating memory for an array dynamically and freeing it.

Answer:
Dynamic memory allocation in C allows for the allocation and deallocation of memory during runtime. The functions malloc(), calloc(), and realloc() are used for dynamic memory allocation, and free() is used to release the allocated memory.

Here’s an example of dynamically allocating memory for an array:

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

int main() {
    int size;
    printf("Enter the size of the array: ");
    scanf("%d", &size);

    int* arr = (int*)malloc(size * sizeof(int));
    if (arr == NULL) {
        printf("Memory allocation failed.n");
        return 1;
    }

    for (int i = 0; i < size; i++) {
        arr[i] = i + 1;
    }

    printf("Array elements: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("n");

    free(arr);

    return 0;
}Code language: PHP (php)

In this example, the user enters the size of the array. The malloc() function allocates memory dynamically based on the size provided by the user. We check if the memory allocation is successful before proceeding. We then assign values to the array elements and print them. Finally, we free the allocated memory using free().

Question:
What are function pointers in C? Provide an example demonstrating the use of function pointers.

Answer:
Function pointers in C are variables that store addresses of functions. They allow functions to be treated as data and passed as arguments to other functions or stored in data structures.

Here’s an example demonstrating the use of function pointers:

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int multiply(int a, int b) {
    return a * b;
}

int main() {
    int (*operation)(int, int);  // Declare a function pointer

    operation = add;  // Assign the address of the add() function

    int result = operation(5, 3);  // Call the function through the pointer

    printf("Result: %dn", result);

    operation = subtract;  // Assign the address of the subtract() function

    result = operation(5, 3);  // Call the function through the pointer

    printf("Result: %dn", result);

    return 0;
}Code language: PHP (php)

In this example, we declare a function pointer operation that can point to functions accepting two integers and returning an integer. We assign the address of the add() function to the pointer and call the function through the pointer. We then reassign the pointer to the subtract() function and call it again. This allows us to switch between different functions using a single function pointer.

Question:
Explain the concept of a binary search tree (BST) and its operations. Provide an example of inserting nodes into a BST and traversing it.

Answer:
A binary search tree (BST) is a binary tree data structure where each node has a key greater than all keys in its left subtree and less than all keys in its right subtree. It allows efficient searching, insertion, and deletion operations.

Here’s an example of inserting nodes into a BST and traversing it in-order:

#include

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

struct Node {
    int key;
    struct Node* left;
    struct Node* right;
};

struct Node* createNode(int key) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->key = key;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

struct Node* insert(struct Node* root, int key) {
    if (root == NULL) {
        return createNode(key);
    }

    if (key < root->key) {
        root->left = insert(root->left, key);
    }
    else if (key > root->key) {
        root->right = insert(root->right, key);
    }

    return root;
}

void inorderTraversal(struct Node* root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("%d ", root->key);
        inorderTraversal(root->right);
    }
}

int main() {
    struct Node* root = NULL;

    root = insert(root, 50);
    insert(root, 30);
    insert(root, 20);
    insert(root, 40);
    insert(root, 70);
    insert(root, 60);
    insert(root, 80);

    printf("Inorder traversal: ");
    inorderTraversal(root);
    printf("n");

    return 0;
}Code language: PHP (php)

In this example, we define a structure Node representing a node in the BST. The createNode() function creates a new node with the given key. The insert() function inserts a new node into the BST based on the key value. The inorderTraversal() function performs an in-order traversal of the BST and prints the keys in ascending order. We create a BST by inserting nodes with keys 50, 30, 20, 40, 70, 60, and 80. The output of the program will be:

Inorder traversal: 20 30 40 50 60 70 80

Question:
Explain the concept of multithreading in C. Provide an example of creating and synchronizing multiple threads.

Answer:
Multithreading in C allows a program to have multiple threads of execution running concurrently. Each thread represents a separate flow of control within the same program, allowing for parallel execution.

Here’s an example of creating and synchronizing multiple threads:

#include <stdio.h>
#include <pthread.h>

#define NUM_THREADS 5

void* threadFunc(void* arg) {
    int threadID = *((int*)arg);
    printf("Thread %d: Hello, world!n", threadID);
    pthread_exit(NULL);
}

int main() {
    pthread_t threads[NUM_THREADS];
    int threadIDs[NUM_THREADS];

    for (int i = 0; i < NUM_THREADS; i++) {
        threadIDs[i] = i + 1;
        int result = pthread_create(&threads[i], NULL, threadFunc, &threadIDs[i]);
        if (result != 0) {
            printf("Failed to create thread %dn", i + 1);
            return 1;
        }
    }

    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    printf("All threads completed.n");

    return 0;
}Code language: PHP (php)

In this example, we define a thread function threadFunc() that takes an argument representing the thread ID. Each thread prints a greeting message with its ID. We create an array of thread IDs and use a loop to create multiple threads. The

pthread_create() function creates a new thread, and we pass the thread ID as an argument. The pthread_join() function is used to wait for all threads to complete before proceeding. The output of the program may vary, but it will resemble:

Thread 1: Hello, world!
Thread 2: Hello, world!
Thread 3: Hello, world!
Thread 4: Hello, world!
Thread 5: Hello, world!
All threads completed.

Question:
Explain the concept of a linked list in C. Provide an example of creating a linked list, inserting elements, and traversing it.

Answer:
A linked list in C is a linear data structure where each element (node) contains a value and a pointer to the next node. It allows for efficient insertion and deletion operations, but random access is slower compared to arrays.

Here’s an example of creating a linked list, inserting elements, and traversing it:

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

struct Node {
    int data;
    struct Node* next;
};

void insert(struct Node** head, int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;

    if (*head == NULL) {
        *head = newNode;
    } else {
        struct Node* temp = *head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
}

void traverse(struct Node* head) {
    struct Node* temp = head;
    while (temp != NULL) {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("n");
}

int main() {
    struct Node* head = NULL;

    insert(&head, 10);
    insert(&head, 20);
    insert(&head, 30);

    traverse(head);

    return 0;
}Code language: PHP (php)

In this example, we define a structure Node representing a node in the linked list. The insert() function inserts a new node at the end of the list. If the list is empty, it assigns the new node as the head. Otherwise, it traverses to the end of the list and appends the new node. The traverse() function prints the data in each node by traversing the list. We create a linked list by inserting elements with values 10, 20, and 30. The output of the program will be:

10 20 30

These questions cover various advanced topics in the C language and their applications. They aim to assess the knowledge and experience of a senior C developer.

More C interview resources

For more guides on improving your knowledge of C and acing interviews, we have outlined helpful blog posts below:

1,000 Companies use CoderPad to Screen and Interview Developers

Best interview practices for C roles

To carry out successful C interviews, it is vital to consider various factors such as the candidate’s background and the specific engineering role. To ensure a fruitful interview experience, we recommend adopting the following best practices:

  • Develop technical questions that reflect real-world business scenarios within your organization. This approach will effectively engage the candidate and assist in evaluating their compatibility with your team.
  • Cultivate a cooperative environment by encouraging candidates to ask questions throughout the interview.
  • As C is a low-level programming language, make sure your candidates have a grasp of low-level programming concepts like registers, memory addressing, and bitwise operations.

Moreover, adhering to established interview procedures is essential when conducting C interviews. This encompasses adjusting the complexity of the questions to match the candidates’ skills, promptly informing them about the status of their application, and providing them with the opportunity to ask about the evaluation process and collaboration with you and your team.