c

examples

examples.cšŸ”§
/**
 * =============================================================================
 * POINTER TO POINTER (DOUBLE POINTERS) - EXAMPLES
 * =============================================================================
 * 
 * This file demonstrates double pointers (pointer to pointer) in C with
 * comprehensive examples covering:
 *   - Basic declaration and initialization
 *   - Memory layout and visualization
 *   - Dereferencing at multiple levels
 *   - Modifying pointers through functions
 *   - Dynamic 2D arrays
 *   - Array of strings
 *   - Command line argument handling
 * 
 * Compile: gcc -o examples examples.c -Wall
 * Run: ./examples
 * =============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/* ============================================================
 * EXAMPLE 1: Basic Double Pointer Concept
 * ============================================================ */

void example1_basic_concept(void) {
    printf("\n=== EXAMPLE 1: Basic Double Pointer Concept ===\n\n");
    
    // Level 0: Regular variable
    int value = 42;
    
    // Level 1: Pointer to integer
    int *ptr = &value;
    
    // Level 2: Pointer to pointer (double pointer)
    int **pp = &ptr;
    
    printf("The chain of references:\n");
    printf("─────────────────────────────────────────\n");
    printf("value  = %d           (the integer value)\n", value);
    printf("&value = %p     (address of value)\n", (void*)&value);
    printf("\n");
    printf("ptr    = %p     (stores &value)\n", (void*)ptr);
    printf("*ptr   = %d           (dereferenced to value)\n", *ptr);
    printf("&ptr   = %p     (address of ptr)\n", (void*)&ptr);
    printf("\n");
    printf("pp     = %p     (stores &ptr)\n", (void*)pp);
    printf("*pp    = %p     (dereferenced to ptr)\n", (void*)*pp);
    printf("**pp   = %d           (double dereferenced to value)\n", **pp);
    
    printf("\n");
    printf("Visual representation:\n");
    printf("  pp ──────► ptr ──────► value\n");
    printf("  (%p) → (%p) → (%d)\n", 
           (void*)pp, (void*)ptr, value);
}


/* ============================================================
 * EXAMPLE 2: Memory Layout Visualization
 * ============================================================ */

void example2_memory_layout(void) {
    printf("\n=== EXAMPLE 2: Memory Layout Visualization ===\n\n");
    
    int number = 100;
    int *p = &number;
    int **pp = &p;
    
    printf("Memory Layout:\n");
    printf("═══════════════════════════════════════════════════════════\n");
    printf("Variable    Address           Value           Meaning\n");
    printf("───────────────────────────────────────────────────────────\n");
    printf("pp          %p    %p    Address of p\n", 
           (void*)&pp, (void*)pp);
    printf("p           %p    %p    Address of number\n", 
           (void*)&p, (void*)p);
    printf("number      %p    %-16d    The actual data\n", 
           (void*)&number, number);
    printf("═══════════════════════════════════════════════════════════\n");
    
    printf("\nPointer Sizes:\n");
    printf("  sizeof(int)    = %zu bytes\n", sizeof(int));
    printf("  sizeof(int*)   = %zu bytes\n", sizeof(int*));
    printf("  sizeof(int**)  = %zu bytes\n", sizeof(int**));
    printf("\nNote: All pointer types have the same size on this system.\n");
}


/* ============================================================
 * EXAMPLE 3: Dereferencing Levels
 * ============================================================ */

void example3_dereferencing(void) {
    printf("\n=== EXAMPLE 3: Dereferencing Levels ===\n\n");
    
    int x = 999;
    int *ptr = &x;
    int **pp = &ptr;
    
    printf("Given: int x = 999; int *ptr = &x; int **pp = &ptr;\n\n");
    
    printf("Dereferencing Table:\n");
    printf("ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”\n");
    printf("│ Expression │ Result                │ Description        │\n");
    printf("ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤\n");
    printf("│ pp         │ %-21p │ Address of ptr     │\n", (void*)pp);
    printf("│ *pp        │ %-21p │ Value of ptr       │\n", (void*)*pp);
    printf("│ **pp       │ %-21d │ Value of x         │\n", **pp);
    printf("ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n");
    
    // Modify through double pointer
    printf("\nModifying through double pointer:\n");
    printf("Before: x = %d\n", x);
    **pp = 1000;
    printf("After **pp = 1000: x = %d\n", x);
}


/* ============================================================
 * EXAMPLE 4: Modifying Pointers in Functions
 * ============================================================ */

// Without double pointer - doesn't work
void wrongModify(int *p) {
    static int local = 500;
    p = &local;  // Only modifies local copy of p
}

