Skip to content

C++ Online Assessment Questions & Answers

40 questions for the online assessment stage — 21 easy, 19 medium.

About the online assessment round

Most companies start with an online test: aptitude and reasoning, a few MCQs on core C++ 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

Write a C++ program that counts how often each word appears in the input.

Save to ▾
Show answer
#include <iostream> #include <map> #include <string> int main() { std::map<std::string, int> freq; std::string word; while (std::cin >> word) { ++freq[word]; } for (const auto& [w, c] : freq) { std::cout << w << ' ' << c << '\n'; } } // Use std::unordered_map for O(1) average lookups if sorted output is not needed.
02

Explain the stages of compiling and running a C++ program.

Save to ▾
Show answer
There are four stages. The preprocessor expands #include directives and macros into a translation unit. The compiler turns each translation unit into assembly and then an object file. The linker combines object files and libraries and resolves symbols into an executable. At run time the loader maps it into memory. A missing function body therefore shows up as a linker error, not a compiler error.
03

What are C++20 concepts?

Save to ▾
Show answer
Concepts are named compile-time predicates on template parameters. You can write template <std::integral T> T gcd(T a, T b) or define your own with a requires expression. If a type does not satisfy the concept, the compiler reports a short, readable error at the call site instead of pages of instantiation errors. Concepts also allow overloading by constraint and document the template's expectations.
04

Group a list of words into anagram groups.

Save to ▾
Show answer
#include <algorithm> #include <string> #include <unordered_map> #include <vector> std::vector<std::vector<std::string>> groupAnagrams(const std::vector<std::string>& words) { std::unordered_map<std::string, std::vector<std::string>> groups; for (const auto& w : words) { std::string key = w; std::sort(key.begin(), key.end()); groups[key].push_back(w); } std::vector<std::vector<std::string>> out; for (auto& [k, g] : groups) out.push_back(std::move(g)); return out; } // O(n * k log k) where k is the word length.
05

Write a thread-safe counter using std::atomic.

Save to ▾
Show answer
#include <atomic> #include <iostream> #include <thread> #include <vector> int main() { std::atomic<long> hits{0}; std::vector<std::thread> ts; for (int t = 0; t < 4; ++t) ts.emplace_back([&] { for (int i = 0; i < 1000000; ++i) hits.fetch_add(1, std::memory_order_relaxed); }); for (auto& t : ts) t.join(); std::cout << hits.load() << '\n'; // always 4000000 }
06

What are structured bindings and how do they work with range-based for loops?

Save to ▾
Show answer
Structured bindings, from C++17, unpack a pair, tuple, array or simple struct into named variables: auto [id, name] = getUser();. In loops they make map iteration readable: for (const auto& [key, value] : m). The variables are aliases into a hidden object, so const auto& avoids copies. They pair well with if statements with initialisers, such as if (auto [it, ok] = s.insert(x); ok).
07

What is std::string_view and what are its pitfalls?

Save to ▾
Show answer
string_view is a non-owning pointer and length pair that refers to existing characters, so passing it avoids copies and accepts both std::string and literals. The main pitfall is lifetime: it must not outlive the data it views, so returning a string_view to a local string or a temporary dangles. It is also not guaranteed to be null-terminated, so do not pass data() to C functions expecting C strings.
08

What are the fundamental data types in C++ and their typical sizes?

Save to ▾
Show answer
The main types are bool, char, short, int, long, long long, float, double and long double. On a typical 64-bit Linux system char is 1 byte, short 2, int 4, long 8, long long 8, float 4 and double 8. The standard only guarantees minimum ranges, so check with sizeof, and use fixed-width types such as int32_t or uint64_t from <cstdint> when the exact size matters.
09

Write a program where two threads print odd and even numbers alternately up to 10.

Save to ▾
Show answer
#include <condition_variable> #include <iostream> #include <mutex> #include <thread> std::mutex m; std::condition_variable cv; int n = 1; const int kMax = 10; void printer(int parity) { std::unique_lock<std::mutex> lk(m); while (true) { cv.wait(lk, [&] { return n > kMax || n % 2 == parity; }); if (n > kMax) break; std::cout << n++ << '\n'; cv.notify_all(); } cv.notify_all(); } int main() { std::thread odd(printer, 1), even(printer, 0); odd.join(); even.join(); }
10

