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
ifstatements.
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
strncpyoverstrcpy,snprintfoversprintffor added safety. - Modern C Features: In C99 or later, use the
restrictkeyword 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;
}



