Lesson 04-C Language Arrays and Strings

Array Definition and Usage

Array Definition

An array is defined by specifying its data type and size. The size must be a non-negative integer constant expression.

// Define an integer array with 5 elements
int arr[5];

// Define a character array to store a string
char str[10];

Array Initialization

Arrays can be initialized at definition or later using assignment statements.

// Initialize at definition
int numbers[] = {1, 2, 3, 4, 5};

// Initialize a character array
char greeting[] = "Hello";

// Partial initialization
int scores[10] = {100, 95, 90};

If the size is omitted during initialization, the compiler infers it from the number of elements in the initialization list.

Accessing Array Elements

Array elements are accessed using zero-based indices.

int arr[5] = {10, 20, 30, 40, 50};
printf("Element at index 2: %d\n", arr[2]); // Outputs 30

Traversing Arrays

Loops are used to iterate over all elements of an array.

int arr[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
    printf("Element %d: %d\n", i, arr[i]);
}

Array Size

The sizeof operator retrieves the total size of an array in bytes. Dividing by the size of a single element gives the number of elements.

int arr[5];
printf("Size of array: %lu elements\n", sizeof(arr) / sizeof(arr[0]));

Passing Arrays to Functions

When an array is passed to a function, it decays into a pointer to its first element.

void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    printArray(arr, 5);
    return 0;
}

Multidimensional Arrays

Multidimensional arrays are arrays of arrays. For example, a two-dimensional array can represent a matrix.

// Define a 3x3 two-dimensional array
int matrix[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// Access an element
printf("Element at [1][2]: %d\n", matrix[1][2]); // Outputs 6

Arrays and Pointers

An array name acts as a pointer to its first element, allowing pointer arithmetic to access elements.

int arr[5] = {1, 2, 3, 4, 5};
printf("Element at index 2: %d\n", *(arr + 2)); // Outputs 3

Two-Dimensional and Multidimensional Arrays

Two-Dimensional Arrays

A two-dimensional array is an array of arrays, often used to represent tables or matrices with rows and columns.

Defining a Two-Dimensional Array:

type arrayName[rowSize][columnSize];

Here, type is the data type, and rowSize and columnSize are the number of rows and columns.

Initializing a Two-Dimensional Array:

int matrix[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

Accessing Elements:

int element = matrix[rowIndex][columnIndex];

Traversing a Two-Dimensional Array:

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
        printf("%d ", matrix[i][j]);
    }
    printf("\n");
}

Multidimensional Arrays

Multidimensional arrays can have three or more dimensions, useful for complex data structures like 3D spatial data.

Defining a Multidimensional Array:

type arrayName[dim1Size][dim2Size][dim3Size];

Initializing a Multidimensional Array:

int cube[2][3][4] = {
    {{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}},
     {{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}},
    {{{25, 26, 27, 28}, {29, 30, 31, 32}, {33, 34, 35, 36}},
     {{37, 38, 39, 40}, {41, 42, 43, 44}, {45, 46, 47, 48}}}
};

Accessing Elements:

int element = cube[firstDimIndex][secondDimIndex][thirdDimIndex];

Traversing a Multidimensional Array:

for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 3; j++) {
        for (int k = 0; k < 4; k++) {
            printf("%d ", cube[i][j][k]);
        }
        printf("\n");
    }
    printf("\n");
}

Example Code

This example demonstrates defining, initializing, and traversing a two-dimensional array:

#include <stdio.h>

int main() {
    // Define and initialize a 3x4 two-dimensional array
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    // Traverse and print the array
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

Output:

1 2 3 4
5 6 7 8
9 10 11 12

Array Processing Methods

Array Initialization

Arrays can be initialized at declaration or later via assignments.

At Declaration:

int arr[5] = {1, 2, 3, 4, 5};
char name[] = "John Doe"; // String automatically includes null terminator '\0'

After Declaration:

int arr[5];
arr[0] = 1;
arr[1] = 2;
// ...

Accessing Array Elements

Elements are accessed using zero-based indices.

int arr[5] = {1, 2, 3, 4, 5};
printf("%d\n", arr[2]); // Outputs 3

Traversing Arrays

Use loops to access each element.

int arr[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
    printf("%d ", arr[i]);
}
printf("\n");

Array Size

The sizeof operator retrieves the array’s size in bytes.

int arr[5];
printf("Size of array: %lu bytes\n", sizeof(arr));

To get the number of elements, divide by the size of one element.

printf("Number of elements: %lu\n", sizeof(arr) / sizeof(arr[0]));

Array Sorting

Algorithms like bubble sort, insertion sort, or selection sort can sort arrays.

void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

Array Searching

Linear search or binary search can find elements in an array.

int linearSearch(int arr[], int n, int key) {
    for (int i = 0; i < n; i++) {
        if (arr[i] == key) {
            return i;
        }
    }
    return -1;
}

Copying Arrays

Use loops or memcpy to copy arrays.

int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5];
memcpy(arr2, arr1, sizeof(arr1));

