c
examples
examples.cš§c
/**
* String Arrays and Pointers - Examples
*
* This file demonstrates working with arrays of strings in C.
*
* Compile: gcc examples.c -o examples
* Run: ./examples
*/
#define _POSIX_C_SOURCE 200809L // For strdup
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* ============================================================
* EXAMPLE 1: 2D Character Array vs Pointer Array
* ============================================================ */
void example1_array_types(void) {
printf("=== EXAMPLE 1: 2D Array vs Pointer Array ===\n\n");
// Method 1: 2D Character Array (fixed size)
char names_2d[5][20] = {
"Alice",
"Bob",
"Charlie",
"David",
"Eve"
};
// Method 2: Array of Pointers
const char *names_ptr[] = {
"Alice",
"Bob",
"Charlie",
"David",
"Eve"
};
printf("--- 2D Character Array ---\n");
printf("Size: %zu bytes (5 x 20 = 100)\n", sizeof(names_2d));
printf("Each row: %zu bytes\n", sizeof(names_2d[0]));
for (int i = 0; i < 5; i++) {
printf(" names_2d[%d] = \"%s\"\n", i, names_2d[i]);
}
printf("\n--- Array of Pointers ---\n");
printf("Size: %zu bytes (%zu pointers)\n", sizeof(names_ptr),
sizeof(names_ptr) / sizeof(names_ptr[0]));
printf("Each pointer: %zu bytes\n", sizeof(names_ptr[0]));
for (int i = 0; i < 5; i++) {
printf(" names_ptr[%d] = \"%s\"\n", i, names_ptr[i]);
}
// Key difference: 2D array strings are modifiable
printf("\n--- Modifiability ---\n");
strcpy(names_2d[0], "ALICE"); // OK
printf("Modified 2D: names_2d[0] = \"%s\"\n", names_2d[0]);
// names_ptr[0][0] = 'a'; // UNDEFINED BEHAVIOR - string literal!
printf("Pointer array points to read-only string literals\n");
}
/* ============================================================
* EXAMPLE 2: Memory Layout Visualization
* ============================================================ */
void example2_memory_layout(void) {
printf("\n=== EXAMPLE 2: Memory Layout ===\n\n");
char names_2d[3][10] = {"Alice", "Bob", "Charlie"};
char *names_ptr[] = {"Alice", "Bob", "Charlie"};
printf("--- 2D Array Memory (Contiguous) ---\n");
printf("Base address: %p\n\n", (void*)names_2d);
for (int i = 0; i < 3; i++) {
printf("Row %d: %p \"%s\"\n", i, (void*)names_2d[i], names_2d[i]);
printf(" Characters: ");
for (int j = 0; j < 10; j++) {
if (names_2d[i][j] == '\0') {
printf("[\\0]");
} else {
printf("[%c]", names_2d[i][j]);
}
}
printf("\n");
}
printf("\n--- Pointer Array Memory (Scattered) ---\n");
printf("Array base: %p\n\n", (void*)names_ptr);
for (int i = 0; i < 3; i++) {
printf("names_ptr[%d]: %p -> %p \"%s\"\n",
i, (void*)&names_ptr[i], (void*)names_ptr[i], names_ptr[i]);
}
}
/* ============================================================
* EXAMPLE 3: Accessing Elements
* ============================================================ */
void example3_accessing(void) {
printf("\n=== EXAMPLE 3: Accessing String Array Elements ===\n\n");
char *words[] = {"Hello", "World", "C"};
int count = sizeof(words) / sizeof(words[0]);
printf("Array: {\"Hello\", \"World\", \"C\"}\n\n");
printf("--- Accessing Strings ---\n");
printf("words[0] = \"%s\"\n", words[0]);
printf("words[1] = \"%s\"\n", words[1]);
printf("words[2] = \"%s\"\n\n", words[2]);
printf("--- Accessing Characters ---\n");
printf("words[0][0] = '%c'\n", words[0][0]); // 'H'
printf("words[0][1] = '%c'\n", words[0][1]); // 'e'
printf("words[1][0] = '%c'\n\n", words[1][0]); // 'W'
printf("--- Using Pointer Notation ---\n");
printf("*words[0] = '%c' (first char of first string)\n", *words[0]);
printf("*(words[0]+1) = '%c'\n", *(words[0]+1));
printf("**(words+1) = '%c' (first char of second string)\n\n", **(words+1));
printf("--- Iterating Methods ---\n");
// Method 1: Index-based
printf("Index-based: ");
for (int i = 0; i < count; i++) {
printf("%s ", words[i]);
}
printf("\n");
// Method 2: Pointer-based
printf("Pointer-based: ");
char **ptr = words;
for (int i = 0; i < count; i++) {
printf("%s ", *ptr++);
}
printf("\n");
}
/* ============================================================
* EXAMPLE 4: Dynamic String Array Allocation
* ============================================================ */
char **create_string_array(int count, int max_len) {
char **arr = malloc(count * sizeof(char *));
if (arr == NULL) return NULL;
for (int i = 0; i < count; i++) {
arr[i] = malloc(max_len * sizeof(char));
if (arr[i] == NULL) {
// Cleanup on failure
for (int j = 0; j < i; j++) {
free(arr[j]);
}
free(arr);
return NULL;
}
arr[i][0] = '\0'; // Initialize as empty string
}
return arr;
}
void free_string_array(char **arr, int count) {
if (arr == NULL) return;
for (int i = 0; i < count; i++) {
free(arr[i]);
}
free(arr);
}
void example4_dynamic_allocation(void) {
printf("\n=== EXAMPLE 4: Dynamic String Array Allocation ===\n\n");
int count = 5;
int max_len = 50;
printf("Allocating array of %d strings, max length %d\n\n",
count, max_len);
// Allocate
char **names = create_string_array(count, max_len);
if (names == NULL) {
printf("Allocation failed!\n");
return;
}
// Populate
strcpy(names[0], "Alice");
strcpy(names[1], "Bob");
strcpy(names[2], "Charlie");
strcpy(names[3], "David");
strcpy(names[4], "Eve");
printf("Populated strings:\n");
for (int i = 0; i < count; i++) {
printf(" names[%d] = \"%s\"\n", i, names[i]);
}
// Modify
strcpy(names[0], "ALICE (Modified)");
printf("\nAfter modification:\n");
printf(" names[0] = \"%s\"\n", names[0]);
// Free
free_string_array(names, count);
printf("\nMemory freed successfully.\n");
}
/* ============================================================
* EXAMPLE 5: Using strdup() for Dynamic Strings
* ============================================================ */
void example5_strdup(void) {
printf("\n=== EXAMPLE 5: Using strdup() ===\n\n");
int count = 4;
char **words = malloc(count * sizeof(char *));
if (words == NULL) {
printf("Allocation failed!\n");
return;
}
// strdup allocates exact size needed
words[0] = strdup("Short");
words[1] = strdup("Medium length string");
words[2] = strdup("This is a longer string example");
words[3] = strdup("Hi");
printf("Strings created with strdup:\n");
for (int i = 0; i < count; i++) {
printf(" [%d] \"%s\" (len=%zu)\n",
i, words[i], strlen(words[i]));
}
// Memory is allocated individually
printf("\nNote: Each string has its own allocation.\n");
// Cleanup
for (int i = 0; i < count; i++) {
free(words[i]);
}
free(words);
printf("Memory freed.\n");
}
/* ============================================================
* EXAMPLE 6: Sorting String Arrays
* ============================================================ */
void bubble_sort_strings(char **arr, int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (strcmp(arr[j], arr[j + 1]) > 0) {
// Swap pointers (very efficient)
char *temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// Comparison function for qsort
int compare_strings(const void *a, const void *b) {
return strcmp(*(const char **)a, *(const char **)b);
}
// Case-insensitive comparison
int compare_strings_nocase(const void *a, const void *b) {
return strcasecmp(*(const char **)a, *(const char **)b);
}
void example6_sorting(void) {
printf("\n=== EXAMPLE 6: Sorting String Arrays ===\n\n");
char *names1[] = {"Charlie", "Alice", "Eve", "Bob", "David"};
int count = 5;
printf("--- Bubble Sort ---\n");
printf("Before: ");
for (int i = 0; i < count; i++) printf("%s ", names1[i]);
printf("\n");
bubble_sort_strings(names1, count);
printf("After: ");
for (int i = 0; i < count; i++) printf("%s ", names1[i]);
printf("\n\n");
// Using qsort
char *names2[] = {"banana", "Apple", "cherry", "Date"};
count = 4;
printf("--- qsort (case-sensitive) ---\n");
printf("Before: ");
for (int i = 0; i < count; i++) printf("%s ", names2[i]);
printf("\n");
qsort(names2, count, sizeof(char *), compare_strings);
printf("After: ");
for (int i = 0; i < count; i++) printf("%s ", names2[i]);
printf("\n\n");
// Case-insensitive sort
char *names3[] = {"banana", "Apple", "cherry", "Date"};
printf("--- qsort (case-insensitive) ---\n");
printf("Before: ");
for (int i = 0; i < count; i++) printf("%s ", names3[i]);
printf("\n");
qsort(names3, count, sizeof(char *), compare_strings_nocase);
printf("After: ");
for (int i = 0; i < count; i++) printf("%s ", names3[i]);
printf("\n");
}
/* ============================================================
* EXAMPLE 7: Searching String Arrays
* ============================================================ */
int linear_search(char **arr, int n, const char *target) {
for (int i = 0; i < n; i++) {
if (strcmp(arr[i], target) == 0) {
return i;
}
}
return -1;
}
int binary_search_string(char **arr, int n, const char *target) {
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
int cmp = strcmp(arr[mid], target);
if (cmp == 0) {
return mid;
} else if (cmp < 0) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
void example7_searching(void) {
printf("\n=== EXAMPLE 7: Searching String Arrays ===\n\n");
char *names[] = {"Alice", "Bob", "Charlie", "David", "Eve"};
int count = 5;
printf("Array: ");
for (int i = 0; i < count; i++) printf("%s ", names[i]);
printf("\n\n");
printf("--- Linear Search ---\n");
int idx = linear_search(names, count, "Charlie");
printf("Search for \"Charlie\": index %d\n", idx);
idx = linear_search(names, count, "Frank");
printf("Search for \"Frank\": index %d (not found)\n\n", idx);
printf("--- Binary Search (sorted array) ---\n");
// Already sorted alphabetically
idx = binary_search_string(names, count, "David");
printf("Search for \"David\": index %d\n", idx);
idx = binary_search_string(names, count, "Alice");
printf("Search for \"Alice\": index %d\n", idx);
idx = binary_search_string(names, count, "Zack");
printf("Search for \"Zack\": index %d (not found)\n", idx);
}
/* ============================================================
* EXAMPLE 8: Command Line Arguments Simulation
* ============================================================ */
void process_args(int argc, char *argv[]) {
printf("Program: %s\n", argv[0]);
printf("Argument count: %d\n\n", argc);
int verbose = 0;
const char *filename = NULL;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-v") == 0 ||
strcmp(argv[i], "--verbose") == 0) {
verbose = 1;
} else if ((strcmp(argv[i], "-f") == 0 ||
strcmp(argv[i], "--file") == 0) && i + 1 < argc) {
filename = argv[++i];
} else if (argv[i][0] != '-') {
printf("Positional argument: %s\n", argv[i]);
} else {
printf("Unknown option: %s\n", argv[i]);
}
}
printf("\nParsed options:\n");
printf(" Verbose: %s\n", verbose ? "yes" : "no");
printf(" Filename: %s\n", filename ? filename : "(not specified)");
}
void example8_command_line(void) {
printf("\n=== EXAMPLE 8: Command Line Arguments ===\n\n");
// Simulate different command line invocations
printf("--- Simulation 1: Basic usage ---\n");
char *args1[] = {"./myprogram", "input.txt", "-v"};
process_args(3, args1);
printf("\n--- Simulation 2: With file option ---\n");
char *args2[] = {"./myprogram", "-f", "data.txt", "--verbose"};
process_args(4, args2);
}
/* ============================================================
* EXAMPLE 9: NULL-Terminated String Arrays
* ============================================================ */
void print_null_terminated(char **arr) {
int count = 0;
while (*arr != NULL) {
printf("[%d] %s\n", count++, *arr);
arr++;
}
printf("Total: %d strings\n", count);
}
void example9_null_terminated(void) {
printf("\n=== EXAMPLE 9: NULL-Terminated String Arrays ===\n\n");
// NULL-terminated array (no need to pass size)
char *colors[] = {"red", "green", "blue", "yellow", NULL};
printf("Colors array (NULL-terminated):\n");
print_null_terminated(colors);
printf("\n--- Iterating with different methods ---\n");
// Method 1: Check against NULL
printf("Method 1: ");
for (int i = 0; colors[i] != NULL; i++) {
printf("%s ", colors[i]);
}
printf("\n");
// Method 2: Using pointer
printf("Method 2: ");
char **ptr = colors;
while (*ptr) {
printf("%s ", *ptr++);
}
printf("\n");
}
/* ============================================================
* EXAMPLE 10: Tokenizing into String Array
* ============================================================ */
int tokenize(char *str, char *tokens[], int max, const char *delim) {
int count = 0;
char *token = strtok(str, delim);
while (token != NULL && count < max) {
tokens[count++] = token;
token = strtok(NULL, delim);
}
return count;
}
void example10_tokenizing(void) {
printf("\n=== EXAMPLE 10: Tokenizing into String Array ===\n\n");
char text[] = "apple,banana,cherry,date,elderberry";
char *tokens[10];
printf("Original: \"%s\"\n\n", text);
int count = tokenize(text, tokens, 10, ",");
printf("Tokenized by ',': %d tokens\n", count);
for (int i = 0; i < count; i++) {
printf(" tokens[%d] = \"%s\"\n", i, tokens[i]);
}
// Tokenize sentence
printf("\n--- Tokenizing a sentence ---\n");
char sentence[] = "The quick brown fox jumps over";
char *words[20];
count = tokenize(sentence, words, 20, " ");
printf("Words: ");
for (int i = 0; i < count; i++) {
printf("\"%s\" ", words[i]);
}
printf("\n");
}
/* ============================================================
* EXAMPLE 11: Filtering String Arrays
* ============================================================ */
int filter_by_length(char **arr, int n, char **result, int min_len) {
int count = 0;
for (int i = 0; i < n; i++) {
if (strlen(arr[i]) >= (size_t)min_len) {
result[count++] = arr[i];
}
}
return count;
}
int filter_by_prefix(char **arr, int n, char **result, const char *prefix) {
int count = 0;
size_t prefix_len = strlen(prefix);
for (int i = 0; i < n; i++) {
if (strncmp(arr[i], prefix, prefix_len) == 0) {
result[count++] = arr[i];
}
}
return count;
}
void example11_filtering(void) {
printf("\n=== EXAMPLE 11: Filtering String Arrays ===\n\n");
char *words[] = {"apple", "apricot", "banana", "blueberry",
"cherry", "avocado", "kiwi"};
int count = 7;
char *filtered[10];
printf("Original: ");
for (int i = 0; i < count; i++) printf("%s ", words[i]);
printf("\n\n");
// Filter by minimum length
printf("--- Filter: length >= 6 ---\n");
int filtered_count = filter_by_length(words, count, filtered, 6);
printf("Result: ");
for (int i = 0; i < filtered_count; i++) printf("%s ", filtered[i]);
printf("(%d matches)\n\n", filtered_count);
// Filter by prefix
printf("--- Filter: prefix \"a\" ---\n");
filtered_count = filter_by_prefix(words, count, filtered, "a");
printf("Result: ");
for (int i = 0; i < filtered_count; i++) printf("%s ", filtered[i]);
printf("(%d matches)\n", filtered_count);
}
/* ============================================================
* EXAMPLE 12: Copying and Comparing String Arrays
* ============================================================ */
char **copy_string_array(char **src, int count) {
char **dest = malloc(count * sizeof(char *));
if (dest == NULL) return NULL;
for (int i = 0; i < count; i++) {
dest[i] = strdup(src[i]);
if (dest[i] == NULL) {
// Cleanup on failure
for (int j = 0; j < i; j++) {
free(dest[j]);
}
free(dest);
return NULL;
}
}
return dest;
}
int arrays_equal(char **arr1, char **arr2, int count) {
for (int i = 0; i < count; i++) {
if (strcmp(arr1[i], arr2[i]) != 0) {
return 0;
}
}
return 1;
}
void example12_copy_compare(void) {
printf("\n=== EXAMPLE 12: Copying and Comparing ===\n\n");
char *original[] = {"one", "two", "three"};
int count = 3;
printf("Original array: ");
for (int i = 0; i < count; i++) printf("%s ", original[i]);
printf("\n");
// Deep copy
char **copy = copy_string_array(original, count);
printf("Copied array: ");
for (int i = 0; i < count; i++) printf("%s ", copy[i]);
printf("\n\n");
// Compare
printf("Arrays equal? %s\n",
arrays_equal(original, copy, count) ? "Yes" : "No");
// Modify copy
strcpy(copy[0], "ONE");
printf("\nAfter modifying copy[0] to \"ONE\":\n");
printf("Original: ");
for (int i = 0; i < count; i++) printf("%s ", original[i]);
printf("\n");
printf("Copy: ");
for (int i = 0; i < count; i++) printf("%s ", copy[i]);
printf("\n");
printf("Arrays equal? %s\n",
arrays_equal(original, copy, count) ? "Yes" : "No");
// Cleanup
for (int i = 0; i < count; i++) {
free(copy[i]);
}
free(copy);
}
/* ============================================================
* MAIN FUNCTION
* ============================================================ */
int main(void) {
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf("ā STRING ARRAYS AND POINTERS - EXAMPLES ā\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n\n");
example1_array_types();
example2_memory_layout();
example3_accessing();
example4_dynamic_allocation();
example5_strdup();
example6_sorting();
example7_searching();
example8_command_line();
example9_null_terminated();
example10_tokenizing();
example11_filtering();
example12_copy_compare();
printf("\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf("ā ALL EXAMPLES COMPLETED! ā\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
return 0;
}