// With double pointer - works correctly
void correctModify(int **pp) {
    static int local = 500;
    *pp = &local;  // Modifies the original pointer
}

void example4_modify_pointer(void) {
    printf("\n=== EXAMPLE 4: Modifying Pointers in Functions ===\n\n");
    
    int original = 10;
    int *ptr = &original;
    
    printf("Initial state: *ptr = %d (pointing to original)\n\n", *ptr);
    
    // Wrong way
    printf("Calling wrongModify(ptr)...\n");
    wrongModify(ptr);
    printf("After wrongModify: *ptr = %d (unchanged!)\n\n", *ptr);
    
    // Correct way
    printf("Calling correctModify(&ptr)...\n");
    correctModify(&ptr);
    printf("After correctModify: *ptr = %d (changed!)\n\n", *ptr);
    
    printf("Explanation:\n");
    printf("- wrongModify receives a COPY of the pointer\n");
    printf("- correctModify receives the ADDRESS of the pointer\n");
    printf("- With &ptr, we can modify what ptr points to\n");
}


/* ============================================================
 * EXAMPLE 5: Dynamic Memory Allocation via Double Pointer
 * ============================================================ */

void allocateMemory(int **arr, int size) {
    *arr = (int*)malloc(size * sizeof(int));
    if (*arr == NULL) {
        fprintf(stderr, "Memory allocation failed!\n");
        return;
    }
    
    // Initialize array
    for (int i = 0; i < size; i++) {
        (*arr)[i] = (i + 1) * 100;
    }
}

void freeMemory(int **arr) {
    free(*arr);
    *arr = NULL;  // Set to NULL to prevent dangling pointer
}

void example5_dynamic_allocation(void) {
    printf("\n=== EXAMPLE 5: Dynamic Allocation via Double Pointer ===\n\n");
    
    int *myArray = NULL;
    int size = 5;
    
    printf("Before allocation: myArray = %p\n", (void*)myArray);
    
    // Allocate through double pointer
    allocateMemory(&myArray, size);
    
    printf("After allocation:  myArray = %p\n\n", (void*)myArray);
    
    printf("Array contents:\n");
    for (int i = 0; i < size; i++) {
        printf("  myArray[%d] = %d\n", i, myArray[i]);
    }
    
    // Free through double pointer
    freeMemory(&myArray);
    printf("\nAfter freeing: myArray = %p (safely set to NULL)\n", (void*)myArray);
}


/* ============================================================
 * EXAMPLE 6: Swapping Pointers
 * ============================================================ */

void swapPointers(int **p1, int **p2) {
    int *temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}

void example6_swap_pointers(void) {
    printf("\n=== EXAMPLE 6: Swapping Pointers ===\n\n");
    
    int a = 10, b = 20;
    int *pa = &a;
    int *pb = &b;
    
    printf("Before swap:\n");
    printf("  pa points to a: *pa = %d\n", *pa);
    printf("  pb points to b: *pb = %d\n", *pb);
    
    swapPointers(&pa, &pb);
    
    printf("\nAfter swap:\n");
    printf("  pa points to b: *pa = %d\n", *pa);
    printf("  pb points to a: *pb = %d\n", *pb);
    
    printf("\nNote: a and b values are unchanged (%d, %d)\n", a, b);
    printf("Only the pointers were swapped!\n");
}


/* ============================================================
 * EXAMPLE 7: Array of Pointers
 * ============================================================ */

void example7_array_of_pointers(void) {
    printf("\n=== EXAMPLE 7: Array of Pointers ===\n\n");
    
    int a = 10, b = 20, c = 30, d = 40;
    
    // Array of pointers
    int *arr[4] = {&a, &b, &c, &d};
    
    // Double pointer pointing to the array
    int **pp = arr;
    
    printf("Array of 4 integer pointers:\n");
    printf("arr[i]     *arr[i]    Using **pp\n");
    printf("────────────────────────────────\n");
    
    for (int i = 0; i < 4; i++) {
        printf("%p    %-10d %-10d\n", 
               (void*)arr[i], *arr[i], **(pp + i));
    }
    
    printf("\nAccessing via double pointer:\n");
    printf("  **pp     = %d (first element)\n", **pp);
    printf("  **(pp+1) = %d (second element)\n", **(pp+1));
    printf("  **(pp+2) = %d (third element)\n", **(pp+2));
    printf("  **(pp+3) = %d (fourth element)\n", **(pp+3));
}