Dynamically Allocating Arrays

Use malloc or calloc for dynamic arrays.

int *arr = malloc(5 * sizeof(int));

Arrays and Pointers

An array name is a pointer to its first element.

int arr[5] = {1, 2, 3, 4, 5};
printf("%d\n", *arr); // Outputs 1

Arrays as Function Parameters

Arrays decay to pointers when passed to functions.

void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

Multidimensional Arrays

Multidimensional arrays, like two-dimensional arrays, represent matrices.

int matrix[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

Dynamic Array Resizing

While C arrays have fixed sizes, dynamic memory allocation with malloc, realloc, and free allows variable-sized arrays.

int *dynamicArray;
int size = 5;

// Allocate initial array
dynamicArray = (int *)malloc(size * sizeof(int));

// Resize array
size *= 2;
dynamicArray = (int *)realloc(dynamicArray, size * sizeof(int));

Advanced Array Operations

Reversing an Array:

void reverseArray(int arr[], int n) {
    int start = 0;
    int end = n - 1;
    while (start < end) {
        int temp = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
        start++;
        end--;
    }
}

Rotating an Array:

void rotateArray(int arr[], int n, int k) {
    int temp[k];
    for (int i = 0; i < k; i++) {
        temp[i] = arr[i];
    }
    for (int i = 0; i < n - k; i++) {
        arr[i] = arr[i + k];
    }
    for (int i = 0; i < k; i++) {
        arr[n - k + i] = temp[i];
    }
}

Arrays and Strings

Character arrays in C are often used to represent strings, terminated by a null character (\0).

char str[] = "Hello, World!";
printf("%s\n", str); // Outputs the string using %s

String Processing Functions

The C standard library provides functions like strlen, strcpy, strcat, and strcmp for string manipulation.

#include <string.h>

char str1[] = "Hello";
char str2[] = "World";
char result[20];

strcpy(result, str1); // Copy str1 to result
strcat(result, str2); // Append str2 to result
printf("%s\n", result); // Outputs "HelloWorld"

Array Input and Output

Use scanf and printf to read and write arrays.

int arr[5];
printf("Enter 5 integers: ");
for (int i = 0; i < 5; i++) {
    scanf("%d", &arr[i]);
}
printf("Array elements are: ");
for (int i = 0; i < 5; i++) {
    printf("%d ", arr[i]);
}

Arrays and File Operations

Array data can be saved to or read from files.

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    FILE *fp = fopen("data.txt", "w");

    // Write array to file
    for (int i = 0; i < 5; i++) {
        fprintf(fp, "%d\n", arr[i]);
    }

    fclose(fp);

    // Read array from file
    fp = fopen("data.txt", "r");
    for (int i = 0; i < 5; i++) {
        fscanf(fp, "%d", &arr[i]);
    }

    fclose(fp);

    return 0;
}

Arrays and Memory Management

Use malloc/free or calloc/free to manage dynamic array memory. Failing to free unused dynamic arrays causes memory leaks.

int *arr = (int *)malloc(5 * sizeof(int));
// Use arr...
free(arr); // Free memory used by arr

Array Sorting

Selection Sort

Selection sort finds the minimum (or maximum) element in the unsorted portion and places it at the end of the sorted portion.

void selectionSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        int min_idx = i;
        for (int j = i + 1; j < n; j++)
            if (arr[j] < arr[min_idx])
                min_idx = j;
        int temp = arr[min_idx];
        arr[min_idx] = arr[i];
        arr[i] = temp;
    }
}

Insertion Sort

Insertion sort builds a sorted sequence by inserting unsorted elements into their correct position in the sorted portion.

void insertionSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

Bubble Sort

Bubble sort repeatedly compares adjacent elements, swapping them if they are in the wrong order.

void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

Quick Sort

Quick sort uses a divide-and-conquer strategy, partitioning the array into smaller and larger subarrays, then recursively sorting them.