What are lvalues and rvalues?

Save to ▾
Show answer
An lvalue has identity and a persistent address, such as a named variable x. An rvalue is a temporary without lasting identity, such as 5 or the result of a + b. C++11 splits these further into lvalue, xvalue and prvalue. The distinction matters because rvalue references, written T&&, bind to temporaries and enable move semantics, letting the program steal resources instead of making expensive copies.
11

Write a Shape hierarchy with a virtual area function and use it polymorphically.

Save to ▾
Show answer
#include <iostream> #include <memory> #include <vector> struct Shape { virtual ~Shape() = default; virtual double area() const = 0; }; struct Circle : Shape { double r; explicit Circle(double r) : r(r) {} double area() const override { return 3.14159 * r * r; } }; struct Rect : Shape { double w, h; Rect(double w, double h) : w(w), h(h) {} double area() const override { return w * h; } }; int main() { std::vector<std::unique_ptr<Shape>> v; v.push_back(std::make_unique<Circle>(2)); v.push_back(std::make_unique<Rect>(3, 4)); for (const auto& s : v) std::cout << s->area() << '\n'; }
12

What is CMake and why is it used for C++ projects?

Save to ▾
Show answer
CMake is a cross-platform build system generator. You describe targets, source files, include paths and dependencies in CMakeLists.txt, and CMake generates Makefiles, Ninja files or Visual Studio projects. Modern CMake is target based, using target_link_libraries and target_include_directories so settings flow to dependents. It integrates with package managers such as vcpkg and Conan and with CTest for running tests.
13

What do auto and decltype do?

Save to ▾
Show answer
auto deduces a variable's type from its initialiser, so auto it = m.begin(); avoids long iterator types. It drops top-level const and references unless you write const auto& or auto&. decltype(expr) yields the declared type of an expression without evaluating it, useful in generic code and return types. decltype(auto) keeps reference-ness exactly, which matters when forwarding return values.
14

What are type traits and how does if constexpr use them?

Save to ▾
Show answer
Type traits in <type_traits> answer questions about types at compile time, such as std::is_integral_v<T>, std::is_pointer_v<T> or std::is_same_v<T, U>, and transform types, such as std::remove_reference_t. if constexpr picks a branch at compile time and discards the other, so code like if constexpr (std::is_integral_v<T>) can call integer-only operations safely inside a generic function.
15

Write a GoogleTest unit test for a function, including an edge case.

Save to ▾
Show answer
#include <gtest/gtest.h> #include <stdexcept> #include <vector> double average(const std::vector<int>& v) { if (v.empty()) throw std::invalid_argument("empty"); long long s = 0; for (int x : v) s += x; return static_cast<double>(s) / v.size(); } TEST(AverageTest, ComputesMean) { EXPECT_DOUBLE_EQ(average({2, 4, 6}), 4.0); } TEST(AverageTest, ThrowsOnEmpty) { EXPECT_THROW(average({}), std::invalid_argument); }
16

What is the difference between struct and class in C++?

Save to ▾
Show answer
The only language difference is default access. Members and base classes of a struct are public by default, while in a class they are private by default. Both can have constructors, member functions, inheritance and templates. By convention a struct is used for simple data aggregates such as a Point, and a class is used for types that protect invariants with private state.
17

Find the middle node of a linked list in a single pass.

Save to ▾
Show answer
Node* middle(Node* head) { Node* slow = head; Node* fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } return slow; } // fast moves two steps and slow one step, so slow stops at the middle.
18

Two objects hold shared_ptr references to each other and their memory is never released. Why, and how do you fix it?

Save to ▾
Show answer
This is a reference cycle. Each object keeps the other's reference count above zero, so neither destructor runs even after all outside pointers are gone. Fix it by making one direction non-owning, usually the back pointer, with weak_ptr. For example, a parent holds shared_ptr to its children, while each child holds a weak_ptr to the parent and calls lock() when it needs access.
19

Write an efficient function to check whether a number is prime.

Save to ▾
Show answer
bool isPrime(long long n) { if (n < 2) return false; if (n % 2 == 0) return n == 2; for (long long i = 3; i * i <= n; i += 2) { if (n % i == 0) return false; } return true; } // Only odd divisors up to sqrt(n) are checked: O(sqrt n) time.
20

