Skip to content

C Programming with DSA Online Assessment Questions & Answers

40 questions for the online assessment stage — 19 easy, 20 medium, 1 hard.

About the online assessment round

Most companies start with an online test: aptitude and reasoning, a few MCQs on core C Programming with DSA concepts, and one or two short hands-on tasks. It filters a large number of applicants, so speed and accuracy both count.

Tips for the online assessment round

  • Practise under a timer: about one minute per MCQ and 15-20 minutes per hands-on task.
  • Read every option before answering; tests often include two nearly correct choices.
  • Use a stable internet connection, keep your camera on and avoid switching tabs in proctored tests.
  • Attempt the questions you are sure about first, then return to the harder ones.
Solved — online assessmentStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

Insert a node at the end of a singly linked list using a double pointer.

Save to ▾
Show answer
A pointer to pointer handles the empty list without special cases. int append(Node **head, int value) { Node *n = malloc(sizeof *n); if (!n) return -1; n->data = value; n->next = NULL; while (*head) head = &(*head)->next; *head = n; return 0; } Call it as append(&head, 5). Keep a tail pointer if you append often.
02

What is a prefix sum array and why is it useful?

Save to ▾
Show answer
A prefix sum array stores pre[i] = sum of elements from index 0 to i-1. Then the sum of any range from l to r is pre[r + 1] - pre[l] in O(1) after O(n) preprocessing. It is used for range sum queries, counting subarrays with a given sum together with a hash map, and 2D versions for matrix region sums.
03

What is the difference between greedy algorithms and dynamic programming?

Save to ▾
Show answer
A greedy algorithm makes the best local choice at each step and never revisits it, which works only when the greedy choice property holds, as in activity selection, Huffman coding and Dijkstra. Dynamic programming considers all relevant subproblem choices and combines them, so it works where greedy fails, such as 0/1 knapsack or coin change with arbitrary denominations. Greedy is faster when provably correct.
04

What are the main stages of compiling a C program?

Save to ▾
Show answer
Preprocessing expands #include files and macros and removes comments. Compilation turns the preprocessed code into assembly. Assembly converts it into an object file of machine code. Linking combines object files with libraries such as libc to produce the executable. With gcc you can stop at each stage using -E, -S and -c, which helps when debugging macro or linker errors.
05

What does it mean that arrays decay to pointers when passed to functions?

Save to ▾
Show answer
When you pass an array to a function, C passes only a pointer to its first element, not a copy of the array. So void f(int a[]) is the same as void f(int *a), sizeof a inside gives the pointer size and changes to elements affect the caller's array. Always pass the length as a separate parameter, such as f(arr, n).
06

Write a C function to check whether a number is an Armstrong number.

Save to ▾
Show answer
Sum of digits raised to the number of digits equals the number. int isArmstrong(int n) { int digits = 0, t = n, sum = 0; while (t) { digits++; t /= 10; } t = n; while (t) { int d = t % 10, p = 1; for (int i = 0; i < digits; i++) p *= d; sum += p; t /= 10; } return sum == n; } For example 153 = 1 + 125 + 27.
07

What is a queue and what are its variants?

Save to ▾
Show answer
A queue is first in, first out with enqueue at the rear and dequeue at the front, both O(1). Variants are the circular queue, which reuses array space; the deque, which allows insertion and removal at both ends; and the priority queue, which removes the highest priority element first. Queues are used in BFS, task scheduling, print spooling and buffering data between producers and consumers.
08

Write a C function to count words in a sentence.

Save to ▾
Show answer
Count transitions from space to non-space. #include <ctype.h> int countWords(const char *s) { int count = 0, inWord = 0; for (; *s; s++) { if (isspace((unsigned char)*s)) { inWord = 0; } else if (!inWord) { inWord = 1; count++; } } return count; } This handles multiple spaces, tabs and leading or trailing spaces correctly.
09

Merge two sorted arrays into a third sorted array.

Save to ▾
Show answer
Walk both arrays with two indexes. void merge(const int *a, int n, const int *b, int m, int *out) { int i = 0, j = 0, k = 0; while (i < n && j < m) out[k++] = (a[i] <= b[j]) ? a[i++] : b[j++]; while (i < n) out[k++] = a[i++]; while (j < m) out[k++] = b[j++]; } Time O(n + m). Using <= keeps the merge stable.
10

What is the difference between an array and a pointer?

