Kelick Tech Hub

Build, learn & keep up — tech, Linux & sports news included.

C++ Resume Builder (text-based) Project

Intermediate•1–2 days•structs, file output, text formatting

Answer questions, get a cleanly formatted resume as a text file.

Share on X

What you will build

The program interviews you — name, contact, education, jobs, skills — then typesets a tidy plain-text resume to a file. The work is in presentation: wrapping long text, aligning sections, and making fixed-width output look professionally composed.

What you will learn

Feature checklist

Starter code

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

struct Job { std::string title, company, dates; std::vector<std::string> bullets; };
struct Resume {
    std::string name, email, phone, summary;
    std::vector<Job> jobs;
    std::vector<std::string> skills;
};

std::string wrap(const std::string& text, size_t width = 76) {
    std::string out, line;
    std::istringstream words(text); std::string w;
    while (words >> w) {
        if (line.size() + w.size() + 1 > width) { out += line + "\n"; line = w; }
        else line += (line.empty() ? "" : " ") + w;
    }
    return out + line;
}

void render(const Resume& r, std::ostream& os) {
    os << r.name << "\n" << r.email << " | " << r.phone << "\n";
    os << std::string(60, '=') << "\nSUMMARY\n" << wrap(r.summary) << "\n\n";
    os << "EXPERIENCE\n";
    for (const auto& j : r.jobs) {
        os << j.title << " — " << j.company << " (" << j.dates << ")\n";
        for (const auto& b : j.bullets) os << "  • " << wrap(b) << "\n";
    }
    os << "\nSKILLS\n";
    for (size_t i = 0; i < r.skills.size(); ++i)
        os << r.skills[i] << (i + 1 < r.skills.size() ? ", " : "\n");
}

Full walkthrough

Step 1: Model the resume as nested data

struct Job { title, company, period, std::vector<std::string> bullets } and struct Resume { name, contact line, summary, education entries, std::vector<Job> jobs, std::vector<std::string> skills }. The resume is a tree of data; the builder collects it, render() prints it. Separating collection from rendering is what lets you re-render after an edit without re-typing everything.

Step 2: Collect input section by section

Prompt in document order — contact, summary, then loops for education and jobs ('Add a job, or press Enter on an empty title to finish'), bullets per job the same way, skills last. Empty-line-to-finish loops are the friendliest console pattern for variable-length input; learn it here and reuse it everywhere.

Step 3: Write wrap(): the one real algorithm

wrap(text, width = 80) breaks a paragraph into lines no longer than 80 chars, splitting at the LAST space before the limit — never mid-word. Walk a position pointer: if the remaining text fits, take it all; else find the last space within the window and cut there. Every 'nicely formatted text output' feature you will ever build contains this function.

std::vector<std::string> wrap(const std::string& s, int w) {
    std::vector<std::string> lines;
    size_t pos = 0;
    while (pos < s.size()) {
        if (pos + w >= s.size()) { lines.push_back(s.substr(pos)); break; }
        size_t cut = s.rfind(' ', pos + w);
        lines.push_back(s.substr(pos, cut - pos));
        pos = cut + 1;
    }
    return lines;
}

Step 4: render(): produce the document

render() writes to an std::ofstream: the name in caps, a rule line of '=' characters, section headings, wrapped summary paragraphs, jobs with indented wrapped bullets (' - ' prefix, continuation lines aligned). Fixed 80-column output is a deliberate retro constraint — it prints identically everywhere, including the preview.

Step 5: Preview before saving

Print render()'s output to the console first (render to a string or write to cout in a dry run), let the user look, then save to resume.txt on confirmation. Preview-then-commit is the same pattern as the library's fine check or the ATM's confirmations: never let the first time a user sees output be after it is permanent.

Step 6: Save the raw data, not just the render

Write the Resume fields to a data file (one field per line, jobs and bullets counted) so the user can reload, fix a typo, and re-render. Saving only the pretty .txt makes every edit a full retype — the checklist explicitly asks for editable data, and this is why.

Step 7: Test the wrap and the round-trip

Feed wrap() a paragraph with a word longer than 80 characters (a URL) and confirm nothing crashes (the fallback is a hard cut). Build a small resume, save, reload, re-render, and diff against the first render — they must be identical.

Common mistakes

Compile and run

g++ -std=c++17 -o resume resume.cpp

Sample run

$ ./resume
Full name:
> Adaeze Obi
Contact line (email · phone · city):
> adaeze@example.com · 0803 555 0142 · Lagos
Summary:
> Computer Science graduate who builds small, honest tools in C++ and Python.
Job (title — company, period; empty to finish):
> Graphic Designer — Freelance, 2023 - present
Bullet (empty to finish):
> Designed brand kits for 12 small businesses
Skills (comma separated):
> C++, Python, Photoshop, Illustrator
ADAEZE OBI
SUMMARY
Computer Science graduate who builds small, honest tools in C++ and
Python.
EXPERIENCE
Graphic Designer — Freelance (2023 - present)
  - Designed brand kits for 12 small businesses
Saved resume.txt (and resume_data.txt, so you can edit and re-render).

Try it in your browser

No browser demo is included for this project. Build the C++ version below — that is the real program.

Related Intermediate projects

← All 60 projects · Classic site (Learn & Sandbox)

Download Fake GPS