ScAs: C17 Explained for Beginners
Let’s go through Chapter 17 in a very beginner-friendly way, with lots of “why you should / shouldn’t do this” and clear examples.
This chapter’s big idea: pointers are powerful, but easy to mess up, so modern C++ often prefers references and containers like vector, but you still need pointers for certain situations (legacy code, constrained systems, dynamic memory, polymorphism, etc.).
1) What “memory” is (and what an “address” is)
Your computer’s RAM is like a huge row of tiny boxes called bytes. Each byte has a number label. That label is a memory address.
A memory address is just “where something lives”.
Memory addresses are often shown in hex (hexadecimal) form (like
0x7ffd...).
& (address-of operator)
C++ lets you ask “what’s the address of this object?” using &.
int x = 42;
cout << &x << "\n"; // prints the memory address of x
Why this matters: pointers store addresses, so you often use & to put an address into a pointer.
2) What a pointer is (and how * and -> work)
A pointer is a variable that stores the memory address of another object.
Declaring a pointer
int x = 42;
int* p = &x; // p “points to” x
pcontains x’s address (not the value 42).If
xmoves (it usually doesn’t), the address would change, andpwould be wrong.
* (indirection / dereference operator)
To get the value at the address a pointer holds, you dereference it with *.
cout << *p << "\n"; // prints 42
*p = 100; // changes x to 100
cout << x << "\n"; // prints 100
Why you should be careful: dereferencing means “walk to that memory address and use what’s there.” If the pointer is wrong, you might crash or corrupt memory.
-> (member access through a pointer)
If a pointer points to an object, you use -> to access its members.
string s = "hi";
string* ps = &s;
cout << ps->size() << "\n"; // same as (*ps).size()
3) Null pointers (nullptr) and why dereferencing them is a disaster
A null pointer points to “nothing” and should not be dereferenced.
int* p = nullptr;
cout << *p; // VERY BAD
Why not? Because you’re trying to use memory at “no real address.” That’s like saying “open mailbox ‘nothing’.”
4) Pointers vs references (and why references are often better)
This chapter strongly hints at modern best practice: avoid raw pointers when you can, because they’re error-prone; prefer references and STL vectors most of the time.
Passing into functions: pointer vs reference
Pointer version (more annoying / more risky):
You might need to check for null before dereferencing.
Callers often must use
&to pass the address.
Reference version (simpler):
A reference can’t be null, so no null checks.
No dereferencing needed, no
&needed in the call.
The chapter basically says: it usually makes sense to use reference parameters instead of pointer parameters.
When pointers as parameters do make sense
The chapter gives two main reasons:
when you need to pass “no object” (null) as a valid possibility
when you want to change what the pointer points to
Also: built-in arrays “decay” to pointers when passed to functions, so pointer parameters are common there.
5) Storage types: stack vs heap (free store)
When a program starts, the system sets aside different “areas” of memory (storage).
Automatic storage (stack)
Local variables live here. It’s fast and automatically cleaned up, but limited; you can run out → stack overflow.
Free store (heap)
Dynamic memory you allocate while the program runs. It’s flexible and bigger, but:
slower to access
you must manually allocate/deallocate
if you don’t deallocate, you risk memory leaks or heap corruption
6) new and delete (dynamic allocation) + common mistakes
To work with free store memory:
newallocates and returns a pointerdeletedeallocates (returns memory to the free store)
Example: allocate a single object
double* pi = new double; // allocate
*pi = 3.14;
delete pi; // deallocate
pi = nullptr; // good habit: avoid dangling pointer
Example: allocate an array
double* arr = new double[10]; // allocate array
// ...
delete[] arr; // must use delete[] for arrays
arr = nullptr;
Memory leak (the classic “why not”)
If you forget delete, the memory is never returned and can’t be reused: memory leak. For long-running programs, leaks can pile up and hurt performance.
Rule of thumb: if you used new, you must ensure delete happens exactly once.
7) RAII: the “don’t forget to delete” solution
RAII means: wrap the heap resource inside an object, so when the object is destroyed, its destructor automatically cleans up.
The chapter: RAII uses how the stack creates/destroys objects to automatically allocate/deallocate free store memory.
Huge rule: for RAII to work, the object must be on the stack; if it’s on the heap, its destructor won’t run automatically when it goes out of scope.
8) Shallow copy vs deep copy (and the Rule of Three)
When your class has a pointer member, the compiler-generated copy operations often copy the pointer, not the data it points to — that’s a shallow copy.
Why shallow copy is dangerous
If two objects end up with pointers to the same heap array, then both destructors might call delete[] on the same memory → memory corruption.
Deep copy
A deep copy copies the underlying data, not just the pointer.
Rule of Three
If you need to write any of these:
destructor
copy constructor
copy assignment operator
…you should write all three, because they work together to manage ownership safely.
The chapter’s MyContainer example shows:
copy constructor allocates new array and copies elements
explains why deep copy is critical and what goes wrong otherwise
copy assignment uses a temp array for exception safety (so object won’t end half-updated)
9) Move semantics (Rule of Five): faster than copying
C++11 introduced move semantics: transfer existing data instead of copying it, which is more efficient.
To implement move semantics in your class:
write a move constructor and move assignment operator
An rvalue reference (&&) indicates the object can be moved.
What a move does (intuitively)
The chapter’s move constructor logic:
copy the pointer from the source to the destination
set source pointer to null
This avoids allocating a new array and copying every element, which is why it’s faster.
Rule of Five
If you define any of these, define all five:
destructor
copy constructor
copy assignment
move constructor
move assignment
10) Smart pointers: “RAII for you automatically”
The chapter says: if you just want simple dynamic allocation, it may not make sense to write full RAII + Rule of Three/Five — use smart pointers instead.
Smart pointers use RAII “under the hood” to deallocate automatically.
You include:
#include <memory>
unique_ptr (most common)
only one owner
cannot be copied, can be moved
memory is deallocated when it goes out of scope
The chapter also notes: unique_ptr has less overhead than shared_ptr and is appropriate for most purposes.
Example from the chapter:
unique_ptr<int> ptr(new int);
*ptr = 4;
*ptr *= *ptr;
cout << *ptr << endl; // 16
shared_ptr
multiple owners allowed
reference count; deallocates when count hits zero
weak_ptr
copy of a
shared_ptrbut doesn’t increase reference counthelps avoid circular references that keep count from reaching zero
make_unique (C++14+)
The chapter shows make_unique() as a cleaner way to create unique_ptrs (lets you avoid new and use auto).
11) Pointer arithmetic (why it exists, why to be careful)
Pointer arithmetic moves a pointer forward/backward along memory; usually only used with pointers to arrays.
Why you should be careful: move too far and you point outside the array → undefined behavior (bugs/crashes).
(Also note: with smart pointers like unique_ptr, the chapter points out you can’t use pointer arithmetic.)
12) void* (generic pointer): “points to anything, but you don’t know what”
A void pointer can point to any data type.
Why not to use it much in modern C++: because you lose type safety—you need casting to use it meaningfully, which is error-prone.
13) Pointers + inheritance (polymorphism)
A pointer to a superclass can store the address of a subclass object.
But:
you can only call superclass members through a superclass pointer
if you call a virtual member, C++ uses polymorphism to call the subclass override
That’s a huge real-world use of pointers.
14) Complex compound types (how to read scary pointer declarations)
You can have pointers to pointers, references to pointers, const pointers, pointers-to-const, etc. The chapter notes you can’t have a pointer to a reference (references don’t have their own address).
Helpful tip from the chapter: read complex types right to left.
What to focus on to “master” Chapter 17
If you can confidently explain and write small examples for these, you’re solid:
&,*,->, and null pointersstack vs free store (heap): benefits/drawbacks, why leaks happen
new/deleteand how leaks occur if delete is forgottenwhy shallow copy breaks classes with pointers + Rule of Three
move semantics + Rule of Five + why it’s faster
smart pointers and when to use
unique_ptrvsshared_ptr