Notifications

No notifications

/Phase 1

Variables, auto & References

Storing Data — Modern C++ Style 📦

Variables in C++ work like C, plus three superpowers: auto (let the compiler figure out the type), references (&, a safer pointer), and uniform { } initialisation.

int    age = 19;
double price = 99.99;
char   grade = 'A';
bool   passed = true;
string name = "Asha";        // needs <string>

auto x = 42; // compiler deduces int auto pi = 3.14; // double auto greet = "hello"; // const char*

const int MAX = 100; // never changes after init

References — Aliases for Existing Variables

int score = 50;
int& ref = score;            // ref IS another name for score
ref = 100;
cout << score;               // 100 — same variable!

References are like pointers, but:

  • Cannot be NULL
  • Cannot be reassigned to another variable
  • Use normal . syntax (not -> or *)

Uniform Initialisation

int    a{42};                // brace init (C++11+)
int    b = 42;               // also fine
double c{3.14};
int    d{};                  // d == 0 — zero-init

Brace init catches narrowing conversions: int x{3.14}; is a compile error (good!).

On this page

Detailed Theory

Modern C++ keeps the speed of C variables but adds safety, brevity, and a much larger built-in toolkit.

The Built-In Types

Same as C, with one important addition: bool.

TypeSize (typical)Range
bool1 bytetrue / false
char1 byte-128..127 (or 0..255)
int4 bytes±2 billion
long long8 bytes±9 quintillion
float4 bytes~7 digits precision
double8 bytes~15 digits precision

Use int for normal numbers, long long when ints might overflow (CP problems!), double for decimals.

auto — Let the Compiler Figure It Out

auto x = 42;                 // int
auto y = 3.14;               // double
auto name = string("Asha");  // string
auto v = vector<int>{1,2,3}; // vector<int>

Use auto when:

  • The type is obvious from the right-hand side.
  • The type is verbose (iterators, lambdas, templates).
Don't use auto when:
  • Hiding the type makes the code unclear.
// Verbose without auto:
map<string, vector<int>>::iterator it = m.begin();

// Clean with auto: auto it = m.begin();

const — Promise You Won't Modify It

const int MAX_USERS = 1000;        // can never change
const string GREETING = "hello";

void print(const string& s); // function won't modify s

const everywhere you can. It catches mistakes at compile time and helps optimisation.

> const vs #define: prefer const (or constexpr). It has a type, respects scope, and shows up in the debugger.

constexpr — Compile-Time Constants

constexpr int FACTORIAL_5 = 5 * 4 * 3 * 2 * 1;   // computed at compile time
constexpr double PI = 3.14159265358979;

constexpr is "even more const" — guaranteed to be known at compile time. Use it for true constants and array sizes.

Brace Initialisation { }

The modern, uniform way to initialise:

int     a{42};
double  b{3.14};
string  c{"hello"};
vector<int> v{1, 2, 3, 4};
int     zero{};                   // zero-initialised — value is 0

It also forbids dangerous narrowing conversions:

int x = 3.14;     // compiles — silently truncates to 3
int y{3.14};      // ❌ compile error — narrowing

Prefer { } for initialisation in modern C++.

References (&) — The Safer Pointer

A reference is just another name for an existing variable.

int score = 50;
int& ref = score;             // ref refers to score
ref = 80;
cout << score;                 // 80

Once bound, a reference can't change which variable it refers to. There's no "null reference". Use them for:

1. Pass by Reference (no copy, can modify)

void grow(vector<int>& v) {    // & = pass by reference
    v.push_back(99);            // modifies caller's vector
}

2. Pass by Const Reference (no copy, read-only)

void print(const string& s) {  // big string — no copy, no modify
    cout << s;
}

This is the default way to pass anything bigger than a few ints in modern C++.

3. Range-Based for With References

vector<int> nums = {1, 2, 3};
for (int& n : nums) n *= 2;            // modifies in place
for (const int& n : nums) cout << n;   // read-only, no copy

Reference vs Pointer (Mental Model)

Reference (int&)Pointer (int*)
Can be NULL?NoYes
Reassignable?NoYes
Syntaxnormal x.fieldp->field
Use forfunction args, range-fordata structures, optional refs

> In modern C++, prefer references unless you genuinely need null or reassignment. They eliminate a whole class of bugs.

Type Casting

NeedUse
Numeric conversionstatic_cast(3.7)
Drop constconst_cast (rarely!)
Run-time polymorphic checkdynamic_cast (with virtual classes)
Reinterpret bitsreinterpret_cast (almost never)

double d = 3.14;
int n = static_cast<int>(d);    // n = 3

static_cast covers 99% of conversions safely. Avoid C-style (int)d in new code.

Scope & Lifetime

Variables declared inside { } exist only within that block:

int x = 1;
{
    int y = 2;       // y is alive here
    cout << x + y;
}
// y no longer exists

Initialise where you declare. Don't put declarations at the top of main() (old K&R style); declare at point of first use.

Cheat-Sheet

ActionModern C++
Type-deduced varauto x = 42;
True constantconstexpr int N = 100;
Read-only varconst int n = 5;
Referenceint& r = x;
Const reference (param)void f(const T& x);
Brace initint x{42};
Caststatic_cast(d)

These five tools — auto, const, constexpr, references, brace init — are the foundation of every modern C++ program.