Save to ▾
Show answer
An array is a block of contiguous elements whose size is fixed and known to the compiler; sizeof gives the full array size. A pointer is a variable holding an address; sizeof gives the pointer size. An array name decays to a pointer to its first element in most expressions, but it cannot be reassigned. When passed to a function, an array always becomes a pointer, losing its length.
11

What is recursion and what are its risks?

Save to ▾
Show answer
Recursion is when a function calls itself on a smaller subproblem until reaching a base case. It expresses tree traversal, divide and conquer and backtracking naturally. Risks are stack overflow when depth is large, repeated work when subproblems overlap, like naive Fibonacci, and function call overhead. Use memoisation for overlapping subproblems and iterative versions when depth may be huge.
12

Write a function that dynamically allocates an array of n integers and fills it with squares.

Save to ▾
Show answer
Check the allocation and let the caller free it. int *makeSquares(size_t n) { int *arr = malloc(n * sizeof *arr); if (arr == NULL) return NULL; for (size_t i = 0; i < n; i++) { arr[i] = (int)(i * i); } return arr; } // caller int *a = makeSquares(10); if (a) { /* use */ free(a); }
13

A search on a sorted array of 10 lakh elements is done with a linear loop. How would you justify changing it?

Save to ▾
Show answer
Linear search takes up to 10 lakh comparisons, while binary search needs about 20, because log base 2 of 10 lakh is roughly 20. If searches are frequent, this is a huge saving at zero memory cost. If data changes often, keeping it sorted costs inserts, so consider a balanced tree or hash table. Measure with realistic workloads before and after.
14

Find the length of the longest substring without repeating characters in C.

Save to ▾
Show answer
Sliding window with last seen positions. int longestUnique(const char *s) { int last[256]; for (int i = 0; i < 256; i++) last[i] = -1; int best = 0, start = 0; for (int i = 0; s[i]; i++) { unsigned char c = s[i]; if (last[c] >= start) start = last[c] + 1; last[c] = i; if (i - start + 1 > best) best = i - start + 1; } return best; } For abcabcbb it returns 3.
15

Write a C program that counts lines, words and characters in a file.

Save to ▾
Show answer
Read character by character with fgetc. FILE *fp = fopen(path, "r"); if (!fp) { perror("fopen"); return 1; } long lines = 0, words = 0, chars = 0; int c, inWord = 0; while ((c = fgetc(fp)) != EOF) { chars++; if (c == '\n') lines++; if (isspace(c)) inWord = 0; else if (!inWord) { inWord = 1; words++; } } fclose(fp); printf("%ld %ld %ld\n", lines, words, chars); c is int so EOF can be distinguished from valid bytes.
16

Why is gets() dangerous and what should you use instead?

Save to ▾
Show answer
gets() reads a line into a buffer without knowing its size, so long input overflows the buffer and can be used for code execution attacks. It was removed in C11. Use fgets(buf, sizeof buf, stdin), which stops at the buffer size and keeps the newline, then strip the newline if needed. For formatted input, give scanf field widths like %19s.
17

Copy a file in C using fread and fwrite.

Save to ▾
Show answer
Use a buffer and binary mode. int copyFile(const char *src, const char *dst) { FILE *in = fopen(src, "rb"); if (!in) return -1; FILE *out = fopen(dst, "wb"); if (!out) { fclose(in); return -1; } char buf[8192]; size_t n; while ((n = fread(buf, 1, sizeof buf, in)) > 0) { if (fwrite(buf, 1, n, out) != n) break; } fclose(in); return fclose(out); }
18

Write a C program to swap two numbers without using a third variable.

Save to ▾
Show answer
Using arithmetic or XOR through pointers: void swap(int *a, int *b) { if (a == b) return; *a = *a ^ *b; *b = *a ^ *b; *a = *a ^ *b; } The a == b check matters because XOR swapping a variable with itself sets it to zero. In real code a temporary variable is clearer and just as fast.
19

A hash table becomes slow as more data is inserted. What is wrong?

Save to ▾
Show answer
The load factor has grown, so chains get long or open addressing probes become long, turning O(1) into nearly O(n). Another cause is a poor hash function clustering keys into few buckets. Fix it by resizing to roughly double capacity and rehashing when the load factor crosses a threshold, and by using a better hash function. Measure the longest chain to confirm.
20

How do you pass a structure to a function efficiently?