What do compiler optimisation levels like -O0, -O2, -O3 and -Os mean?

Save to ▾
Show answer
-O0 disables optimisation and is best for debugging. -O1 and -O2 enable progressively more optimisations such as inlining, constant propagation and loop optimisations; -O2 is the common release default. -O3 adds aggressive vectorisation and inlining, which may increase code size. -Os optimises for size. Link-time optimisation with -flto optimises across translation units, and -march=native tunes for the current CPU.
21

Four threads each increment a shared int one million times, but the final total is less than four million. Why?

Save to ▾
Show answer
counter++ is a read-modify-write of three steps, so threads interleave and overwrite each other's updates, which is a data race and undefined behaviour. Fix it with std::atomic<int> and fetch_add, which is fast for a simple counter, or protect the variable with a mutex. Even better for performance, let each thread count in a local variable and add it to the total once at the end.
22

What is the difference between a process and a thread?

Save to ▾
Show answer
A process is an independent program with its own address space, file handles and resources; processes are isolated and communicate through IPC such as pipes, sockets or shared memory. Threads live inside a process and share its memory and handles, but each has its own stack and registers. Threads are cheaper to create and communicate faster, but shared memory needs synchronisation to avoid races.
23

Write a generic function template that returns the larger of two values.

Save to ▾
Show answer
template <typename T> const T& maxOf(const T& a, const T& b) { return (a < b) ? b : a; } // usage int m = maxOf(3, 7); // T = int double d = maxOf(2.5, 1.5); // T = double auto s = maxOf<double>(3, 4.5); // explicit T avoids deduction conflict
24

What is pointer arithmetic?

Save to ▾
Show answer
Adding an integer to a pointer moves it by that many elements, not bytes, so p + 1 on an int* advances by sizeof(int) bytes. Subtracting two pointers into the same array gives the number of elements between them as ptrdiff_t. Arithmetic is only valid inside an array or one past its end; moving beyond that is undefined behaviour. Contiguous iterators work on the same idea.
25

Explain std::async, std::future and std::promise.

Save to ▾
Show answer
std::async runs a function, possibly on another thread, and returns a std::future that will hold its result or exception; calling get() waits for it. Use std::launch::async to force a new thread. std::promise is the writing end: one thread calls set_value or set_exception, and the paired future receives it. They make simple fork-join tasks easier than manual threads, but are not a full thread pool.
26

After calling std::move on a string, a teammate prints it and sees an empty value. Is this a bug?

Save to ▾
Show answer
It is a misunderstanding. A moved-from standard library object is in a valid but unspecified state; for std::string it is often empty, but you cannot rely on that. The safe operations are destroying it or assigning a new value. Reading it is not undefined behaviour, but the content is meaningless. Clang-tidy's bugprone-use-after-move check catches this pattern in code review.
27

Write a function to reverse a string in place without using std::reverse.

Save to ▾
Show answer
#include <string> #include <utility> void reverseInPlace(std::string& s) { if (s.empty()) return; std::size_t i = 0, j = s.size() - 1; while (i < j) { std::swap(s[i], s[j]); ++i; --j; } } // Two pointers meet in the middle: O(n) time, O(1) extra space.
28

What are default arguments and what rules apply to them?

Save to ▾
Show answer
Default arguments supply values when a caller leaves out trailing arguments, for example void log(const std::string& msg, int level = 1);. Defaults must appear at the end of the parameter list and be given only once, usually in the header declaration. They are bound at compile time, so for a virtual function the default value comes from the static type of the pointer, not the dynamic type, which is a common trap.
29

When are std::vector iterators invalidated?

Save to ▾
Show answer
Any insertion that causes reallocation, when size exceeds capacity, invalidates all iterators, pointers and references. Insertion without reallocation invalidates those at or after the insertion point. erase invalidates iterators at and after the erased element. clear and resize to a larger size beyond capacity invalidate everything. Holding a pointer to an element and then calling push_back is a classic bug.
30

What is the difference between push_back and emplace_back?

Save to ▾
Show answer
push_back takes an existing object, copying or moving it into the container. emplace_back forwards constructor arguments and builds the element directly in place, which can avoid a temporary. For example v.emplace_back(name, age) constructs a Person inside the vector. The gain is small when you already have an object, and emplace_back can call explicit constructors unexpectedly, so use it deliberately.
31

