Module 01: Memory Allocation, References, and Pointers
Key Concepts:
- Stack vs Heap allocation
newanddeleteoperators- References vs Pointers
- Pointers to members
switchstatements
Understanding New Operators in This Module
Section titled “Understanding New Operators in This Module”This module introduces memory management operators. Here’s what they mean:
The new Operator
Section titled “The new Operator”int* ptr = new int; // Allocate memory for one intint* arr = new int[10]; // Allocate memory for 10 intsnewallocates memory on the heap (also called “free store”)- It returns a pointer to the allocated memory
- Memory allocated with
newpersists until you explicitlydeleteit - Unlike
malloc(),newautomatically calculates the size and properly initializes objects
The delete Operator
Section titled “The delete Operator”delete ptr; // Free memory for one objectdelete[] arr; // Free memory for array (NOTE the []!)deletefrees memory that was allocated withnewdelete[](with square brackets) frees arrays allocated withnew[]- CRITICAL: Using
deleteon an array is undefined behavior! - CRITICAL: Using
delete[]on a single object is undefined behavior!
References with &
Section titled “References with &”int& ref = x; // ref is an alias (another name) for x&after a type creates a reference (not a pointer)- A reference is just another name for an existing variable
- When you change
ref, you changex- they are the same variable! - References must be initialized when declared
- References cannot be reassigned to refer to a different variable
Pointer Syntax Review
Section titled “Pointer Syntax Review”int* ptr = &x; // ptr stores the address of x (ptr "points to" x)*ptr = 42; // Dereference ptr to access/modify xptr->method(); // If ptr points to an object, call its method- Remember:
*before a pointer dereferences it (accesses the value) &before a variable gets its address->is shorthand for dereference + member access
The ->* Operator (Pointer to Member)
Section titled “The ->* Operator (Pointer to Member)”void (Class::*ptr)() = &Class::method; // ptr points to a member function(object.*ptr)(); // Call through object(objectPtr->*ptr)(); // Call through pointer to object->*combines the arrow operator with pointer-to-member- It’s used when you have a pointer to an object AND a pointer to one of its members
- This is advanced syntax used for function pointers to member functions
Understanding Memory Layout (Visual Guide)
Section titled “Understanding Memory Layout (Visual Guide)”Understanding how memory is organized helps you write better C++ code:
Memory Layout Overview
Section titled “Memory Layout Overview”┌─────────────────────────────────────┐│ HIGH MEMORY ││ ││ ┌──────────────────────────────┐ ││ │ HEAP │ │ ← Dynamic allocation (new/delete)│ │ (grows downward) │ │ Large, slower, manual cleanup│ │ [Zombie* z] │ ││ │ [Brain* b] ← new Brain() │ ││ └──────────────────────────────┘ ││ ││ ↓ gap ↓ ││ ││ ┌──────────────────────────────┐ ││ │ STACK │ │ ← Automatic allocation│ │ (grows upward) │ │ Fast, small, automatic│ │ │ ││ │ ┌────────────────────┐ │ ││ │ │ main() │ │ ││ │ │ int x = 42; │ │ ││ │ │ Zombie z; │ ← constructor called│ │ │ │ │ ││ │ └────────────────────┘ │ ││ └──────────────────────────────┘ ││ ││ ┌──────────────────────────────┐ ││ │ DATA SEGMENT │ │ ← Global/static variables│ └──────────────────────────────┘ ││ ││ ┌──────────────────────────────┐ ││ │ CODE SEGMENT │ │ ← Program instructions│ └──────────────────────────────┘ ││ ││ LOW MEMORY │└─────────────────────────────────────┘Stack Frame Layout
Section titled “Stack Frame Layout”┌─────────────────────────────────────┐│ Stack Frame for function() │├─────────────────────────────────────┤│ Return address │ ← Where to go back to├─────────────────────────────────────┤│ Saved registers │ ← Previous state├─────────────────────────────────────┤│ Local variables: ││ int x = 42; → [ 42 ] ││ Zombie z; → [ object ] │├─────────────────────────────────────┤│ Function parameters │└─────────────────────────────────────┘ ↑ Stack grows UPObject in Memory
Section titled “Object in Memory”┌─────────────────────────────────────┐│ Contact object on STACK │├─────────────────────────────────────┤│ vptr (hidden) → vtable │ (only if class has virtual functions)├─────────────────────────────────────┤│ std::string _firstName ││ ├─ pointer to heap memory ││ └─ size/capacity info │├─────────────────────────────────────┤│ std::string _lastName │├─────────────────────────────────────┤│ int _age = 25; → [ 25 ] │└─────────────────────────────────────┘1. Stack vs Heap Memory
Section titled “1. Stack vs Heap Memory”Stack Allocation (Automatic)
Section titled “Stack Allocation (Automatic)”void function() { int x = 42; // On stack Zombie zombie; // On stack} // Automatically destroyed hereCharacteristics:
- Fast allocation/deallocation
- Limited size (~1-8 MB typically)
- Automatic cleanup when scope ends
- Cannot outlive function
Heap Allocation (Dynamic)
Section titled “Heap Allocation (Dynamic)”void function() { int* x = new int(42); // On heap Zombie* zombie = new Zombie(); // On heap
// ... use them ...
delete x; // Must manually delete delete zombie; // Must manually delete}Characteristics:
- Slower allocation
- Large capacity (limited by RAM)
- Must be manually freed
- Can outlive function (return pointer)
2. new and delete Operators
Section titled “2. new and delete Operators”Single Object
Section titled “Single Object”// Allocationint* ptr = new int; // Uninitializedint* ptr = new int(); // Zero-initializedint* ptr = new int(42); // Initialized to 42
// Deallocationdelete ptr;ptr = NULL; // Good practice (C++98)Arrays
Section titled “Arrays”// Allocationint* arr = new int[10]; // Array of 10 intsZombie* horde = new Zombie[5]; // Array of 5 Zombies
// Deallocation - NOTE THE []delete[] arr; // MUST use delete[] for arraysdelete[] horde;Common Mistakes
Section titled “Common Mistakes”// WRONG: Using delete on arrayint* arr = new int[10];delete arr; // UNDEFINED BEHAVIOR!
// WRONG: Using delete[] on single objectint* ptr = new int(42);delete[] ptr; // UNDEFINED BEHAVIOR!
// WRONG: Double deleteint* ptr = new int(42);delete ptr;delete ptr; // CRASH or corruption!When to Use Stack vs Heap
Section titled “When to Use Stack vs Heap”| Use Stack When… | Use Heap When… |
|---|---|
| Object’s lifetime = function scope | Object must outlive function |
| Size known at compile time | Size determined at runtime |
| Small objects | Large objects |
| Performance critical | Returning new objects |
3. References
Section titled “3. References”What is a Reference?
Section titled “What is a Reference?”A reference is an alias - another name for an existing variable.
int x = 42;int& ref = x; // ref IS x (not a copy, not a pointer)
ref = 100; // Changes x to 100std::cout << x; // Prints 100References vs Pointers
Section titled “References vs Pointers”| Feature | Reference | Pointer |
|---|---|---|
| Syntax | int& ref = x; | int* ptr = &x; |
| Can be null | No | Yes |
| Can be reassigned | No | Yes |
| Must be initialized | Yes | No |
| Access value | ref | *ptr |
| Access address | &ref | ptr |
Key Rules for References
Section titled “Key Rules for References”// MUST initializeint& ref; // ERROR: references must be initializedint& ref = x; // OK
// CANNOT be nullint& ref = NULL; // ERROR: cannot bind to null
// CANNOT be reassignedint& ref = x;ref = y; // This doesn't reassign ref, it copies y to x!Why References Exist
Section titled “Why References Exist”// BAD: Passing by value (copies entire object)void printZombie(Zombie z) { // z is a COPY - expensive for large objects}
// BETTER: Passing by pointervoid printZombie(Zombie* z) { if (z != NULL) // Must check for null std::cout << z->getName();}
// BEST: Passing by referencevoid printZombie(Zombie& z) { // z is the original object - no copy // Cannot be null - no check needed std::cout << z.getName();}
// CONST reference - read-only accessvoid printZombie(const Zombie& z) { std::cout << z.getName(); // Can read // z.setName("X"); // ERROR: z is const}When to Use What
Section titled “When to Use What”| Situation | Use |
|---|---|
| Never null, won’t change what it refers to | Reference |
| Might be null | Pointer |
| Needs to be reassigned | Pointer |
| Return new object from function | Pointer (or smart pointer in modern C++) |
| Optional parameter | Pointer (can pass NULL) |
4. Memory Address Demonstration (ex02)
Section titled “4. Memory Address Demonstration (ex02)”std::string str = "HI THIS IS BRAIN";std::string* stringPTR = &str; // Pointer TO strstd::string& stringREF = str; // Reference (alias) OF str
// Addresses - all should be the same!std::cout << &str << std::endl; // Address of strstd::cout << stringPTR << std::endl; // Pointer holds same addressstd::cout << &stringREF << std::endl; // Address of ref = address of str
// Values - all should be the same!std::cout << str << std::endl; // Direct accessstd::cout << *stringPTR << std::endl; // Dereference pointerstd::cout << stringREF << std::endl; // Reference is same as original5. Reference vs Pointer in Classes (ex03)
Section titled “5. Reference vs Pointer in Classes (ex03)”Using a Reference (HumanA)
Section titled “Using a Reference (HumanA)”class HumanA {private: std::string _name; Weapon& _weapon; // Reference - MUST always have a weapon
public: // MUST initialize reference in constructor HumanA(std::string name, Weapon& weapon) : _name(name), _weapon(weapon) {}
void attack() { std::cout << _name << " attacks with " << _weapon.getType(); }};
// UsageWeapon club("club");HumanA bob("Bob", club); // MUST provide weapon at constructionUsing a Pointer (HumanB)
Section titled “Using a Pointer (HumanB)”class HumanB {private: std::string _name; Weapon* _weapon; // Pointer - might not have a weapon
public: HumanB(std::string name) : _name(name), _weapon(NULL) {}
void setWeapon(Weapon& weapon) { _weapon = &weapon; }
void attack() { if (_weapon) std::cout << _name << " attacks with " << _weapon->getType(); else std::cout << _name << " has no weapon"; }};
// UsageHumanB jim("Jim"); // No weapon initiallyjim.setWeapon(club); // Weapon added laterDecision Guide
Section titled “Decision Guide”- Reference: When object MUST exist at construction and throughout lifetime
- Pointer: When object might not exist, or might change
6. Pointers to Members (ex05)
Section titled “6. Pointers to Members (ex05)”Function Pointers (C-style)
Section titled “Function Pointers (C-style)”void sayHello() { std::cout << "Hello"; }void sayBye() { std::cout << "Bye"; }
// Function pointervoid (*funcPtr)() = &sayHello;funcPtr(); // Calls sayHello()
funcPtr = &sayBye;funcPtr(); // Calls sayBye()Pointers to Member Functions
Section titled “Pointers to Member Functions”class Harl {public: void debug() { std::cout << "Debug"; } void info() { std::cout << "Info"; } void warning() { std::cout << "Warning"; } void error() { std::cout << "Error"; }
void complain(std::string level) { // Array of member function pointers void (Harl::*funcs[4])() = { &Harl::debug, &Harl::info, &Harl::warning, &Harl::error };
std::string levels[4] = {"DEBUG", "INFO", "WARNING", "ERROR"};
for (int i = 0; i < 4; i++) { if (level == levels[i]) { (this->*funcs[i])(); // Call the member function return; } } }};Syntax Breakdown
Section titled “Syntax Breakdown”// Declarationvoid (ClassName::*pointerName)(parameters);
// AssignmentpointerName = &ClassName::methodName;
// Call via object(object.*pointerName)(args);
// Call via pointer to object(objectPtr->*pointerName)(args);7. switch Statement (ex06)
Section titled “7. switch Statement (ex06)”Basic Syntax
Section titled “Basic Syntax”switch (expression) { case value1: // code break; case value2: // code break; default: // code if no match}Fall-through Behavior
Section titled “Fall-through Behavior”// WITHOUT break - falls through to next caseswitch (level) { case 3: // WARNING std::cout << "Warning message\n"; // No break - falls through! case 2: // INFO std::cout << "Info message\n"; // No break - falls through! case 1: // DEBUG std::cout << "Debug message\n"; break;}
// If level = 3: prints Warning, Info, Debug// If level = 2: prints Info, Debug// If level = 1: prints Debugswitch vs if-else
Section titled “switch vs if-else”// Can only switch on integral types in C++98switch (number) { ... } // OKswitch (character) { ... } // OKswitch (string) { ... } // ERROR in C++98!
// For strings, must use if-elseif (str == "DEBUG") { ... }else if (str == "INFO") { ... }String-to-Integer Conversion for Switch
Section titled “String-to-Integer Conversion for Switch”Since C++98 cannot switch on strings, convert strings to integers first:
// Convert string to index for switchint getLevel(const std::string& level) { std::string levels[4] = {"DEBUG", "INFO", "WARNING", "ERROR"}; for (int i = 0; i < 4; i++) { if (level == levels[i]) return i; } return -1; // Not found}
void complain(const std::string& level) { switch (getLevel(level)) { case 0: std::cout << "Debug message" << std::endl; break; case 1: std::cout << "Info message" << std::endl; break; case 2: std::cout << "Warning message" << std::endl; break; case 3: std::cout << "Error message" << std::endl; break; default: std::cout << "Unknown level" << std::endl; }}This is cleaner than a long if-else chain and allows fall-through behavior.
8. File I/O (ex04)
Section titled “8. File I/O (ex04)”Reading from File
Section titled “Reading from File”#include <fstream>#include <string>
std::ifstream inFile("input.txt");
if (!inFile.is_open()) { std::cerr << "Cannot open file" << std::endl; return 1;}
std::string line;while (std::getline(inFile, line)) { std::cout << line << std::endl;}
inFile.close();Writing to File
Section titled “Writing to File”std::ofstream outFile("output.txt");
if (!outFile.is_open()) { std::cerr << "Cannot create file" << std::endl; return 1;}
outFile << "Hello, World!" << std::endl;outFile << "Line 2" << std::endl;
outFile.close();Reading Entire File into String
Section titled “Reading Entire File into String”std::ifstream inFile("input.txt");std::string content;std::string line;
while (std::getline(inFile, line)) { content += line; content += "\n";}Quick Reference
Section titled “Quick Reference”Memory
Section titled “Memory”// Single objectType* ptr = new Type(args);delete ptr;
// ArrayType* arr = new Type[size];delete[] arr;References
Section titled “References”Type& ref = original; // Create alias// ref is now indistinguishable from originalMember Function Pointers
Section titled “Member Function Pointers”void (Class::*ptr)(args) = &Class::method;(object.*ptr)(args);File I/O
Section titled “File I/O”std::ifstream in("file");std::ofstream out("file");std::getline(in, str);out << content;