Module 7: Pointers and References
Chapter 7 • Intermediate
Pointers and References
Pointers and references are powerful features in C++ that allow you to work directly with memory addresses. They're essential for efficient memory management and advanced programming.
What are Pointers?
A pointer is a variable that stores the memory address of another variable. Instead of storing a value, it stores where the value is located in memory.
Key Concepts:
- Address: Location in memory where data is stored
- Pointer: Variable that holds an address
- Dereference: Accessing the value at an address
Pointer Declaration
Syntax:
type* pointerName;
Example:
int* ptr; // Pointer to int
double* dptr; // Pointer to double
char* cptr; // Pointer to char
Address-of Operator (&)
Gets the memory address of a variable:
int num = 10;
int* ptr = # // ptr now holds address of num
Dereference Operator (*)
Accesses the value at the address stored in a pointer:
int num = 10;
int* ptr = #
cout << *ptr << endl; // Prints 10 (value at address)
Basic Pointer Operations
Example:
int num = 10;
int* ptr = #
cout << "Value of num: " << num << endl; // 10
cout << "Address of num: " << &num << endl; // Memory address
cout << "Value of ptr: " << ptr << endl; // Same address
cout << "Value at ptr: " << *ptr << endl; // 10
Modifying Values Through Pointers
Example:
int num = 10;
int* ptr = #
*ptr = 20; // Changes num to 20
cout << num << endl; // 20
Null Pointers
Pointers that don't point to anything:
int* ptr = nullptr; // C++11 (preferred)
int* ptr2 = NULL; // C-style
int* ptr3 = 0; // Also valid
Always initialize pointers! Uninitialized pointers contain garbage addresses.
Pointer Arithmetic
Pointers can be incremented/decremented to move to adjacent memory locations:
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr; // Points to first element
cout << *ptr << endl; // 10
ptr++; // Move to next element
cout << *ptr << endl; // 20
ptr += 2; // Move 2 elements forward
cout << *ptr << endl; // 40
Important: Pointer arithmetic depends on the size of the data type.
Pointers and Arrays
Arrays and pointers are closely related:
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr; // Array name is pointer to first element
// These are equivalent:
cout << arr[0] << endl; // 10
cout << *arr << endl; // 10
cout << ptr[0] << endl; // 10
cout << *ptr << endl; // 10
Pointers as Function Parameters
Passing pointers allows functions to modify original values:
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
swap(&x, &y); // Pass addresses
cout << x << " " << y << endl; // 20 10
return 0;
}
Dynamic Memory Allocation
new Operator
Allocates memory at runtime:
int* ptr = new int; // Allocate single integer
*ptr = 10;
int* arr = new int[5]; // Allocate array of 5 integers
arr[0] = 10;
arr[1] = 20;
delete Operator
Frees allocated memory:
int* ptr = new int;
*ptr = 10;
delete ptr; // Free single variable
ptr = nullptr; // Good practice
int* arr = new int[5];
delete[] arr; // Free array (use delete[])
arr = nullptr;
Important Rules:
- Every
newmust have a correspondingdelete - Use
deletefor single variables,delete[]for arrays - Set pointer to
nullptrafter deletion - Never delete the same pointer twice
Memory Leaks
Memory leaks occur when allocated memory is not freed:
void leak() {
int* ptr = new int[1000];
// Forgot to delete - memory leak!
}
Prevention:
- Always match
newwithdelete - Use smart pointers (we'll cover later)
- Use RAII (Resource Acquisition Is Initialization)
What are References?
A reference is an alias (another name) for an existing variable. Unlike pointers, references must be initialized and cannot be reassigned.
Key Differences from Pointers:
- Must be initialized when declared
- Cannot be reassigned to point to another variable
- No need for dereference operator
- Cannot be null
Reference Declaration
Syntax:
type& refName = variable;
Example:
int num = 10;
int& ref = num; // ref is alias for num
ref = 20; // Changes num to 20
cout << num << endl; // 20
References as Function Parameters
References allow functions to modify original values without pointers:
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swap(x, y); // Pass variables directly
cout << x << " " << y << endl; // 20 10
return 0;
}
Benefits:
- Cleaner syntax (no
&when calling) - No need to check for null
- Cannot be reassigned accidentally
Const References
Prevent modification while avoiding copying:
void print(const int& value) {
cout << value << endl;
// value = 10; // Error: cannot modify const reference
}
Use const references for:
- Large objects (avoid copying)
- Parameters that shouldn't be modified
- Read-only access
Pointers vs References
| Feature | Pointer | Reference |
|---|---|---|
| **Declaration** | `int* ptr;` | `int& ref = var;` |
| **Initialization** | Can be null | Must initialize |
| **Reassignment** | Can change | Cannot change |
| **Null value** | Can be null | Cannot be null |
| **Dereference** | Need `*` | Automatic |
| **Address** | Has own address | Same as variable |
When to use:
- Pointers: Dynamic memory, optional parameters, arrays, C compatibility
- References: Function parameters, return values, aliases
Pointer to Pointer
Pointers can point to other pointers:
int num = 10;
int* ptr = #
int** pptr = &ptr; // Pointer to pointer
cout << num << endl; // 10
cout << *ptr << endl; // 10
cout << **pptr << endl; // 10
Function Pointers
Pointers that point to functions:
int add(int a, int b) {
return a + b;
}
int main() {
int (*funcPtr)(int, int) = add;
int result = funcPtr(5, 3); // Calls add(5, 3)
return 0;
}
Common Patterns
Pattern 1: Swap Function
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
Pattern 2: Array Parameter
void printArray(int* arr, int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
}
Pattern 3: Return by Reference
int& getElement(int* arr, int index) {
return arr[index];
}
// Usage
int arr[5] = {1, 2, 3, 4, 5};
getElement(arr, 2) = 99; // Modifies arr[2]
Best Practices
- ✅ Always initialize pointers (use
nullptr) - ✅ Check for null before dereferencing pointers
- ✅ Match new with delete (and new[] with delete[])
- ✅ Set pointers to nullptr after deletion
- ✅ Use references for function parameters when possible
- ✅ Use const references for read-only parameters
- ✅ Avoid raw pointers when smart pointers are available
- ✅ Prefer references over pointers when null isn't needed
Common Mistakes
- ❌ Dereferencing null or uninitialized pointers
- ❌ Memory leaks (forgetting to delete)
- ❌ Double deletion (deleting same pointer twice)
- ❌ Using deleted memory
- ❌ Array bounds violations with pointers
- ❌ Mixing up
*(dereference) and&(address-of) - ❌ Trying to reassign references
Next Module
In Module 8, we'll learn about Object-Oriented Programming - how to create classes and objects to model real-world entities!
Hands-on Examples
Basic Pointer Operations
#include <iostream>
using namespace std;
int main() {
int num = 10;
int* ptr = # // ptr stores address of num
cout << "Value of num: " << num << endl;
cout << "Address of num: " << &num << endl;
cout << "Value of ptr (address): " << ptr << endl;
cout << "Value at ptr: " << *ptr << endl;
// Modifying through pointer
*ptr = 20;
cout << "After *ptr = 20, num = " << num << endl;
// Pointer arithmetic
int arr[5] = {10, 20, 30, 40, 50};
int* arrPtr = arr;
cout << "\nArray via pointer:" << endl;
for (int i = 0; i < 5; i++) {
cout << "arr[" << i << "] = " << *(arrPtr + i) << endl;
}
return 0;
}Pointers store memory addresses. Use & to get address, * to dereference. Pointers can be used to access and modify values indirectly. Pointer arithmetic allows moving through arrays.
Practice with Programs
Reinforce your learning with hands-on practice programs