c
examples
examples.cš§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;
}