C++ Exercises
Practise what you've learned. Type the missing piece into each highlighted gap and press Check. Further down are programming challenges with editors and model solutions — copy them to compile and run locally.
Fill in the blanks
Basics
Include the header for console input and output.
#include <>
(lesson 03)
Print a value followed by a newline.
std:: << total << '\n';
(lesson 03)
Let the compiler deduce the type.
price = 9.99;
(lesson 04)
A value computed at compile time.
int board_size = 8;
(lesson 05)
Read a whole line of text.
std::(std::cin, name);
(lesson 07)
Convert an int to double before dividing.
double avg = <double>(total) / count;
(lesson 09)
Print booleans as true/false.
std::cout << std:: << ready << '\n';
(lesson 06)
Visit every element of a vector without copying.
for (const auto name : names) std::cout << name << '\n';
(lesson 11)
Functions
A parameter the function can modify.
void normalise(std::vector<double> values);
A reference (lesson 13).
Read a large object without copying it.
int count(const std::string text);
A const reference (lesson 14).
Transfer a string's contents instead of copying.
names.push_back(std::(name));
(lesson 14)
Give a parameter a default value.
void greet(const std::string& name, int times 1);
(lesson 15)
Print a floating-point number with two decimals using a manipulator.
std::cout << std::fixed << std::(2) << price;
From <iomanip> (lesson 07).
Containers and algorithms
Add an element to the end of a vector.
scores.(95);
Or emplace_back (lesson 18).
Index with bounds checking.
int x = values.(3);
Throws std::out_of_range if invalid (lesson 18).
Check whether a map has a key (C++20).
if (stock.("apples")) { /* ... */ }
(lesson 21)
A container that keeps unique values in sorted order.
std::<std::string> tags;
(lesson 21)
A scoped enumeration.
enum Colour { red, green, blue };
(lesson 20)
Unpack a struct with members name and age into variables.
auto [name, ] = person;
A structured binding (lesson 20).
Sort a vector with the ranges library.
std::ranges::(names);
(lesson 25)
Count the elements that satisfy a lambda.
auto n = std::ranges::(v, [limit](int x) { return x > limit; });
(lessons 24–25)
Keep only even numbers in a view pipeline.
auto evens = numbers | std::views::([](int n) { return n % 2 == 0; });
(lesson 26)
Remove all elements matching a condition (C++20).
std::(v, [](int x) { return x < 0; });
(lesson 18)
Memory and classes
A pointer that points to nothing.
Book* found = ;
(lesson 27)
Create an object owned by a unique_ptr.
auto engine = std::<Engine>("V8");
(lesson 29)
Shared ownership of an object.
std::<Texture> grass = std::make_shared<Texture>("grass.png");
(lesson 29)
Members only the class itself can access.
class Account {
:
double balance_ = 0;
};
(lesson 31)
A member function that doesn't modify the object.
double balance() { return balance_; }
(lesson 31)
Prevent implicit conversion through a constructor.
Temperature(double celsius);
(lesson 32)
The destructor of class Logger.
Logger();
(lesson 32)
Generate all comparison operators from the members.
auto operator(const Version&) const = default;
(lessons 20 and 34)
Forbid copying.
Connection(const Connection&) = ;
(lesson 35)
Derive publicly from a base class.
class SavingsAccount : Account { /* ... */ };
(lesson 36)
Mark a function that derived classes can override.
double area() const = 0;
Pure virtual (lessons 37–38).
Check that you really override a base-class function.
double area() const { return w * h; }
(lesson 37)
Templates, errors and the library
Declare a function template.
<typename T> T largest(const T& a, const T& b);
(lesson 39)
Constrain a template to integer types.
template <std:: T> T gcd(T a, T b);
(lesson 41)
Report an error by throwing.
std::invalid_argument("negative price");
(lesson 42)
A value that may be absent.
std::<int> find_index(const std::vector<int>& v, int x);
(lesson 43)
Open a file for reading.
std:: in{"data.txt"};
(lesson 44)
Format a number with two decimals.
std::string s = std::("{:.2f}", price);
(lesson 45)
Programming challenges
1. Word frequencies
Count how often each word appears in a sentence and print the words with their counts, most frequent first (alphabetical for ties).
Show a model solution
#include <algorithm> #include <iostream> #include <map> #include <sstream> #include <string> #include <vector> int main() { std::istringstream text{"the cat and the hat and the bat"}; std::map<std::string, int> counts; for (std::string w; text >> w;) ++counts[w]; std::vector<std::pair<std::string, int>> sorted(counts.begin(), counts.end()); std::ranges::stable_sort(sorted, std::greater{}, &std::pair<std::string, int>::second); for (const auto& [word, n] : sorted) std::cout << word << ' ' << n << '\n'; }
the 3 and 2 bat 1 cat 1 hat 1
2. A bank account class
Write a BankAccount class with an owner, a balance that can never go negative, deposit and withdraw functions that throw on invalid amounts, and a transaction count.
Show a model solution
#include <iostream> #include <stdexcept> #include <string> #include <utility> class BankAccount { public: explicit BankAccount(std::string owner) : owner_(std::move(owner)) {} void deposit(double amount) { if (amount <= 0) throw std::invalid_argument("deposit must be positive"); balance_ += amount; ++transactions_; } void withdraw(double amount) { if (amount <= 0) throw std::invalid_argument("withdrawal must be positive"); if (amount > balance_) throw std::runtime_error("insufficient funds"); balance_ -= amount; ++transactions_; } double balance() const { return balance_; } int transactions() const { return transactions_; } const std::string& owner() const { return owner_; } private: std::string owner_; double balance_ = 0; int transactions_ = 0; }; int main() { BankAccount acc{"Ana"}; acc.deposit(100); acc.withdraw(30); try { acc.withdraw(500); } catch (const std::exception& e) { std::cout << "error: " << e.what() << '\n'; } std::cout << acc.owner() << ": " << acc.balance() << " after " << acc.transactions() << " transactions\n"; }
error: insufficient funds Ana: 70 after 2 transactions
3. Shapes with polymorphism
Create an abstract Shape with area() and name(), implement Circle and Rectangle, store several in a std::vector<std::unique_ptr<Shape>>, and print the largest.
Show a model solution
#include <algorithm> #include <iostream> #include <memory> #include <string> #include <vector> class Shape { public: virtual ~Shape() = default; virtual double area() const = 0; virtual std::string name() const = 0; }; class Circle : public Shape { public: explicit Circle(double r) : r_(r) {} double area() const override { return 3.14159265 * r_ * r_; } std::string name() const override { return "circle"; } private: double r_; }; class Rectangle : public Shape { public: Rectangle(double w, double h) : w_(w), h_(h) {} double area() const override { return w_ * h_; } std::string name() const override { return "rectangle"; } private: double w_, h_; }; int main() { std::vector<std::unique_ptr<Shape>> shapes; shapes.push_back(std::make_unique<Circle>(1.5)); shapes.push_back(std::make_unique<Rectangle>(3, 2.5)); shapes.push_back(std::make_unique<Circle>(0.5)); auto biggest = std::ranges::max_element(shapes, {}, [](const auto& s) { return s->area(); }); std::cout << "largest: " << (*biggest)->name() << " with area " << (*biggest)->area() << '\n'; }
largest: rectangle with area 7.5
4. A generic stack with a concept
Write a class template Stack<T> with push, pop (returning std::optional<T>) and size, and a function constrained with a concept that sums the contents of a stack of numbers.
Show a model solution
#include <concepts> #include <iostream> #include <optional> #include <vector> template <typename T> class Stack { public: void push(T value) { items_.push_back(std::move(value)); } std::optional<T> pop() { if (items_.empty()) return std::nullopt; T top = std::move(items_.back()); items_.pop_back(); return top; } std::size_t size() const { return items_.size(); } private: std::vector<T> items_; }; template <typename T> concept Number = std::integral<T> || std::floating_point<T>; template <Number T> T drain_sum(Stack<T>& s) { T total{}; while (auto v = s.pop()) total += *v; return total; } int main() { Stack<double> s; for (double x : {1.5, 2.25, 4.0}) s.push(x); std::cout << s.size() << " values, sum " << drain_sum(s) << ", now " << s.size() << '\n'; std::cout << std::boolalpha << s.pop().has_value() << '\n'; }
3 values, sum 7.75, now 0 false
5. Grade report from a file
Read lines of the form name,score from a file, skip bad lines, and print the average, the best student and a grade for each, using algorithms where they fit.
Ana,82 Ben,91 oops Chloe,77 Dev,64
Show a model solution
#include <algorithm> #include <format> #include <fstream> #include <iostream> #include <numeric> #include <sstream> #include <string> #include <vector> struct Result { std::string name; int score; }; char grade(int score) { return score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : score >= 60 ? 'D' : 'F'; } int main() { std::ifstream in{"grades.csv"}; std::vector<Result> results; for (std::string line; std::getline(in, line);) { std::istringstream fields{line}; Result r; if (std::getline(fields, r.name, ',') && fields >> r.score) results.push_back(r); else std::cout << "skipping: " << line << '\n'; } double avg = std::accumulate(results.begin(), results.end(), 0.0, [](double sum, const Result& r) { return sum + r.score; }) / results.size(); auto best = std::ranges::max_element(results, {}, &Result::score); std::cout << std::format("average {:.1f}, best {} ({})\n", avg, best->name, best->score); for (const auto& r : results) std::cout << std::format("{:<6} {:>3} {}\n", r.name, r.score, grade(r.score)); }
skipping: oops average 78.5, best Ben (91) Ana 82 B Ben 91 A Chloe 77 C Dev 64 D