/* ============================================================
 * EXAMPLE 8: Array of Strings
 * ============================================================ */

void example8_string_array(void) {
    printf("\n=== EXAMPLE 8: Array of Strings ===\n\n");
    
    // Static array of strings
    char *fruits[] = {"Apple", "Banana", "Cherry", "Date", "Elderberry"};
    int count = 5;
    
    // Double pointer to string array
    char **pp = fruits;
    
    printf("Array of strings (char **):\n");
    printf("────────────────────────────\n");
    
    // Method 1: Using array indexing
    printf("Using array indexing:\n");
    for (int i = 0; i < count; i++) {
        printf("  fruits[%d] = \"%s\"\n", i, fruits[i]);
    }
    
    // Method 2: Using double pointer
    printf("\nUsing double pointer:\n");
    for (int i = 0; i < count; i++) {
        printf("  *(pp+%d) = \"%s\"\n", i, *(pp + i));
    }
    
    // Method 3: Pointer increment
    printf("\nUsing pointer increment:\n");
    char **current = pp;
    int idx = 0;
    while (idx < count) {
        printf("  *current = \"%s\"\n", *current);
        current++;
        idx++;
    }
}


/* ============================================================
 * EXAMPLE 9: Dynamic 2D Array
 * ============================================================ */

int** create2DArray(int rows, int cols) {
    // Allocate row pointers
    int **matrix = (int**)malloc(rows * sizeof(int*));
    if (matrix == NULL) return NULL;
    
    // Allocate each row
    for (int i = 0; i < rows; i++) {
        matrix[i] = (int*)malloc(cols * sizeof(int));
        if (matrix[i] == NULL) {
            // Cleanup on failure
            for (int j = 0; j < i; j++) {
                free(matrix[j]);
            }
            free(matrix);
            return NULL;
        }
    }
    
    return matrix;
}

void free2DArray(int **matrix, int rows) {
    if (matrix == NULL) return;
    
    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);
}

void example9_dynamic_2d_array(void) {
    printf("\n=== EXAMPLE 9: Dynamic 2D Array ===\n\n");
    
    int rows = 3, cols = 4;
    
    // Create dynamic 2D array
    int **matrix = create2DArray(rows, cols);
    if (matrix == NULL) {
        printf("Failed to create matrix!\n");
        return;
    }
    
    // Initialize with values
    int value = 1;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = value++;
        }
    }
    
    // Print matrix
    printf("Dynamic %dx%d matrix:\n", rows, cols);
    printf("ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”\n");
    for (int i = 0; i < rows; i++) {
        printf("│");
        for (int j = 0; j < cols; j++) {
            printf(" %3d", matrix[i][j]);
        }
        printf(" │\n");
    }
    printf("ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n");
    
    // Show memory layout
    printf("\nMemory layout:\n");
    printf("matrix (%p) points to:\n", (void*)matrix);
    for (int i = 0; i < rows; i++) {
        printf("  matrix[%d] = %p → ", i, (void*)matrix[i]);
        printf("{%d, %d, %d, %d}\n", 
               matrix[i][0], matrix[i][1], matrix[i][2], matrix[i][3]);
    }
    
    // Free memory
    free2DArray(matrix, rows);
    printf("\nMatrix freed successfully!\n");
}


/* ============================================================
 * EXAMPLE 10: Contiguous 2D Array
 * ============================================================ */

void example10_contiguous_2d_array(void) {
    printf("\n=== EXAMPLE 10: Contiguous 2D Array ===\n\n");
    
    int rows = 3, cols = 4;
    
    // Allocate pointers and data contiguously
    int **matrix = (int**)malloc(rows * sizeof(int*));
    int *data = (int*)malloc(rows * cols * sizeof(int));
    
    if (matrix == NULL || data == NULL) {
        free(matrix);
        free(data);
        printf("Allocation failed!\n");
        return;
    }
    
    // Set up row pointers into the contiguous data
    for (int i = 0; i < rows; i++) {
        matrix[i] = data + (i * cols);
    }
    
    // Initialize
    int val = 10;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = val;
            val += 10;
        }
    }
    
    // Print
    printf("Contiguous 2D array:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%4d", matrix[i][j]);
        }
        printf("\n");
    }
    
    // Show contiguity
    printf("\nMemory addresses (showing contiguous storage):\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%p ", (void*)&matrix[i][j]);
        }
        printf("\n");
    }
    
    // Free (simpler with contiguous allocation)
    free(data);     // Free data block
    free(matrix);   // Free pointer array
    
    printf("\nAdvantage: Only 2 free() calls needed!\n");
}