void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

int partition(int arr[], int low, int high) {
    int pivot = arr[high];
    int i = (low - 1);
    for (int j = low; j <= high - 1; j++) {
        if (arr[j] < pivot) {
            i++;
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    int temp = arr[i + 1];
    arr[i + 1] = arr[high];
    arr[high] = temp;
    return (i + 1);
}

Merge Sort

Merge sort, also based on divide-and-conquer, splits the array into halves, recursively sorts them, and merges the results.

void merge(int arr[], int l, int m, int r) {
    int n1 = m - l + 1;
    int n2 = r - m;
    int L[n1], R[n2];
    for (int i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];
    int i = 0, j = 0, k = l;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        } else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }
}

void mergeSort(int arr[], int l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        mergeSort(arr, l, m);
        mergeSort(arr, m + 1, r);
        merge(arr, l, m, r);
    }
}

Standard Library Sorting

The C standard library provides the qsort function, which sorts arrays using a user-defined comparison function.

#include <stdlib.h>

int compare(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    int arr[] = {64, 34, 25, 12, 22, 11, 90};
    int n = sizeof(arr)/sizeof(arr[0]);
    qsort(arr, n, sizeof(int), compare);
    return 0;
}

Heap Sort

Heap sort is an efficient algorithm using a binary heap. It builds a max-heap, repeatedly removes the largest element, and adjusts the heap.

void heapify(int arr[], int n, int i) {
    int largest = i; // Initialize largest as root
    int left = 2 * i + 1; // Left child
    int right = 2 * i + 2; // Right child

    // If left child is larger than root
    if (left < n && arr[left] > arr[largest])
        largest = left;

    // If right child is larger than largest so far
    if (right < n && arr[right] > arr[largest])
        largest = right;

    // If largest is not root
    if (largest != i) {
        int temp = arr[i];
        arr[i] = arr[largest];
        arr[largest] = temp;

        // Recursively heapify the affected sub-tree
        heapify(arr, n, largest);
    }
}

void heapSort(int arr[], int n) {
    // Build heap
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);

    // Extract elements from heap
    for (int i = n - 1; i >= 0; i--) {
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;

        heapify(arr, i, 0);
    }
}

Counting Sort

Counting sort is a non-comparison-based integer sorting algorithm, suitable for integers within a specific range. It stores counts of values in an auxiliary array.

void countSort(int arr[], int n, int exp) {
    int output[n]; // Output array
    int i, count[10] = {0};

    // Store count of occurrences
    for (i = 0; i < n; i++)
        count[(arr[i] / exp) % 10]++;

    // Adjust count array
    for (i = 1; i < 10; i++)
        count[i] += count[i - 1];

    // Build output array
    for (i = n - 1; i >= 0; i--) {
        output[count[(arr[i] / exp) % 10] - 1] = arr[i];
        count[(arr[i] / exp) % 10]--;
    }

    // Copy output to input array
    for (i = 0; i < n; i++)
        arr[i] = output[i];
}

Bucket Sort

Bucket sort, an enhancement of counting sort, uses a mapping function to distribute elements into buckets, which are then sorted.

#include <vector>
#include <algorithm>

void bucketSort(float arr[], int n) {
    // Create n empty buckets
    std::vector<float> b[n];

    // Put array elements in buckets
    for (int i = 0; i < n; i++) {
        int bi = n * arr[i]; // Index in bucket
        b[bi].push_back(arr[i]);
    }

    // Sort individual buckets
    for (int i = 0; i < n; i++)
        std::sort(b[i].begin(), b[i].end());

    // Concatenate buckets into arr
    int index = 0;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < b[i].size(); j++)
            arr[index++] = b[i][j];
}

Array Bounds and Overflow

Array Out-of-Bounds Access

Array out-of-bounds access occurs when attempting to access an element outside the array’s defined range. C does not perform automatic bounds checking, which can lead to accessing other variables’ memory or system-reserved areas, causing errors.

Example Code:

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int i;

    // Attempt to access the 6th element
    i = arr[5];
    printf("Value at arr[5]: %d\n", i); // Out-of-bounds access

    return 0;
}

Solutions:

  • Check Indices: Ensure indices are within valid ranges before accessing.
  • Use Conditional Statements: Verify indices with if statements.

