InterviewGrind Get notified

InterviewGrind › C++

C++ Interview Questions and Answers

References, lifetimes, the STL and integer arithmetic: C++ interview questions where the bug is real and the explanation tells you exactly why.

15 free questions from the app. Try each one before you open the answer.

1. ParametersEasy

A function only reads a large vector<string> argument. How should it take it?

  1. By value
  2. By const reference
  3. By raw pointer
  4. As a global variable
Show answer

Answer: B. By const reference

const vector<string>& avoids the copy and promises not to modify it. Take by value only when the function needs its own copy anyway (then move into it).

2. ArraysEasy

Letter counts come out as huge random numbers on some runs and fine on others.

  1. int counts[26];
  2. for (char c : word) {
  3. counts[c - 'a']++;
  4. }

Which line has the bug?

Show answer

Answer: Line 1: int counts[26];

A local array with no initializer holds whatever was in memory. Write int counts[26] = {}; (or {0}): any elements you don't list in a brace initializer are zero-initialized.

3. CharactersEasy

A teammate sorts customer names, and "Banana" lands before "apple". Which review comment explains it?

std::sort(names.begin(), names.end());
  1. Characters compare by code, so every capital letter sorts before every lowercase one
  2. std::sort isn't stable, so names that compare equal can swap places
  3. std::string compares lengths first and only then looks at the letters
  4. The default comparator sorts strings in descending order, not ascending
Show answer

Answer: A. Characters compare by code, so every capital letter sorts before every lowercase one

'B' is 66 and 'a' is 97, so a plain < puts all uppercase before lowercase. Sort with a comparator that lowercases both sides (or a locale-aware collation for real names).

4. ReferencesEasy

Raising the database timeout at startup has no effect: requests still time out after 1 second.

  1. // registry.get returns Config&
  2. Config cfg = registry.get("db");
  3. cfg.timeoutMs = 5000;
  4. connect(registry);

Which line has the bug?

Show answer

Answer: Line 2: Config cfg = registry.get("db");

Config cfg = ... copies the struct, so the change goes to a local copy the registry never sees. Bind a reference instead: Config& cfg = registry.get("db");.

5. ArithmeticEasy

The average of 1, 2 and 2 comes back as 1 instead of about 1.67.

  1. double average(const std::vector<int>& v) {
  2. int sum = 0;
  3. for (int x : v) sum += x;
  4. return sum / v.size();
  5. }

Which line has the bug?

Show answer

Answer: Line 4: return sum / v.size();

Both operands are integers, so the division drops the fraction before the result becomes a double. Convert first: static_cast<double>(sum) / v.size(). (And decide what an empty vector should return.)

6. Type promotionEasy

The label should show the next grade letter, but it prints 66. What fixes it?

char grade = 'A';
std::cout << grade + 1 << '\n';
  1. grade + 1 → char(grade + 1)
  2. grade + 1 → grade++
  3. 'A' → "A"
  4. grade + 1 → +grade + 1
Show answer

Answer: A. grade + 1 → char(grade + 1)

grade + 1 promotes the char to int, and cout prints ints as numbers. Converting back with char(...) (or static_cast<char>) prints the letter B.

7. STL setsEasy

Deduplicating player IDs with a std::set. In what order do they come out?

set<int> s = {3, 1, 2, 1};
for (int x : s) cout << x;
cout << endl;

What does it output?

  1. 3121
  2. 312
  3. 123
  4. 1123
Show answer

Answer: C. 123

std::set stores unique keys in sorted order (it's a balanced tree). unordered_set drops duplicates too but has no defined order.

8. LambdasEasy

The running total is still 0 after add(5).

  1. int total = 0;
  2. auto add = [total](int x) mutable { total += x; };
  3. add(5);
  4. std::cout << total;

Which line has the bug?

Show answer

Answer: Line 2: auto add = [total](int x) mutable { total += x; };

[total] captures a copy when the lambda is created; mutable only lets the lambda change its own copy. Capture by reference with [&total] so the change reaches the outer variable.

9. I/OEasy

Myth or fact: std::endl flushes the output stream, but '\n' does not.

  1. Myth
  2. Fact
Show answer

Answer: B. Fact

Fact. Both end the line, but std::endl also flushes. In a loop writing a million lines, those flushes can make output several times slower; use '\n' unless you need the output to appear immediately.

10. StringsEasy

Ported from Java, this substring comes out longer than expected. What does it print?

string s = "hello";
cout << s.substr(1, 3) << endl;

What does it output?

  1. el
  2. ell
  3. ello
  4. hel
Show answer

Answer: B. ell

substr(pos, count) takes a start position and a length, not an end index (unlike Python slices or Java's substring).

11. Range-based forEasy

This is supposed to double every score in place, but the vector doesn't change. What's the one-token fix?

for (auto x : scores) {
    x *= 2;
}
  1. auto → auto&
  2. auto → const auto&
  3. auto → auto*
  4. auto → static auto
Show answer

Answer: A. auto → auto&

auto x copies each element. auto& x binds a reference to the element itself, so the change sticks.

12. RAIIMedium

A function locks a mutex with std::lock_guard and returns from three different places, yet the lock is always released. What's the principle behind that?

  1. Resources are released in destructors, which run automatically at scope exit
  2. All memory must be allocated on the heap, where it's tracked
  3. Raw pointers are used for every allocation so ownership is explicit
  4. Objects are garbage-collected automatically when the program reaches the end of main
Show answer

Answer: A. Resources are released in destructors, which run automatically at scope exit

Resource Acquisition Is Initialization ties a resource's lifetime (memory, file, lock) to an object's lifetime. Because destructors run even when exceptions are thrown, lock_guard, unique_ptr and fstream never leak.

13. AlgorithmsMedium

Filtering even numbers out of a vector, the right way. What size is left?

vector<int> v = {1, 2, 3, 4};
v.erase(remove_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; }), v.end());
cout << v.size() << endl;

What does it output?

  1. 4
  2. 2
  3. 0
  4. 1
Show answer

Answer: B. 2

This is the erase-remove idiom: remove_if moves the kept elements to the front and returns the new logical end; erase then actually shrinks the vector. C++20 adds std::erase_if(v, pred) to do both.

14. Smart pointersMedium

What's the key difference between unique_ptr and shared_ptr?

  1. unique_ptr has one owner and can only be moved; shared_ptr counts many owners
  2. unique_ptr is for arrays, while shared_ptr is for single objects
  3. shared_ptr is faster, because it never has to delete the object
  4. They're the same type; shared_ptr is just the older C++03 name
Show answer

Answer: A. unique_ptr has one owner and can only be moved; shared_ptr counts many owners

Default to unique_ptr: zero overhead, clear ownership. Use shared_ptr only when ownership is genuinely shared; it costs an atomic reference count, and cycles leak unless you break them with weak_ptr.

15. Range-based forMedium

You double every score in a loop, but the scores don’t change. What ends up on screen?

vector<int> v = {1, 2, 3};
for (auto x : v) x *= 2;
cout << v[0] << endl;

What does it output?

  1. 1
  2. 2
  3. 6
  4. Compile error
Show answer

Answer: A. 1

auto x is a copy of each element, so doubling it doesn't touch the vector. Use auto& x to modify in place, and const auto& x to read large elements without copying.

Practise like this every day

InterviewGrind gives you ten questions like these each day on your iPhone, with Pro tracks for company-style loops.

Get the launch email