/* ============================================================
 * EXAMPLE 11: Triple Pointer
 * ============================================================ */

void example11_triple_pointer(void) {
    printf("\n=== EXAMPLE 11: Triple Pointer ===\n\n");
    
    int value = 777;
    int *p1 = &value;       // Single pointer
    int **p2 = &p1;         // Double pointer
    int ***p3 = &p2;        // Triple pointer
    
    printf("Chain: p3 → p2 → p1 → value\n\n");
    
    printf("Level   Variable   Address            Contains\n");
    printf("─────────────────────────────────────────────────────────\n");
    printf("0       value      %p     %d\n", 
           (void*)&value, value);
    printf("1       p1         %p     %p\n", 
           (void*)&p1, (void*)p1);
    printf("2       p2         %p     %p\n", 
           (void*)&p2, (void*)p2);
    printf("3       p3         %p     %p\n", 
           (void*)&p3, (void*)p3);
    
    printf("\nDereferencing:\n");
    printf("  *p1   = %d\n", *p1);
    printf("  **p2  = %d\n", **p2);
    printf("  ***p3 = %d\n", ***p3);
    
    // Modify through triple pointer
    ***p3 = 888;
    printf("\nAfter ***p3 = 888:\n");
    printf("  value = %d\n", value);
    
    printf("\nNote: Triple pointers are rarely needed in practice.\n");
}


/* ============================================================
 * EXAMPLE 12: Command Line Arguments Simulation
 * ============================================================ */

void example12_argv_simulation(void) {
    printf("\n=== EXAMPLE 12: Command Line Arguments Simulation ===\n\n");
    
    // Simulating what main(int argc, char **argv) receives
    char *argv_sim[] = {
        "./program",
        "-v",
        "--input",
        "data.txt",
        "--output",
        "result.csv",
        NULL  // argv is NULL-terminated
    };
    int argc_sim = 6;
    
    // Using char** like in main()
    char **argv = argv_sim;
    
    printf("Simulated command: ./program -v --input data.txt --output result.csv\n\n");
    
    printf("argc = %d\n\n", argc_sim);
    
    printf("argv layout:\n");
    printf("ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”\n");
    for (int i = 0; i <= argc_sim; i++) {
        if (argv[i] != NULL) {
            printf("│ argv[%d] → \"%s\"\n", i, argv[i]);
        } else {
            printf("│ argv[%d] → NULL (terminator)\n", i);
        }
    }
    printf("ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n");
    
    // Processing with pointer arithmetic
    printf("\nProcessing with pointer arithmetic:\n");
    char **current = argv;
    int idx = 0;
    while (*current != NULL) {
        printf("  Argument %d: %s\n", idx++, *current);
        current++;
    }
}


/* ============================================================
 * EXAMPLE 13: Dynamic Array of Strings
 * ============================================================ */

char** createStringArray(int count) {
    char **arr = (char**)malloc(count * sizeof(char*));
    return arr;
}

void freeStringArray(char **arr, int count) {
    for (int i = 0; i < count; i++) {
        free(arr[i]);
    }
    free(arr);
}

void example13_dynamic_string_array(void) {
    printf("\n=== EXAMPLE 13: Dynamic Array of Strings ===\n\n");
    
    int count = 4;
    char **names = createStringArray(count);
    
    if (names == NULL) {
        printf("Allocation failed!\n");
        return;
    }
    
    // Allocate and copy strings
    const char *source[] = {"Alice", "Bob", "Charlie", "Diana"};
    
    for (int i = 0; i < count; i++) {
        names[i] = (char*)malloc(strlen(source[i]) + 1);
        if (names[i] != NULL) {
            strcpy(names[i], source[i]);
        }
    }
    
    printf("Dynamic string array:\n");
    for (int i = 0; i < count; i++) {
        printf("  names[%d] = \"%s\" (at %p)\n", 
               i, names[i], (void*)names[i]);
    }
    
    // Modify a string
    printf("\nModifying names[1] from \"Bob\" to \"Bobby\":\n");
    free(names[1]);
    names[1] = (char*)malloc(6);  // "Bobby" + null
    strcpy(names[1], "Bobby");
    
    printf("After modification:\n");
    for (int i = 0; i < count; i++) {
        printf("  names[%d] = \"%s\"\n", i, names[i]);
    }
    
    freeStringArray(names, count);
    printf("\nString array freed successfully!\n");
}


/* ============================================================
 * EXAMPLE 14: Linked List Node with Double Pointer
 * ============================================================ */