Safe Example:

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int i = 5;

    if (i >= 0 && i < 5) {
        printf("Value at arr[%d]: %d\n", i, arr[i]);
    } else {
        printf("Array index out of bounds.\n");
    }

    return 0;
}

Memory Overflow

Memory overflow occurs in dynamically allocated memory when writing beyond the allocated block, potentially overwriting other memory and causing data corruption.

Example Code:

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

int main() {
    int *ptr = (int *)malloc(10 * sizeof(int));
    int i;

    // Write beyond allocated memory
    for (i = 0; i <= 10; i++) {
        ptr[i] = i * i;
    }

    free(ptr);
    return 0;
}

Solutions:

  • Correct Allocation: Ensure allocated memory is sufficient.
  • Free Memory: Use free() to release unneeded memory, preventing leaks.

Safe Example:

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

int main() {
    int *ptr = (int *)malloc(10 * sizeof(int));
    int i;

    // Write within allocated memory
    for (i = 0; i < 10; i++) {
        ptr[i] = i * i;
    }

    free(ptr);
    return 0;
}

Strategies to Prevent Bounds and Overflow Issues

  • Use assert(): In debugging, use assert() to check array bounds.
  • Use Safe Functions: Prefer strncpy over strcpy, snprintf over sprintf for added safety.
  • Modern C Features: In C99 or later, use the restrict keyword to indicate non-overlapping pointers, aiding optimization and safety.
  • Static Analysis Tools: Use tools like Valgrind or AddressSanitizer to detect runtime errors like out-of-bounds access and memory leaks.

String Operations and Methods

String Copying

The strcpy() function copies one string to another.

Example Code:

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

int main() {
    char str1[50];
    char str2[] = "Hello, World!";

    // Copy string
    strcpy(str1, str2);
    printf("Copied string: %s\n", str1);

    return 0;
}

String Concatenation

The strcat() function appends one string to the end of another.

Example Code:

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

int main() {
    char str1[50] = "Hello, ";
    char str2[] = "World!";

    // Concatenate strings
    strcat(str1, str2);
    printf("Concatenated string: %s\n", str1);

    return 0;
}

String Comparison

The strcmp() function compares two strings.

Example Code:

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

int main() {
    char str1[] = "Hello";
    char str2[] = "hello";

    // Compare strings
    int result = strcmp(str1, str2);
    if (result == 0) {
        printf("Strings are equal.\n");
    } else if (result < 0) {
        printf("str1 is less than str2.\n");
    } else {
        printf("str1 is greater than str2.\n");
    }

    return 0;
}

String Length

The strlen() function returns the length of a string (excluding the null terminator \0).

Example Code:

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

int main() {
    char str[] = "Hello, World!";

    // Get string length
    size_t len = strlen(str);
    printf("Length of string: %zu\n", len);

    return 0;
}

String Searching

The strstr() function finds a substring within a string.

Example Code:

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

int main() {
    char str[] = "Hello, World!";
    char substr[] = "World";

    // Search for substring
    char *found = strstr(str, substr);
    if (found) {
        printf("Substring found: %s\n", found);
    } else {
        printf("Substring not found.\n");
    }

    return 0;
}

String Replacement

While the C standard library lacks a direct replacement function, strstr() and strncpy() can be combined for replacement.

Example Code:

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

void replace(char *str, const char *oldstr, const char *newstr) {
    char *p = strstr(str, oldstr);
    if (p) {
        size_t oldlen = strlen(oldstr);
        size_t newlen = strlen(newstr);
        memmove(p + newlen, p + oldlen, strlen(p + oldlen) + 1);
        strncpy(p, newstr, newlen);
    }
}

int main() {
    char str[] = "Hello, World!";
    replace(str, "World", "Universe");
    printf("Replaced string: %s\n", str);

    return 0;
}

String Splitting

The strtok() function splits a string into tokens.

Example Code:

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

int main() {
    char str[] = "one,two,three,four,five";
    char *token;

    // Split string
    token = strtok(str, ",");
    while (token != NULL) {
        printf("%s\n", token);
        token = strtok(NULL, ",");
    }

    return 0;
}

String Conversion

Functions like atoi(), atof(), and strtoul() convert strings to numbers.

Example Code:

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

int main() {
    char str[] = "12345";
    int num = atoi(str);

    printf("Converted number: %d\n", num);

    return 0;
}

String Formatting

The sprintf() function writes formatted data to a string.

Example Code:

#include <stdio.h>