Write a lookup function that uses std::optional instead of returning -1 or a null pointer.

Save to ▾
Show answer
#include <optional> #include <string> #include <unordered_map> std::optional<int> findAge(const std::unordered_map<std::string, int>& db, const std::string& name) { if (auto it = db.find(name); it != db.end()) return it->second; return std::nullopt; } // caller if (auto age = findAge(db, "Meera")) { use(*age); } int a = findAge(db, "Unknown").value_or(0);
32

What is the difference between a static library and a dynamic library?

Save to ▾
Show answer
A static library, .a or .lib, is copied into the executable at link time, giving a self-contained binary but larger size and a rebuild for every library update. A dynamic library, .so or .dll, is loaded at run time and shared between processes, saving memory and allowing updates without relinking, but it needs the right version present on the machine and has a small call overhead.
33

What is the difference between an inline function and a macro?

Save to ▾
Show answer
A macro is text substitution done by the preprocessor with no type checking, so #define SQ(x) x*x gives a wrong result for SQ(a+1) and may evaluate arguments twice. An inline function is a real function with type checking, scope and debugger support, and the compiler may expand it at the call site. In modern C++ inline mainly allows a function to be defined in a header without breaking the One Definition Rule.
34

How do virtual functions work internally?

Save to ▾
Show answer
Most compilers give each polymorphic class a vtable, a static table of function pointers for its virtual functions. Every object stores a hidden vptr pointing to its class's vtable. A call through a base pointer loads the vptr, looks up the slot and jumps to the right override. The cost is one pointer per object, an indirect call and usually no inlining, which matters only in very hot loops.
35

What is function overloading and how does the compiler choose an overload?

Save to ▾
Show answer
Overloading means several functions share a name but differ in the number or types of parameters; return type alone is not enough. The compiler runs overload resolution: exact matches win, then promotions such as char to int, then standard conversions, then user-defined conversions. If two candidates are equally good the call is ambiguous and compilation fails. Name mangling gives every overload a unique linker symbol.
36

What are header guards and #pragma once?

Save to ▾
Show answer
Including the same header twice in a translation unit would redefine classes and cause errors. Header guards wrap the file in #ifndef MY_HEADER_H, #define MY_HEADER_H and #endif, so the second inclusion is skipped. #pragma once does the same in one line and is supported by all major compilers, though it is not in the standard. Most modern projects use #pragma once for simplicity.
37

Design a class structure for UPI, card and net banking payments in a checkout system.

Save to ▾
Show answer
I would define an abstract PaymentMethod interface with virtual functions such as authorize, capture, refund and a virtual destructor. UpiPayment, CardPayment and NetBankingPayment implement it with their own validation. Checkout depends only on PaymentMethod, and a factory creates the right object from user choice. New methods such as wallets can be added without touching checkout code, which follows the open-closed principle.
38

What is the difference between stack and heap memory?

Save to ▾
Show answer
Stack memory holds local variables and call frames; allocation is very fast and automatic, and memory is freed when the scope ends, but the size is limited to a few megabytes. Heap memory is allocated at run time with new or by containers, is much larger and lives until it is freed, but allocation is slower and can fragment. Large, variable-size or long-lived objects belong on the heap.
39

How do you create a thread in C++ and what is the difference between join and detach?

Save to ▾
Show answer
std::thread t(func, args); starts a new thread running func. join() blocks until the thread finishes, so the caller can safely use its results. detach() lets the thread run independently; you lose the handle and it must not touch objects that may be destroyed. If a joinable std::thread is destroyed without join or detach, std::terminate is called. C++20 std::jthread joins automatically in its destructor.
40

Compare std::vector, std::list and std::deque.

Save to ▾
Show answer
vector stores elements contiguously, gives O(1) random access and fast iteration, with amortised O(1) push_back but O(n) insertion in the middle. list is a doubly linked list with O(1) insert and erase anywhere given an iterator, but no random access and poor cache use. deque supports fast insertion at both ends and random access, stored in chunks. Default to vector unless profiling says otherwise.

Frequently asked questions

What happens in the C++ online assessment round?

Most companies start with an online test: aptitude and reasoning, a few MCQs on core C++ 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.