← Back to all posts

01 C++ Notes

Getting Started with C++

C++ Notes


Compiler and Debugger Tools

Three tools sit behind every C++ program you run. Two of them turn your source code into something the machine can execute, the third helps you when execution goes wrong.

ToolRole
gccCompiler used for C code
g++Compiler used for C++ code
gdbDebugger, used after the compilation process is finished

Your First Program: Hello World

cout and cin Internals


Errors and Warnings

TypeWhen CaughtWhat Happens
Compile Time ErrorCompile timeCompilation fails, no execution happens at all. Caused by illegal code such as invalid syntax or broken semantic rules.
Runtime ErrorDuring executionCompilation succeeds, but the program hits an invalid operation while running. May crash and terminate the program.
WarningCompile timeCompilation and execution both succeed. The code is legal but suspicious, and it should not be ignored.

Functions, the Basics


Real Compilation Flags (VS Code Setup)

Add these flags to your VS Code tasks.json under args to enable the C++20 standard and turn on strict warnings.

-std=c++20 → enables C++20 standard features
-Wall → enables all common warnings
-Wextra → enables extra warnings beyond -Wall
-pedantic-errors → enforces strict standard compliance and turns warnings into errors

Turning warnings into errors with -pedantic-errors feels strict at first, but it catches the exact kind of "technically works, secretly wrong" code that C++ makes it easy to write by accident.


Input and Output

The Streams

StreamTypeRole
coutstd::ostreamPrints data to console
cerrstd::ostreamPrints error messages to console. Not buffered
clogstd::ostreamPrints log messages to console. Buffered
cinstd::istreamReads data from console
getlinefunctionstd::getline(std::cin, name) reads a full line including spaces, using the cin object under the hood

Data Flow


The Leftover Newline Problem

When you read an integer with cin >> x, the newline character you pressed to submit it stays behind in the buffer. If getline runs right after, it immediately reads that leftover newline instead of waiting for real input, and hands you back an empty string.

Fix 1 → std::cin.ignore()
Fix 2 (preferred) → std::getline(std::cin >> std::ws, name)

ignore() only clears one character, so it quietly breaks the moment there's more than a single stray newline in the buffer. std::ws clears everything leading, which is why it's the one to reach for by default.


How a Program Actually Runs: The Execution Memory Model

When a program runs, the OS loads it into memory. The program area holds the instructions. Variables live in a separate data area in RAM. The CPU fetches instructions from the program area, executes them, and returns to the next instruction using a return address stored in its own register.

Hard Drive
source code lives here
  a = 10       (int)
  b = 5        (int)
  c = f_add(a,b)
  ...
RAM
Program Area
0001a = 10 (int)
0002b = 5 (int)
0003c (int)
0004print("S1")
0005print("S2")
0006c = f_add(a,b)
0007print("S3")
0008print("S4")
0009end
Variable Storage
0020a = 10
0021b = 5
0022c = 15
CPU
Registers
RET = 0006
fetches instruction from program area, executes it, stores result back to RAM
Console
Statement1
Statement2
(buffered output)

Step by step, this is what actually happens from launch to exit:

  1. Your source code sits on the hard drive. It's just a text file with instructions, nothing is running yet.
  2. When you run the program, the OS loads it from the hard drive into RAM. The instructions go into the program area and get assigned memory addresses, like 0001, 0002, and so on.
  3. The CPU starts at address 0001 and fetches the first instruction. It reads it, executes it, then moves on to the next address.
  4. When a variable is declared, like a = 10, the value gets stored in a separate section of RAM called variable storage. The CPU reads from and writes to this area as needed.
  5. When a function is called, like f_add(a, b), the arguments are pushed onto the stack in RAM. The CPU stores a return address in its register so it knows exactly where to come back to once the function finishes.
  6. When a print statement runs, the data goes into the cout buffer first. The buffer flushes to the console when it's full, on endl, or right before input is taken.
  7. When the program ends with return 0, the OS clears the RAM it had allocated and the process terminates.

Code Example: main.cpp

C++
#include <iostream>

// function declaration must appear before main
int sum(int a, int b);

int main() {
    std::cout << "Enter first num: ";  // prints: Enter first num:
    int first;
    std::cin >> first;               // reads integer from keyboard

    std::cout << "Enter second num: "; // prints: Enter second num:
    int second;
    std::cin >> second;              // reads integer from keyboard

    // std::cin.ignore() discards only ONE leftover newline, may fail if more whitespace
    // better approach below using std::ws

    int result = sum(first, second);  // calls sum(), stores return value

    std::string name;
    std::cout << "What is your name: "; // prints: What is your name:
    std::getline(std::cin >> std::ws, name); // std::ws discards leftover whitespace first

    std::cout << "Hello : " << name << '\n'; // prints: Hello : Hassan
    std::cout << "Result: " << result << '\n'; // prints: Result: 15

    return 0; // reports success to OS
}

// function definition can appear after main since we declared it above
int sum(int x, int y) {
    int z = x + y;
    return z; // returns result back to caller
}
Console Output
Enter first num: 10 Enter second num: 5 What is your name: Hassan Hello : Hassan Result: 15


C++ Features

C++ is built in three layers, and each one depends on the one before it.

Core Language

The basic building blocks of C++ itself. It defines the rules, syntax, and behavior of the language, and it's the foundation everything else is written on. Nothing else in C++ can exist without this layer.

Standard Library

A collection of ready-to-use components built using C++'s own core features. It handles common tasks so you don't have to deal with low-level details manually every time, which is what makes real-world programming practical and efficient.

HeaderProvides
<iostream>cin, cout
<string>std::string
<fstream>File handling
<cmath>Math functions

STL, the Standard Template Library

A specialized subset of the Standard Library that gives you practical, optimized implementations of common data structures and algorithms, so you don't have to build them from scratch. It's built using templates, which is exactly why every STL component works with any data type without needing to be rewritten per type.

PartRoleExamples
ContainersData structures that store datavector, map, set
AlgorithmsOperations you run on datasort, find, count
IteratorsGeneralized pointers used to traverse containers, connecting algorithms to containers

STL is where C++ stops feeling low-level. Everything up to here is the language itself, this is the toolbox built on top of it.


Closing

That covers the ground floor: tools, hello world, how input and output actually move through the program, and where C++ as a language ends and its libraries begin. Next up, the data types themselves.

Next → 02 - Variables and Data Types