Save to ▾
Show answer
Passing a struct by value copies every member, which is costly for large structs. Pass a pointer instead, and add const when the function should only read it, such as void print(const Student *s). Access members with s->name. Small structs of a few bytes can be passed by value safely, and returning small structs by value is also fine.
21

You need the maximum of every sliding window of size k in an array. How would you solve it efficiently?

Save to ▾
Show answer
Use a deque storing indexes in decreasing order of value. For each element, remove indexes outside the window from the front, pop smaller values from the back, then push the current index. The front is always the maximum of the current window. Each index enters and leaves once, so the total time is O(n) instead of O(nk).
22

What is a pointer in C?

Save to ▾
Show answer
A pointer is a variable that stores the memory address of another variable. int *p = &x; makes p hold the address of x, and *p reads or writes the value at that address. Pointers allow passing large data efficiently, modifying caller variables, working with arrays and strings, building dynamic data structures like linked lists and allocating memory at runtime.
23

What is the sliding window technique?

Save to ▾
Show answer
Sliding window solves problems on contiguous subarrays or substrings by keeping a window with two indexes and moving them forward instead of rechecking every subarray. A fixed window finds things like the maximum sum of k elements, while a variable window expands and shrinks, as in the longest substring without repeating characters. It turns O(n squared) brute force into O(n).
24

What is the difference between stack and heap allocation?

Save to ▾
Show answer
Stack memory holds local variables, is allocated and freed automatically when functions enter and return, and is very fast but limited in size, often 1 to 8 MB. Heap memory is allocated with malloc and freed manually, can be large and outlive the function, but is slower and can fragment or leak. Large or variable sized data and data that must outlive a function belong on the heap.
25

Explain storage classes in C.

Save to ▾
Show answer
auto is the default for local variables, stored on the stack with block lifetime. register hints the variable should live in a CPU register, and its address cannot be taken. static gives a local variable lifetime for the whole program, or limits a global to its file. extern declares a variable defined in another file. Storage class decides scope, lifetime and linkage.
26

Allocate and free a dynamic 2D array of rows by cols in C.

Save to ▾
Show answer
A single block is cache friendly and easy to free. int (*grid)[cols] = malloc(rows * sizeof *grid); if (!grid) return -1; grid[2][3] = 5; free(grid); // array of row pointers alternative int **m = malloc(rows * sizeof *m); for (int i = 0; i < rows; i++) m[i] = calloc(cols, sizeof **m); for (int i = 0; i < rows; i++) free(m[i]); free(m); The first form uses a variable length array type.
27

What is a double pointer and when do you need it?

Save to ▾
Show answer
A double pointer, such as int **pp, stores the address of a pointer. It is needed when a function must change the caller's pointer itself, for example inserting at the head of a linked list or allocating memory inside a function and returning it through a parameter. It is also used for dynamic 2D arrays and arrays of strings, like char **argv.
28

What is a circular linked list and where is it used?

Save to ▾
Show answer
In a circular linked list the last node points back to the first, so there is no NULL end. You can start at any node and visit all nodes, and keeping only a tail pointer gives O(1) access to both ends. It is used in round-robin CPU scheduling, multiplayer turn order and circular buffers. Traversal loops must stop when they return to the starting node.
29

What is the difference between a complete, full and perfect binary tree?

Save to ▾
Show answer
A full binary tree has every node with zero or two children. A complete binary tree has all levels filled except possibly the last, which is filled from left to right; heaps use this shape so they fit an array. A perfect binary tree has all internal nodes with two children and all leaves at the same level, so it has 2 to the power h+1 minus 1 nodes.
30

How do you find the middle of a linked list in one pass?

Save to ▾
Show answer
Use slow and fast pointers starting at the head. Move slow by one node and fast by two nodes each step. When fast reaches the end or NULL, slow is at the middle. For an even number of nodes this gives the second middle; start fast at head->next to get the first middle instead. It takes O(n) time and O(1) space.
31

After calling realloc, the program sometimes crashes. What could be wrong?

Save to ▾
Show answer
realloc may move the block and returns the new address, so old pointers to the block become invalid. Writing ptr = realloc(ptr, n) also leaks the original memory if realloc fails and returns NULL. Store the result in a temporary pointer, check for NULL, then assign. Make sure no other pointers still refer to the old location after a successful move.
32

What is a structure in C and why is it used?