int main() {
    char str[50];
    int num = 12345;

    // Format string
    sprintf(str, "The number is %d", num);
    printf("%s\n", str);

    return 0;
}

Safe String Operations

Some C string functions (e.g., gets(), scanf()) are prone to buffer overflows and should be avoided. Use safer alternatives like fgets() or scanf("%[^\n]%*c").

Example Code:

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

int main() {
    char str[50];

    // Safely read a line
    fgets(str, sizeof(str), stdin);
    str[strcspn(str, "\n")] = 0; // Remove newline

    printf("Read string: %s\n", str);

    return 0;
}

String Reversal

Use a two-pointer technique to reverse a string.

Example Code:

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

void reverseString(char *str) {
    int len = strlen(str);
    for (int i = 0; i < len / 2; i++) {
        char temp = str[i];
        str[i] = str[len - i - 1];
        str[len - i - 1] = temp;
    }
}

int main() {
    char str[] = "Hello, World!";
    reverseString(str);
    printf("Reversed string: %s\n", str);

    return 0;
}

Case Conversion

Use toupper() and tolower() to convert character cases.

Example Code:

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

void toUpperCase(char *str) {
    for (int i = 0; i < strlen(str); i++) {
        str[i] = toupper(str[i]);
    }
}

void toLowerCase(char *str) {
    for (int i = 0; i < strlen(str); i++) {
        str[i] = tolower(str[i]);
    }
}

int main() {
    char str[] = "Hello, World!";
    toUpperCase(str);
    printf("Uppercase: %s\n", str);

    toLowerCase(str);
    printf("Lowercase: %s\n", str);

    return 0;
}

String Concatenation with Dynamic Allocation

For concatenating multiple strings or generating strings of unknown length, use dynamically allocated arrays.

Example Code:

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

char *concatStrings(const char *str1, const char *str2) {
    size_t len1 = strlen(str1);
    size_t len2 = strlen(str2);
    size_t totalLen = len1 + len2 + 1;
    char *result = malloc(totalLen);
    if (!result) {
        return NULL;
    }
    memcpy(result, str1, len1);
    memcpy(result + len1, str2, len2 + 1);
    return result;
}

int main() {
    const char *str1 = "Hello, ";
    const char *str2 = "World!";
    char *result = concatStrings(str1, str2);
    if (result) {
        printf("Concatenated string: %s\n", result);
        free(result);
    } else {
        printf("Memory allocation failed.\n");
    }

    return 0;
}

Complex String Search and Replace

For advanced string search and replace, use the <regex.h> library.

Example Code:

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

int regexReplace(char *str, const char *pattern, const char *replacement) {
    regex_t reg;
    int status;
    if ((status = regcomp(®, pattern, REG_EXTENDED)) != 0) {
        return status;
    }
    regmatch_t match[1];
    while (!regexec(®, str, 1, match, 0)) {
        size_t match_start = match[0].rm_so;
        size_t match_end = match[0].rm_eo;
        size_t pattern_len = match_end - match_start;
        size_t repl_len = strlen(replacement);
        memmove(str + match_start + repl_len, str + match_end, strlen(str + match_end) + 1);
        memcpy(str + match_start, replacement, repl_len);
    }
    regfree(®);
    return 0;
}

int main() {
    char str[] = "The quick brown fox jumps over the lazy dog.";
    regexReplace(str, "quick", "slow");
    printf("Replaced string: %s\n", str);

    return 0;
}

Unicode String Handling

The C standard library primarily supports ASCII. For Unicode, use external libraries like ICU.

Example Code (Using ICU Library):

#include <stdio.h>
#include <unicode/ustream.h>
#include <unicode/ustring.h>

int main() {
    UErrorCode status = U_ZERO_ERROR;
    icu::UnicodeString unicodeStr(u"Hello, 世界!");
    icu::UnicodeString upperStr = unicodeStr.toUpper(status);
    if (U_SUCCESS(status)) {
        printf("Uppercase: %ls\n", upperStr.getTerminatedBuffer());
    }

    return 0;
}

String Encoding and Decoding

For encodings like Base64 or URL encoding, use libraries such as libb64 or libcurl.

Example Code (Base64 Encoding with libb64):

#include <stdio.h>
#include <string.h>
#include <b64/base64.h>

int main() {
    const char *original = "Hello, World!";
    char *encoded = base64_encode((const unsigned char *)original, strlen(original));
    printf("Encoded: %s\n", encoded);
    free(encoded);

    return 0;
}
Share your love