cpp
Pointers Memory
04_Pointers_Memory⚙️cpp
/**
* ============================================================
* C++ POINTERS - FUNDAMENTALS
* ============================================================
*
* This file covers:
* - What are pointers
* - Pointer declaration and initialization
* - Address-of and dereference operators
* - Pointer arithmetic
* - Pointers and arrays
* - Null pointers
*
* Compile: g++ -std=c++17 -Wall 01_pointers.cpp -o pointers
* Run: ./pointers
*
* ============================================================
*/
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
cout << "============================================" << endl;
cout << " C++ POINTERS - FUNDAMENTALS" << endl;
cout << "============================================" << endl << endl;
// ========================================================
// PART 1: WHAT IS A POINTER?
// ========================================================
cout << "--- PART 1: WHAT IS A POINTER? ---" << endl << endl;
/*
* A POINTER is a variable that stores the memory address
* of another variable.
*
* Memory Visualization:
*
* Variable Address Value
* ──────── ───────── ─────
* num 0x1000 42
* ptr 0x1008 0x1000 (points to num)
*
* Key Operators:
* - & (address-of): Gets the address of a variable
* - * (dereference): Accesses the value at an address
*/
int num = 42;
int* ptr = # // ptr holds the address of num
cout << "Variable: num" << endl;
cout << " Value: " << num << endl;
cout << " Address: " << &num << endl;
cout << "\nPointer: ptr" << endl;
cout << " Value (address it holds): " << ptr << endl;
cout << " Dereferenced (*ptr): " << *ptr << endl;
cout << " Address of ptr itself: " << &ptr << endl;
cout << endl;
// ========================================================
// PART 2: POINTER DECLARATION
// ========================================================
cout << "--- PART 2: POINTER DECLARATION ---" << endl << endl;
// Different ways to declare pointers (all equivalent)
int* ptr1; // Preferred style
int *ptr2; // Also valid
int * ptr3; // Also valid
// Declare and initialize
int value = 100;
int* pValue = &value;
// Multiple pointers on same line (careful!)
int *p1, *p2; // Both are pointers
int* p3, p4; // CAREFUL: p3 is pointer, p4 is int!
// Different pointer types
double d = 3.14;
double* pDouble = &d;
char c = 'A';
char* pChar = &c;
cout << "int* pValue = &value; // " << *pValue << endl;
cout << "double* pDouble = &d; // " << *pDouble << endl;
cout << "char* pChar = &c; // " << *pChar << endl;
cout << "\n⚠️ Pointer type must match variable type!" << endl;
cout << " int* cannot point to double, etc." << endl;
cout << endl;
// ========================================================
// PART 3: ADDRESS-OF AND DEREFERENCE
// ========================================================
cout << "--- PART 3: & AND * OPERATORS ---" << endl << endl;
int x = 10;
int* px = &x; // & gets the address of x
cout << "int x = 10;" << endl;
cout << "int* px = &x;" << endl << endl;
cout << "&x (address of x): " << &x << endl;
cout << "px (pointer value): " << px << endl;
cout << "*px (dereferenced): " << *px << endl;
// Modify through pointer
cout << "\nModifying x through pointer:" << endl;
cout << "Before: x = " << x << endl;
*px = 50; // Change the value at the address px points to
cout << "After *px = 50: x = " << x << endl;
// Chain of operations
cout << "\nExpression breakdown:" << endl;
cout << "x = " << x << endl;
cout << "&x = " << &x << endl;
cout << "*&x = " << *&x << " (same as x)" << endl;
cout << "&*px = " << &*px << " (same as px)" << endl;
cout << endl;
// ========================================================
// PART 4: POINTER SIZES
// ========================================================
cout << "--- PART 4: POINTER SIZES ---" << endl << endl;
cout << "Size of pointers on this system:" << endl;
cout << "sizeof(int*): " << sizeof(int*) << " bytes" << endl;
cout << "sizeof(double*): " << sizeof(double*) << " bytes" << endl;
cout << "sizeof(char*): " << sizeof(char*) << " bytes" << endl;
cout << "sizeof(void*): " << sizeof(void*) << " bytes" << endl;
cout << "\n💡 All pointer types have the same size" << endl;
cout << " (typically 8 bytes on 64-bit systems)" << endl;
cout << endl;
// ========================================================
// PART 5: NULL POINTERS
// ========================================================
cout << "--- PART 5: NULL POINTERS ---" << endl << endl;
/*
* A null pointer points to nothing (address 0)
* Used to indicate "no valid address"
*
* C++11: Use nullptr (preferred)
* Old C/C++: Use NULL or 0
*/
int* nullPtr = nullptr; // Modern C++ way
int* nullPtr2 = NULL; // Old way (still works)
int* nullPtr3 = 0; // Also works, not recommended
cout << "nullptr value: " << nullPtr << endl;
// Always check before dereferencing!
if (nullPtr != nullptr) {
cout << "Safe to dereference" << endl;
} else {
cout << "Pointer is null - do not dereference!" << endl;
}
// Shorthand null check
if (nullPtr) { // Same as: if (nullPtr != nullptr)
cout << "Pointer is valid" << endl;
} else {
cout << "Pointer is null" << endl;
}
// ⚠️ Dereferencing nullptr causes UNDEFINED BEHAVIOR!
// *nullPtr; // CRASH! Never do this!
cout << endl;
// ========================================================
// PART 6: POINTER ARITHMETIC
// ========================================================
cout << "--- PART 6: POINTER ARITHMETIC ---" << endl << endl;
/*
* Pointer arithmetic moves by the SIZE of the pointed type
*
* ptr + 1: moves forward by sizeof(*ptr) bytes
* ptr - 1: moves backward by sizeof(*ptr) bytes
*/
int arr[] = {10, 20, 30, 40, 50};
int* p = arr; // Points to first element
cout << "Array: {10, 20, 30, 40, 50}" << endl << endl;
cout << "int* p = arr;" << endl;
cout << "*p = " << *p << " (element 0)" << endl;
cout << "*(p+1) = " << *(p+1) << " (element 1)" << endl;
cout << "*(p+2) = " << *(p+2) << " (element 2)" << endl;
cout << "*(p+3) = " << *(p+3) << " (element 3)" << endl;
cout << "*(p+4) = " << *(p+4) << " (element 4)" << endl;
// Show actual addresses
cout << "\nAddresses (showing pointer arithmetic):" << endl;
cout << "p+0 = " << (p+0) << endl;
cout << "p+1 = " << (p+1) << " (+" << sizeof(int) << " bytes)" << endl;
cout << "p+2 = " << (p+2) << " (+" << 2*sizeof(int) << " bytes)" << endl;
// Increment and decrement
cout << "\nIncrement/Decrement:" << endl;
p = arr;
cout << "*p = " << *p << endl;
p++; // Move to next element
cout << "After p++: *p = " << *p << endl;
p += 2; // Move forward by 2
cout << "After p+=2: *p = " << *p << endl;
p--; // Move back by 1
cout << "After p--: *p = " << *p << endl;
cout << endl;
// ========================================================
// PART 7: POINTERS AND ARRAYS
// ========================================================
cout << "--- PART 7: POINTERS AND ARRAYS ---" << endl << endl;
int numbers[] = {1, 2, 3, 4, 5};
int* pArr = numbers; // Array name is a pointer to first element
cout << "Array name acts like a pointer:" << endl;
cout << "numbers = " << numbers << endl;
cout << "&numbers[0] = " << &numbers[0] << " (same!)" << endl;
cout << "pArr = " << pArr << endl;
cout << "\nTwo ways to access elements:" << endl;
for (int i = 0; i < 5; i++) {
cout << "numbers[" << i << "] = " << numbers[i]
<< " *(pArr+" << i << ") = " << *(pArr+i) << endl;
}
// Array notation vs pointer notation
cout << "\nEquivalent expressions:" << endl;
cout << "arr[i] ←→ *(arr + i)" << endl;
cout << "&arr[i] ←→ arr + i" << endl;
cout << endl;
// ========================================================
// PART 8: POINTER TO POINTER
// ========================================================
cout << "--- PART 8: POINTER TO POINTER ---" << endl << endl;
int val = 100;
int* pVal = &val;
int** ppVal = &pVal; // Pointer to pointer
cout << "int val = 100;" << endl;
cout << "int* pVal = &val;" << endl;
cout << "int** ppVal = &pVal;" << endl << endl;
cout << "val = " << val << endl;
cout << "*pVal = " << *pVal << " (value through pointer)" << endl;
cout << "**ppVal = " << **ppVal << " (value through pointer to pointer)" << endl;
cout << "\nAddresses:" << endl;
cout << "&val = " << &val << endl;
cout << "pVal = " << pVal << " (holds &val)" << endl;
cout << "&pVal = " << &pVal << endl;
cout << "ppVal = " << ppVal << " (holds &pVal)" << endl;
cout << "*ppVal = " << *ppVal << " (holds &val)" << endl;
cout << endl;
// ========================================================
// PART 9: CONST AND POINTERS
// ========================================================
cout << "--- PART 9: CONST AND POINTERS ---" << endl << endl;
int a = 10, b = 20;
// Pointer to const (can't modify value through pointer)
const int* pc = &a;
// *pc = 100; // ERROR: can't modify
pc = &b; // OK: can change what it points to
// Const pointer (can't change what it points to)
int* const cp = &a;
*cp = 100; // OK: can modify value
// cp = &b; // ERROR: can't change pointer
// Const pointer to const (can't do either)
const int* const cpc = &a;
// *cpc = 100; // ERROR
// cpc = &b; // ERROR
cout << "const int* pc: Can't modify *pc, can reassign pc" << endl;
cout << "int* const cp: Can modify *cp, can't reassign cp" << endl;
cout << "const int* const cpc: Can't do either" << endl;
cout << "\n💡 Read right to left:" << endl;
cout << "const int* p → p is a pointer to const int" << endl;
cout << "int* const p → p is a const pointer to int" << endl;
cout << endl;
cout << "============================================" << endl;
cout << "POINTERS SUMMARY:" << endl;
cout << "============================================" << endl;
cout << "• Pointer stores memory address" << endl;
cout << "• & gets address, * dereferences" << endl;
cout << "• Use nullptr for null pointers" << endl;
cout << "• Always check for nullptr before use" << endl;
cout << "• Arrays decay to pointers" << endl;
cout << "• const placement matters!" << endl;
cout << "============================================" << endl;
return 0;
}
// ============================================================
// EXERCISES:
// ============================================================
/*
* 1. Write a function that swaps two integers using pointers
*
* 2. Write a function that reverses an array using pointers only
* (no array indexing [])
*
* 3. Write a function that finds the maximum element in an array
* using pointer arithmetic
*
* 4. Create a pointer to a 2D array and traverse it
*
* 5. Write a function that returns a pointer to the largest
* element in an array
*/