Save to ▾
Show answer
A structure groups related variables of different types under one name, such as struct Student { int roll; char name[50]; float marks; };. It models real records, lets functions take or return one object instead of many parameters and is the base for data structures like linked lists and trees. Members are accessed with the dot operator or with -> through a pointer.
33

Write code to check whether the machine is little endian or big endian.

Save to ▾
Show answer
Look at the first byte of a known integer. int isLittleEndian(void) { uint32_t x = 1; unsigned char *p = (unsigned char *)&x; return p[0] == 1; } // using a union union { uint32_t i; unsigned char c[4]; } u = { 1 }; int little = (u.c[0] == 1); x86 and most ARM systems are little endian; network byte order is big endian.
34

Count the number of islands in a grid of land and water cells. What approach do you take?

Save to ▾
Show answer
Treat each land cell as a graph node connected to its four neighbours. Scan the grid, and when you find unvisited land, increment the count and flood fill with DFS or BFS to mark the whole island visited. Time and space are O(rows times cols). For very large grids, use iterative BFS to avoid recursion depth issues, or union-find.
35

Why is a circular queue better than a simple array queue?

Save to ▾
Show answer
In a simple array queue, the front moves forward as elements are removed, so the space before it is wasted and the queue appears full even when there is room. A circular queue wraps indexes using modulo, so rear = (rear + 1) % size reuses freed slots. You track fullness with a count or by keeping one slot empty to distinguish full from empty.
36

Implement merge sort in C.

Save to ▾
Show answer
Split, sort halves, merge with a temp buffer. void merge(int *a, int l, int m, int r, int *tmp) { int i = l, j = m + 1, k = l; while (i <= m && j <= r) tmp[k++] = (a[i] <= a[j]) ? a[i++] : a[j++]; while (i <= m) tmp[k++] = a[i++]; while (j <= r) tmp[k++] = a[j++]; for (k = l; k <= r; k++) a[k] = tmp[k]; } void mergeSort(int *a, int l, int r, int *tmp) { if (l >= r) return; int m = l + (r - l) / 2; mergeSort(a, l, m, tmp); mergeSort(a, m + 1, r, tmp); merge(a, l, m, r, tmp); }
37

What is an enum in C and what are its advantages?

Save to ▾
Show answer
An enum defines a set of named integer constants, such as enum Color { RED, GREEN, BLUE };, where values start at 0 unless set. It makes code readable and lets compilers warn about missing cases in a switch with -Wswitch. Enum values are int sized in practice, and C23 allows specifying the underlying type. Use them for states, commands and error codes.
38

A doubly linked list delete function leaves the list broken when deleting the head. What is missing?

Save to ▾
Show answer
When deleting the head there is no previous node, so the head pointer itself must move to head->next, and the new head's prev must be set to NULL. Similarly, deleting the tail needs the new tail's next set to NULL. The fix is to check node->prev and node->next for NULL and update head or tail pointers accordingly, or use a sentinel node to avoid these cases.
39

What is the volatile qualifier used for in C?

Save to ▾
Show answer
volatile tells the compiler that a variable can change outside normal program flow, for example a hardware register, a variable changed in an interrupt handler or memory shared with another device. The compiler must read it from memory every time and cannot cache it in a register or remove repeated reads. It does not provide atomicity or thread safety on its own.
40

You must schedule the maximum number of non-overlapping meetings in one room. What algorithm do you use?

Save to ▾
Show answer
This is activity selection, solved greedily. Sort meetings by end time, then pick each meeting whose start is not earlier than the end of the last picked one. Choosing the earliest finishing meeting always leaves the most room for the rest, which can be proven by an exchange argument. Sorting dominates, giving O(n log n) time.

Frequently asked questions

What happens in the C Programming with DSA online assessment round?

Most companies start with an online test: aptitude and reasoning, a few MCQs on core C Programming with DSA concepts, and one or two short hands-on tasks. It filters a large number of applicants, so speed and accuracy both count.

How do I clear the online assessment round?

Practise under a timer: about one minute per MCQ and 15-20 minutes per hands-on task. Read every option before answering; tests often include two nearly correct choices. Use a stable internet connection, keep your camera on and avoid switching tabs in proctored tests.

Which round comes next?

A typical order is online assessment, telephonic screening, one or two technical rounds, a managerial round and HR. Use the other round pages to practise each stage.