Basics, Pointers and References
7 pages · ~5 min✓ Reviewed
Builds on Build Tooling and Linking. Next up: Classes and OOP.
Types, Const and the Mental Model
1. Types and Init
- Statically typed: every variable's type is fixed at compile time
- Sizes are implementation-defined:
int>= 16 bits (typically 32),long long>= 64 - Exact width:
int32_t,uint64_tfrom<cstdint> auto x = 5;deducesint, drops top-level const and references
| Init | Result |
|---|---|
int x{5}; | OK |
int x{3.5}; | error: narrowing rejected |
int x = 3.5; | silently truncates to 3 |
2. const and constexpr
const int n = 10;is read-only after init and must be initializedconstexpralso needs a compile-time value- So it can size arrays:
constexpr int N = 8; int a[N];
| Declaration | Meaning |
|---|---|
const int* p | pointer to const data: no *p = ... |
int* const p | const pointer: cannot reseat p |
const int* const p | both fixed |
Read right to left
int* const p reads: p is a const pointer to int.
3. Common Mistakes
- Signed
intoverflow is undefined behavior -1 < 1uis false: the signed value converts to unsigned- Uninitialized locals hold garbage: always initialize
References vs Pointers and Pass by Value
1. Reference vs Pointer
| Reference | Pointer | |
|---|---|---|
| Declare | int& r = x; | int* p = &x; |
| Initialized | must be | optional |
| Null | never | nullptr ok |
| Reseat | never | yes |
| Access | r (no dereference) | *p, p->m |
cpp
int x = 5; int& r = x; // alias of x int* p = &x; // address of x r = 7; // x is 7 *p = 9; // x is 9
& takes an address, * dereferences
- Required, never null: reference
- Optional or must be reseated: pointer
sizeof(p)is 8 bytes on 64-bit; a reference has no address of its own
2. Parameter Passing
Arrays, std::array and Pointer Decay
1. C Array and Decay
int a[5] = {1,2,3};fixed size, contiguous- Trailing elements zeroed only with an initializer list
- No bounds check:
a[5]is UB - Passed to a function, it decays to
int* void f(int a[])is reallyvoid f(int* a)
cpp
int a[5]{}; sizeof(a); // 20, true array void f(int* p) { sizeof(p); } // 8 // pass the length: f(a, 5)
size is lost after decay
2. std::array
std::array<int,5> a{1,2,3,4,5};zero-overhead wrapper- Has
.size(), range-for, copy by= .at(i)checks bounds, throwsstd::out_of_range- Does not decay
| C array | std::array | std::vector | |
|---|---|---|---|
| Size | fixed | fixed | runtime |
| Storage | stack | stack | heap |
Stack vs Heap, new/delete and nullptr
1. Stack vs Heap
| Stack | Heap | |
|---|---|---|
| Holds | locals, automatic | new objects |
| Freed | LIFO, at scope end | when you delete |
| Speed | very fast | slower, may fragment |
| Size | small, ~1 to 8 MB | large |
| Risk | stack overflow | leaks |
2. new/delete and nullptr
cpp
int* p = new int{5};
delete p;
p = nullptr;
int* a = new int[3];
delete[] a; // new[] pairs with delete[]nullptrhas type std::nullptr_t; prefer it overNULLor0f(nullptr)picks the pointer overload,f(0)picks intdelete nullptris safe; dereferencing it is UB
3. RAII and Mistakes
std::make_unique<T>()frees at scope end
Function Overloading and the Header/Compilation Model
1. Overloads and Resolution
- Same name, different parameter lists (count or types)
- Return type alone cannot tell overloads apart
f(int&)vsf(const int&)are distinct overloads
| Rank | Match | Example |
|---|---|---|
| 1 | Exact | int to int |
| 2 | Promotion | char to int |
| 3 | Conversion | int to double |
| 4 | User-defined | converting constructor |
| Tie | Ambiguity error | f(5) with f(long), f(double) |
2. Build Pipeline
- Preprocessor#include, #define
- Compilerone .cpp = one unit + object file
- Linkerresolves symbols
C++ Fundamentals Cheat Sheet
1. Types and Parameters
- Prefer brace init
int x{5];autowhen obvious int32_t,uint64_tfrom<cstdint>for fixed widthconstexpr= compile-time;consteverywhere possible- Read const right to left:
const int* const p
| Need | Pass |
|---|---|
| Small type | by value |
| Large read-only | const T& |
| Modify caller | T& |
| Optional / nullable | T* |
2. Arrays and Memory
- Prefer
std::arrayorstd::vector;.at(i)checks bounds - C arrays decay to pointers when passed
- Stack: automatic, fast. Heap:
new/delete,new[]/delete[] - Prefer
make_unique; usenullptr; reset tonullptrafter delete
3. Build and Overloads
Check yourself
With int arr[5]; and void g(int a[]) that prints sizeof(a), what does g(arr) print on a 64-bit machine?
- 8, the size of a pointer.
- The array decays to
int*in the call, so its length is lost.
Spot the bug: int* p = new int[3]; delete p;
new[]must pair withdelete[]; mixing them is undefined behavior.- Better: use
std::vectorormake_unique.
Given f(long) and f(double), what happens with f(5)?
- Compile error: ambiguous call.
inttolongandinttodoubleare both conversions, so neither wins.