cpp
examples
examples.cpp⚙️cpp
/**
* Pointers in C++ - Comprehensive Examples
*
* Demonstrates:
* - Pointer declaration and initialization
* - Pointer operators (& and *)
* - Pointer arithmetic
* - Pointers and arrays
* - Pointers to pointers
* - const with pointers
*
* Compile: g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
* Run: ./examples
*/
#include <iostream>
#include <string>
#include <cstdint>
using namespace std;
// ============================================================
// SECTION 1: POINTER BASICS
// ============================================================
void demonstrateBasicPointers() {
cout << "--- Basic Pointer Concepts ---\n" << endl;
// Variable declaration
int x = 42;
// Pointer declaration and initialization
int* ptr = &x; // ptr holds address of x
cout << "Variable x:" << endl;
cout << " Value: " << x << endl;
cout << " Address (&x): " << &x << endl;
cout << " Size: " << sizeof(x) << " bytes" << endl;
cout << "\nPointer ptr:" << endl;
cout << " Value (address it holds): " << ptr << endl;
cout << " Dereferenced (*ptr): " << *ptr << endl;
cout << " Address of ptr (&ptr): " << &ptr << endl;
cout << " Size: " << sizeof(ptr) << " bytes" << endl;
// Modifying through pointer
*ptr = 100;
cout << "\nAfter *ptr = 100:" << endl;
cout << " x = " << x << endl;
cout << " *ptr = " << *ptr << endl;
}
void demonstratePointerTypes() {
cout << "\n--- Different Pointer Types ---\n" << endl;
int intVar = 42;
double doubleVar = 3.14159;
char charVar = 'A';
bool boolVar = true;
int* intPtr = &intVar;
double* doublePtr = &doubleVar;
char* charPtr = &charVar;
bool* boolPtr = &boolVar;
cout << "int* points to " << *intPtr << " at " << intPtr << endl;
cout << "double* points to " << *doublePtr << " at " << doublePtr << endl;
cout << "char* points to '" << *charPtr << "' at " << static_cast<void*>(charPtr) << endl;
cout << "bool* points to " << boolalpha << *boolPtr << " at " << boolPtr << endl;
cout << "\nPointer sizes on this system:" << endl;
cout << " sizeof(int*): " << sizeof(intPtr) << " bytes" << endl;
cout << " sizeof(double*): " << sizeof(doublePtr) << " bytes" << endl;
cout << " sizeof(char*): " << sizeof(charPtr) << " bytes" << endl;
cout << " sizeof(void*): " << sizeof(void*) << " bytes" << endl;
}
void demonstrateNullptr() {
cout << "\n--- nullptr Demonstration ---\n" << endl;
int* ptr = nullptr; // Modern C++ way
cout << "ptr initialized to nullptr" << endl;
cout << "ptr value: " << ptr << endl;
// Check before dereferencing
if (ptr == nullptr) {
cout << "ptr is null - safe check passed" << endl;
}
// Alternative check using boolean conversion
if (!ptr) {
cout << "ptr is null - boolean check passed" << endl;
}
// Now assign a valid address
int x = 42;
ptr = &x;
if (ptr != nullptr) {
cout << "\nptr now points to value: " << *ptr << endl;
}
}
// ============================================================
// SECTION 2: POINTER ARITHMETIC
// ============================================================
void demonstratePointerArithmetic() {
cout << "\n--- Pointer Arithmetic ---\n" << endl;
int arr[] = {10, 20, 30, 40, 50};
int* ptr = arr; // Points to arr[0]
cout << "Array: 10, 20, 30, 40, 50" << endl;
cout << "Initial ptr points to: " << *ptr << " at " << ptr << endl;
// Increment
ptr++;
cout << "\nAfter ptr++:" << endl;
cout << " ptr points to: " << *ptr << " at " << ptr << endl;
// Add offset
ptr += 2;
cout << "\nAfter ptr += 2:" << endl;
cout << " ptr points to: " << *ptr << " at " << ptr << endl;
// Decrement
ptr--;
cout << "\nAfter ptr--:" << endl;
cout << " ptr points to: " << *ptr << " at " << ptr << endl;
// Reset and show arithmetic
ptr = arr;
cout << "\nPointer arithmetic with different offsets:" << endl;
for (int i = 0; i < 5; i++) {
cout << " *(ptr + " << i << ") = " << *(ptr + i) << endl;
}
}
void demonstratePointerSizeArithmetic() {
cout << "\n--- Pointer Size-Aware Arithmetic ---\n" << endl;
char charArr[] = {'A', 'B', 'C', 'D', 'E'};
int intArr[] = {1, 2, 3, 4, 5};
double doubleArr[] = {1.1, 2.2, 3.3, 4.4, 5.5};
char* charPtr = charArr;
int* intPtr = intArr;
double* doublePtr = doubleArr;
cout << "char* increment (sizeof char = " << sizeof(char) << "):" << endl;
cout << " charPtr: " << static_cast<void*>(charPtr) << endl;
charPtr++;
cout << " charPtr + 1: " << static_cast<void*>(charPtr) << " (moved " << sizeof(char) << " byte)" << endl;
cout << "\nint* increment (sizeof int = " << sizeof(int) << "):" << endl;
cout << " intPtr: " << intPtr << endl;
intPtr++;
cout << " intPtr + 1: " << intPtr << " (moved " << sizeof(int) << " bytes)" << endl;
cout << "\ndouble* increment (sizeof double = " << sizeof(double) << "):" << endl;
cout << " doublePtr: " << doublePtr << endl;
doublePtr++;
cout << " doublePtr + 1: " << doublePtr << " (moved " << sizeof(double) << " bytes)" << endl;
}
void demonstratePointerSubtraction() {
cout << "\n--- Pointer Subtraction ---\n" << endl;
int arr[] = {10, 20, 30, 40, 50};
int* start = arr;
int* end = arr + 4; // Points to last element
cout << "start points to arr[0]: " << *start << endl;
cout << "end points to arr[4]: " << *end << endl;
ptrdiff_t diff = end - start;
cout << "\nend - start = " << diff << " elements" << endl;
// Pointer comparison
cout << "\nPointer comparison:" << endl;
cout << " start < end: " << boolalpha << (start < end) << endl;
cout << " start == end: " << (start == end) << endl;
}
// ============================================================
// SECTION 3: POINTERS AND ARRAYS
// ============================================================
void demonstrateArrayPointerRelationship() {
cout << "\n--- Array-Pointer Relationship ---\n" << endl;
int arr[] = {10, 20, 30, 40, 50};
int* ptr = arr; // Array decays to pointer
cout << "Array: {10, 20, 30, 40, 50}" << endl;
cout << "\narr = " << arr << " (array decays to address)" << endl;
cout << "&arr[0] = " << &arr[0] << " (same address)" << endl;
cout << "ptr = " << ptr << " (same address)" << endl;
cout << "\nEquivalent access methods:" << endl;
for (int i = 0; i < 5; i++) {
cout << " arr[" << i << "] = " << arr[i];
cout << ", *(arr + " << i << ") = " << *(arr + i);
cout << ", ptr[" << i << "] = " << ptr[i];
cout << ", *(ptr + " << i << ") = " << *(ptr + i) << endl;
}
}
void demonstrateArrayVsPointerDifference() {
cout << "\n--- Array vs Pointer Difference ---\n" << endl;
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr;
cout << "sizeof(arr) = " << sizeof(arr) << " bytes (whole array)" << endl;
cout << "sizeof(ptr) = " << sizeof(ptr) << " bytes (just pointer)" << endl;
cout << "\nNumber of elements using sizeof:" << endl;
cout << " sizeof(arr) / sizeof(arr[0]) = " << sizeof(arr) / sizeof(arr[0]) << endl;
// Can modify pointer, not array name
cout << "\nPointer can be modified:" << endl;
cout << " Original ptr points to: " << *ptr << endl;
ptr++;
cout << " After ptr++, points to: " << *ptr << endl;
// arr++; // This would cause a compile error!
cout << " arr++ would cause compile error (array name is not modifiable)" << endl;
}
// Function that takes array (actually takes pointer)
void printArray(int* arr, int size) {
cout << "Array elements: ";
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void demonstrateArrayParameter() {
cout << "\n--- Arrays as Function Parameters ---\n" << endl;
int numbers[] = {5, 10, 15, 20, 25};
int size = sizeof(numbers) / sizeof(numbers[0]);
cout << "Calling printArray with int array:" << endl;
printArray(numbers, size);
// Can also pass pointer directly
int* ptr = numbers;
cout << "\nCalling printArray with int pointer:" << endl;
printArray(ptr, size);
}
// ============================================================
// SECTION 4: POINTERS TO POINTERS
// ============================================================
void demonstratePointerToPointer() {
cout << "\n--- Pointer to Pointer ---\n" << endl;
int x = 42;
int* ptr = &x; // Pointer to int
int** pptr = &ptr; // Pointer to pointer to int
int*** ppptr = &pptr; // Pointer to pointer to pointer to int
cout << "int x = 42" << endl;
cout << "int* ptr = &x" << endl;
cout << "int** pptr = &ptr" << endl;
cout << "int*** ppptr = &pptr" << endl;
cout << "\nAccessing value through different levels:" << endl;
cout << " x = " << x << endl;
cout << " *ptr = " << *ptr << endl;
cout << " **pptr = " << **pptr << endl;
cout << " ***ppptr = " << ***ppptr << endl;
cout << "\nAddresses at each level:" << endl;
cout << " &x = " << &x << endl;
cout << " ptr = " << ptr << " (holds &x)" << endl;
cout << " &ptr = " << &ptr << endl;
cout << " pptr = " << pptr << " (holds &ptr)" << endl;
cout << " &pptr = " << &pptr << endl;
cout << " ppptr = " << ppptr << " (holds &pptr)" << endl;
}
// Function that modifies a pointer
void allocateInt(int** pptr, int value) {
*pptr = new int(value);
}
void demonstrateModifyingPointerViaPointer() {
cout << "\n--- Modifying Pointer via Pointer-to-Pointer ---\n" << endl;
int* ptr = nullptr;
cout << "Before allocateInt: ptr = " << ptr << endl;
allocateInt(&ptr, 42);
cout << "After allocateInt: ptr = " << ptr << ", *ptr = " << *ptr << endl;
delete ptr;
ptr = nullptr;
cout << "After cleanup: ptr = " << ptr << endl;
}
// ============================================================
// SECTION 5: CONST WITH POINTERS
// ============================================================
void demonstrateConstPointers() {
cout << "\n--- const with Pointers ---\n" << endl;
int x = 10;
int y = 20;
// 1. Pointer to non-const
cout << "1. int* ptr (non-const pointer to non-const int)" << endl;
int* ptr1 = &x;
*ptr1 = 15; // OK: can modify data
ptr1 = &y; // OK: can change pointer
cout << " Can modify data and change pointer" << endl;
// 2. Pointer to const
cout << "\n2. const int* ptr (pointer to const int)" << endl;
const int* ptr2 = &x;
// *ptr2 = 15; // ERROR: can't modify data
ptr2 = &y; // OK: can change pointer
cout << " Cannot modify data, can change pointer" << endl;
cout << " *ptr2 = " << *ptr2 << endl;
// 3. Const pointer
cout << "\n3. int* const ptr (const pointer to int)" << endl;
int* const ptr3 = &x;
*ptr3 = 25; // OK: can modify data
// ptr3 = &y; // ERROR: can't change pointer
cout << " Can modify data, cannot change pointer" << endl;
cout << " *ptr3 = " << *ptr3 << endl;
// 4. Const pointer to const
cout << "\n4. const int* const ptr (const pointer to const int)" << endl;
const int* const ptr4 = &x;
// *ptr4 = 35; // ERROR: can't modify data
// ptr4 = &y; // ERROR: can't change pointer
cout << " Cannot modify data, cannot change pointer" << endl;
cout << " *ptr4 = " << *ptr4 << endl;
}
void demonstrateConstUseCases() {
cout << "\n--- Practical const Pointer Uses ---\n" << endl;
// Pointer to const is useful for read-only access
string message = "Hello, World!";
const char* strPtr = message.c_str();
cout << "Read-only string access:" << endl;
cout << " Message: " << strPtr << endl;
// strPtr[0] = 'h'; // ERROR: can't modify through const char*
// Array of const pointers to const strings
const char* const days[] = {
"Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"
};
cout << "\nDays of the week:" << endl;
for (int i = 0; i < 7; i++) {
cout << " " << days[i] << endl;
}
}
// ============================================================
// SECTION 6: VOID POINTERS
// ============================================================
void demonstrateVoidPointer() {
cout << "\n--- void Pointers (Generic Pointers) ---\n" << endl;
int intVal = 42;
double doubleVal = 3.14;
char charVal = 'X';
void* vptr;
// Can point to any type
vptr = &intVal;
cout << "void* pointing to int: " << *static_cast<int*>(vptr) << endl;
vptr = &doubleVal;
cout << "void* pointing to double: " << *static_cast<double*>(vptr) << endl;
vptr = &charVal;
cout << "void* pointing to char: " << *static_cast<char*>(vptr) << endl;
cout << "\nNote: Must cast void* before dereferencing!" << endl;
}
// ============================================================
// SECTION 7: POINTER BEST PRACTICES
// ============================================================
void demonstrateBestPractices() {
cout << "\n--- Pointer Best Practices ---\n" << endl;
// 1. Always initialize pointers
cout << "1. Always initialize pointers:" << endl;
int* ptr1 = nullptr; // Good
cout << " int* ptr = nullptr; ✓" << endl;
// 2. Check before dereferencing
cout << "\n2. Check for null before dereferencing:" << endl;
if (ptr1 != nullptr) {
cout << " Safe to use" << endl;
} else {
cout << " Pointer is null - don't dereference! ✓" << endl;
}
// 3. Set to nullptr after delete
cout << "\n3. Set to nullptr after delete:" << endl;
int* ptr2 = new int(42);
delete ptr2;
ptr2 = nullptr; // Good practice
cout << " delete ptr; ptr = nullptr; ✓" << endl;
// 4. Use references when possible
cout << "\n4. Prefer references for non-null, non-reassignable cases:" << endl;
int value = 100;
int& ref = value; // Can't be null, can't be reassigned
cout << " int& ref = value; ✓ (safer than pointer)" << endl;
}
// ============================================================
// MAIN FUNCTION
// ============================================================
int main() {
cout << "╔════════════════════════════════════════════════════════════════════╗" << endl;
cout << "║ C++ POINTERS - EXAMPLES ║" << endl;
cout << "║ Memory Addresses and Indirection ║" << endl;
cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 1: Pointer Basics ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateBasicPointers();
demonstratePointerTypes();
demonstrateNullptr();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 2: Pointer Arithmetic ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstratePointerArithmetic();
demonstratePointerSizeArithmetic();
demonstratePointerSubtraction();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 3: Pointers and Arrays ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateArrayPointerRelationship();
demonstrateArrayVsPointerDifference();
demonstrateArrayParameter();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 4: Pointers to Pointers ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstratePointerToPointer();
demonstrateModifyingPointerViaPointer();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 5: const with Pointers ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateConstPointers();
demonstrateConstUseCases();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 6: void Pointers ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateVoidPointer();
cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ SECTION 7: Best Practices ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateBestPractices();
cout << "\n╔════════════════════════════════════════════════════════════════════╗" << endl;
cout << "║ Examples Complete! ║" << endl;
cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
return 0;
}