typedef struct Node {
    int data;
    struct Node *next;
} Node;

// Insert at head using double pointer
void insertAtHead(Node **head, int data) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL) return;
    
    newNode->data = data;
    newNode->next = *head;
    *head = newNode;  // Update head through double pointer
}

void printList(Node *head) {
    Node *current = head;
    while (current != NULL) {
        printf("%d → ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}

void freeList(Node **head) {
    Node *current = *head;
    while (current != NULL) {
        Node *next = current->next;
        free(current);
        current = next;
    }
    *head = NULL;
}

void example14_linked_list(void) {
    printf("\n=== EXAMPLE 14: Linked List with Double Pointer ===\n\n");
    
    Node *head = NULL;
    
    printf("Inserting: 10, 20, 30 at head\n");
    insertAtHead(&head, 10);
    insertAtHead(&head, 20);
    insertAtHead(&head, 30);
    
    printf("List: ");
    printList(head);
    
    printf("\nWhy double pointer?\n");
    printf("- We pass &head to modify the head pointer itself\n");
    printf("- Without **, we couldn't update head from NULL\n");
    
    freeList(&head);
    printf("\nList freed. head = %p\n", (void*)head);
}


/* ============================================================
 * EXAMPLE 15: Comprehensive Dereferencing Demo
 * ============================================================ */

void example15_comprehensive_demo(void) {
    printf("\n=== EXAMPLE 15: Comprehensive Dereferencing Demo ===\n\n");
    
    int x = 42;
    int *p = &x;
    int **pp = &p;
    int ***ppp = &pp;
    
    printf("Variable setup:\n");
    printf("  int x = 42;\n");
    printf("  int *p = &x;\n");
    printf("  int **pp = &p;\n");
    printf("  int ***ppp = &pp;\n\n");
    
    printf("Dereferencing table:\n");
    printf("ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”\n");
    printf("│ Expression  │ Value            │ Interpretation              │\n");
    printf("ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤\n");
    printf("│ x           │ %-16d │ The integer value           │\n", x);
    printf("│ &x          │ %-16p │ Address of x                │\n", (void*)&x);
    printf("│ p           │ %-16p │ Same as &x                  │\n", (void*)p);
    printf("│ *p          │ %-16d │ Value at p (x)              │\n", *p);
    printf("│ &p          │ %-16p │ Address of p                │\n", (void*)&p);
    printf("│ pp          │ %-16p │ Same as &p                  │\n", (void*)pp);
    printf("│ *pp         │ %-16p │ Value at pp (p)             │\n", (void*)*pp);
    printf("│ **pp        │ %-16d │ Value at *pp (x)            │\n", **pp);
    printf("│ &pp         │ %-16p │ Address of pp               │\n", (void*)&pp);
    printf("│ ppp         │ %-16p │ Same as &pp                 │\n", (void*)ppp);
    printf("│ *ppp        │ %-16p │ Value at ppp (pp)           │\n", (void*)*ppp);
    printf("│ **ppp       │ %-16p │ Value at *ppp (p)           │\n", (void*)**ppp);
    printf("│ ***ppp      │ %-16d │ Value at **ppp (x)          │\n", ***ppp);
    printf("ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n");
}


/* ============================================================
 * MAIN FUNCTION
 * ============================================================ */

int main(int argc, char **argv) {
    printf("╔══════════════════════════════════════════════════════════════╗\n");
    printf("ā•‘   POINTER TO POINTER (DOUBLE POINTERS) - EXAMPLES            ā•‘\n");
    printf("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n");
    
    example1_basic_concept();
    example2_memory_layout();
    example3_dereferencing();
    example4_modify_pointer();
    example5_dynamic_allocation();
    example6_swap_pointers();
    example7_array_of_pointers();
    example8_string_array();
    example9_dynamic_2d_array();
    example10_contiguous_2d_array();
    example11_triple_pointer();
    example12_argv_simulation();
    example13_dynamic_string_array();
    example14_linked_list();
    example15_comprehensive_demo();
    
    printf("\n═══════════════════════════════════════════════════════════════\n");
    printf("                    All examples completed!                     \n");
    printf("═══════════════════════════════════════════════════════════════\n");
    
    // Demonstrate actual command line args if any
    if (argc > 1) {
        printf("\nActual command line arguments received:\n");
        for (int i = 0; i < argc; i++) {
            printf("  argv[%d] = \"%s\"\n", i, argv[i]);
        }
    }
    
    return 0;
}
Examples - C Programming Tutorial | DeepML