Imagine your computer's memory as a huge apartment building. Each apartment (memory location) has a unique address. A pointer is like having someone's address written on a piece of paper - it tells you WHERE to find them, not WHO they are!
Every variable lives somewhere in memory. The & operator (address-of) tells you WHERE it lives!
// Pointer basics
int x = 42; // Regular variable
int* ptr; // Pointer to int (currently uninitialized - dangerous!)
ptr = &x; // ptr now holds the address of x
cout << "x = " << x << endl; // Prints: 42
cout << "&x = " << &x << endl; // Prints: address (e.g., 0x7ffe5c)
cout << "ptr = " << ptr << endl; // Prints: same address
cout << "*ptr = " << *ptr << endl; // Prints: 42
// Modifying through pointer
*ptr = 100; // Changes the value at the address ptr points to
cout << "x = " << x << endl; // Prints: 100 (x was changed!)
// Multiple pointers to same variable
int* ptr2 = &x;
*ptr2 = 200;
cout << "*ptr = " << *ptr << endl; // Prints: 200 (both see the change)
Pointer arithmetic is like navigating apartments - adding 1 to a pointer moves to the next apartment of that size!
// Array and pointer relationship
int arr[] = {10, 20, 30, 40, 50};
int* ptr = arr; // ptr points to first element
// Different ways to access elements
cout << arr[0] << endl; // 10
cout << *ptr << endl; // 10 (same as arr[0])
cout << *(ptr + 2) << endl; // 30 (same as arr[2])
// Moving through array with pointer
for (int i = 0; i < 5; i++) {
cout << *ptr << " "; // Print current element
ptr++; // Move to next element
}
// Pointer arithmetic with different types
char str[] = "Hello";
char* cptr = str;
cptr++; // Moves 1 byte (size of char)
double values[] = {1.1, 2.2, 3.3};
double* dptr = values;
dptr++; // Moves 8 bytes (size of double)
Static memory is like assigned seating - you know exactly how many seats you need beforehand. Dynamic memory is like a restaurant that can add tables as guests arrive!
// Single variable allocation
int* ptr = new int; // Allocate space for one int
*ptr = 42; // Use it like normal
cout << *ptr << endl; // Prints: 42
delete ptr; // FREE THE MEMORY!
// Array allocation
int size;
cout << "How many numbers? ";
cin >> size;
int* numbers = new int[size]; // Dynamic array!
// Use the array
for (int i = 0; i < size; i++) {
numbers[i] = i * 10;
}
// Print array
for (int i = 0; i < size; i++) {
cout << numbers[i] << " ";
}
delete[] numbers; // FREE THE ARRAY! Note the []
// Common mistake - memory leak!
int* leak = new int;
leak = new int; // Old memory is lost forever!
// Always delete before reassigning!
Memory leaks are like borrowing books from a library and never returning them - eventually, there are no books left for anyone!
// Dynamic array example - Grade management system
class GradeManager {
private:
double* grades;
int capacity;
int size;
public:
GradeManager(int initialCapacity = 10) {
capacity = initialCapacity;
size = 0;
grades = new double[capacity];
}
~GradeManager() {
delete[] grades; // Destructor cleans up!
}
void addGrade(double grade) {
if (size == capacity) {
// Need to grow the array
capacity *= 2;
double* newGrades = new double[capacity];
// Copy old data
for (int i = 0; i < size; i++) {
newGrades[i] = grades[i];
}
// Delete old array
delete[] grades;
grades = newGrades;
}
grades[size++] = grade;
}
double getAverage() {
if (size == 0) return 0;
double sum = 0;
for (int i = 0; i < size; i++) {
sum += grades[i];
}
return sum / size;
}
};
Pointers let functions modify variables directly and work with arrays efficiently!
// Passing pointers to modify variables
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// Array functions always receive pointers
int sumArray(int* arr, int size) {
int sum = 0;
for (int i = 0; i < size; i++) {
sum += arr[i]; // or *(arr + i)
}
return sum;
}
// Returning dynamically allocated memory
int* createArray(int size) {
int* arr = new int[size];
for (int i = 0; i < size; i++) {
arr[i] = i * i;
}
return arr; // Caller must delete[]!
}
// Safe string copy
void safeCopy(char* dest, const char* src, int maxLen) {
int i = 0;
while (src[i] != '\0' && i < maxLen - 1) {
dest[i] = src[i];
i++;
}
dest[i] = '\0';
}
Create a program that manages student records with dynamic memory:
#include <iostream>
#include <string>
using namespace std;
struct Student {
string name;
double grade;
};
class StudentDatabase {
private:
Student* students;
int capacity;
int count;
public:
StudentDatabase() {
// TODO: Initialize with capacity of 5
}
~StudentDatabase() {
// TODO: Clean up memory
}
void addStudent(string name, double grade) {
// TODO: Add student, resize if needed
}
void displayAll() {
// TODO: Show all students
}
double getClassAverage() {
// TODO: Calculate average grade
}
};
StudentDatabase() {
capacity = 5;
count = 0;
students = new Student[capacity];
}
Modern C++ provides smart pointers that automatically manage memory - like having a responsible assistant!
Create a Matrix class using dynamic 2D arrays:
// Allocate 2D array
int** matrix = new int*[rows];
for(int i = 0; i < rows; i++) {
matrix[i] = new int[cols];
}
// Don't forget to delete!
for(int i = 0; i < rows; i++) {
delete[] matrix[i];
}
delete[] matrix;