1. Array Fundamentals
An array is a contiguous block of memory that stores elements of the same data type. Unlike individual variables, arrays enable efficient storage and manipulation of multiple related values using a single identifier and an index.
2. One-Dimensional Arrays
2.1 Declaring One-Dimensional Arrays
The declaration processs follows a systematic approach:
- Specify the element type followed by a name
- Append square brackets containing the element count
- The complete declaration represents a collection of that type
Example 1: Five integer elements
int values[5];
Example 2: Five pointers to integers
int *ptr_array[5];
Example 3: Five arrays, each containing ten integers (2D array)
int matrix[5][10];
Example 4: Five functon pointers, each accepting two integers and returning an integer
int (*func_ptr[5])(int, int);
2.2 Array Size Calculation
#include <stdio.h>
int main(void)
{
int data[6] = {0};
size_t total_bytes = sizeof(data);
size_t element_bytes = sizeof(data[0]);
size_t element_count = sizeof(data) / sizeof(data[0]);
printf("Total size: %zu bytes\n", total_bytes);
printf("Element size: %zu bytes\n", element_bytes);
printf("Element count: %zu\n", element_count);
return 0;
}
Total size: 24 bytes
Element size: 4 bytes
Element count: 6
2.3 Array Initialization Methods
Full initialization:
int numbers[5] = {10, 20, 30, 40, 50};
// Alternatively, the dimension can be omitted:
// int numbers[] = {10, 20, 30, 40, 50};
Partial initialization:
int partial[5] = {1, 2, 3}; // Remaining elements default to 0
Zero initialization:
int zeroed[5] = {0}; // All elements become 0
int also_zero[5] = {}; // Also valid, all elements become 0
Designated initializer (C99):
int designated[5] = {[1] = 100, [3] = 300};
2.4 Array Element Manipulation
Arrays require element-by-element operations. Direct assignment between arrays is not permitted.
Example 1: Input and display
#include <stdio.h>
int main(void)
{
int buffer[5] = {0};
size_t count = sizeof(buffer) / sizeof(buffer[0]);
for (size_t i = 0; i < count; i++)
{
scanf("%d", buffer + i);
}
for (size_t i = 0; i < count; i++)
{
printf("%d ", buffer[i]);
}
printf("\n");
return 0;
}
Example 2: Finding maximum and minimum values
#include <stdio.h>
int main(void)
{
int dataset[10] = {0};
size_t len = sizeof(dataset) / sizeof(dataset[0]);
for (size_t i = 0; i < len; i++)
{
scanf("%d", &dataset[i]);
}
int max_val = dataset[0];
int min_val = dataset[0];
for (size_t i = 1; i < len; i++)
{
if (dataset[i] > max_val)
max_val = dataset[i];
if (dataset[i] < min_val)
min_val = dataset[i];
}
printf("Maximum: %d\n", max_val);
printf("Minimum: %d\n", min_val);
return 0;
}
Example 3: Array reversal
#include <stdio.h>
int main(void)
{
int data[10] = {0};
size_t len = sizeof(data) / sizeof(data[0]);
for (size_t i = 0; i < len; i++)
{
scanf("%d", &data[i]);
}
for (size_t i = 0, j = len - 1; i < j; i++, j--)
{
data[i] ^= data[j];
data[j] ^= data[i];
data[i] ^= data[j];
}
for (size_t i = 0; i < len; i++)
{
printf("%d ", data[i]);
}
printf("\n");
return 0;
}
Example 4: Sorting algorithms
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
int data[10] = {0};
size_t len = sizeof(data) / sizeof(data[0]);
srand(time(NULL));
for (size_t i = 0; i < len; i++)
{
data[i] = rand() % 100 + 1;
}
printf("Before sorting:\n");
for (size_t i = 0; i < len; i++)
{
printf("%d ", data[i]);
}
printf("\n");
// Bubble sort implementation
for (size_t i = 0; i < len - 1; i++)
{
for (size_t j = 0; j < len - 1 - i; j++)
{
if (data[j] > data[j + 1])
{
data[j] ^= data[j + 1];
data[j + 1] ^= data[j];
data[j] ^= data[j + 1];
}
}
}
printf("After sorting:\n");
for (size_t i = 0; i < len; i++)
{
printf("%d ", data[i]);
}
printf("\n");
return 0;
}
3. Two-Dimensional Arrays
3.1 Determining Dimensions
#include <stdio.h>
int main(void)
{
int grid[3][4] = {{0}};
size_t rows = sizeof(grid) / sizeof(grid[0]);
size_t cols = sizeof(grid[0]) / sizeof(grid[0][0]);
printf("Rows: %zu, Columns: %zu\n", rows, cols);
return 0;
}
Rows: 3, Columns: 4
3.2 Initialization Strategies
Nested braces (row-by-row):
int matrix1[3][4] = {
{1, 2},
{5, 6},
{9, 10, 11}
};
Flat initialization:
int matrix2[3][4] = {1, 2, 5, 6, 9, 10, 11};
Both approaches populate elements in row-major order. Unspecified elements initialize to zero.
3.3 Element Access Patterns
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
int grid[3][4] = {0};
size_t rows = sizeof(grid) / sizeof(grid[0]);
size_t cols = sizeof(grid[0]) / sizeof(grid[0][0]);
srand(time(NULL));
for (size_t i = 0; i < rows * cols; i++)
{
*(&grid[0][0] + i) = rand() % 100 + 1;
}
for (size_t i = 0; i < rows; i++)
{
for (size_t j = 0; j < cols; j++)
{
printf("%4d ", grid[i][j]);
}
printf("\n");
}
return 0;
}
4. Character Arrays (Strings)
4.1 Initialization Approaches
Character-by-character (not recommended):
char greeting[5] = {'h', 'e', 'l', 'l', 'o'};
String literal (recommended):
char greeting[6] = "hello"; // Compiler appends '\0' automatically
The null terminator \0 marks the end of a string and requires allocation space.
4.2 Traversal Techniques
Loop-based iteration:
#include <stdio.h>
int main(void)
{
char message[6] = "hello";
for (size_t i = 0; i < sizeof(message); i++)
{
putchar(message[i]);
putchar(' ');
}
putchar('\n');
return 0;
}
Direct string output:
#include <stdio.h>
int main(void)
{
char text[32] = "embedded programming";
printf("%s\n", text);
return 0;
}
4.3 sizeof Versus strlen
#include <stdio.h>
#include <string.h>
int main(void)
{
char text[32] = "embedded";
printf("sizeof: %zu bytes (includes null terminator)\n", sizeof(text));
printf("strlen: %zu characters (excludes null terminator)\n", strlen(text));
return 0;
}
sizeof: 32 bytes
strlen: 8 characters
Key distinction: sizeof returns the total allocated memory including \0, while strlen counts actual characters before the null terminator.
4.4 Input Methods for Character Arrays
Using scanf:
#include <stdio.h>
int main(void)
{
char input[64] = {0};
scanf("%63s", input); // Limit to prevent overflow
printf("%s\n", input);
return 0;
}
Using fgets (preferred for safety):
#include <stdio.h>
int main(void)
{
char buffer[128] = {0};
char *result = NULL;
result = fgets(buffer, sizeof(buffer), stdin);
if (result != NULL)
{
// Remove trailing newline if present
size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n')
{
buffer[len - 1] = '\0';
}
printf("%s\n", buffer);
}
return 0;
}
5. Two-Dimensional Character Arrays
char names[3][128] = {
"Alice",
"Bob",
"Charlie"
};
Each row functions as an independent string storage.
6. Practical Exercises
Exercise 1: String Length Without strlen
#include <stdio.h>
int main(void)
{
char text[128] = {0};
size_t length = 0;
fgets(text, sizeof(text), stdin);
// Remove newline
size_t i = 0;
while (text[i] != '\0')
{
if (text[i] == '\n')
{
text[i] = '\0';
break;
}
i++;
}
// Calculate length manually
length = 0;
while (text[length] != '\0')
{
length++;
}
printf("Length: %zu\n", length);
return 0;
}
Exercise 2: String Copy Operation
#include <stdio.h>
int main(void)
{
char source[128] = {0};
char destination[128] = {0};
fgets(source, sizeof(source), stdin);
// Remove newline
size_t src_len = 0;
while (source[src_len] != '\0' && source[src_len] != '\n')
{
src_len++;
}
source[src_len] = '\0';
// Copy character by character
for (size_t i = 0; i <= src_len; i++)
{
destination[i] = source[i];
}
printf("Copied: %s\n", destination);
return 0;
}
Exercise 3: String Concatenation
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[256] = {0};
char str2[128] = {0};
printf("First string: ");
fgets(str1, sizeof(str1), stdin);
str1[strcspn(str1, "\n")] = '\0';
printf("Second string: ");
fgets(str2, sizeof(str2), stdin);
str2[strcspn(str2, "\n")] = '\0';
size_t pos = strlen(str1);
for (size_t i = 0; str2[i] != '\0'; i++)
{
str1[pos + i] = str2[i];
}
printf("Concatenated: %s\n", str1);
return 0;
}
Exercise 4: Character Search
#include <stdio.h>
#include <string.h>
int main(void)
{
char text[128] = {0};
char target;
printf("Enter text: ");
fgets(text, sizeof(text), stdin);
text[strcspn(text, "\n")] = '\0';
printf("Character to find: ");
scanf("%c", &target);
int index = -1;
for (size_t i = 0; text[i] != '\0'; i++)
{
if (text[i] == target)
{
index = (int)i;
break;
}
}
if (index >= 0)
{
printf("Found at index: %d\n", index);
}
else
{
printf("Character not found\n");
}
return 0;
}
Exercise 5: String Insertion at Position
#include <stdio.h>
#include <string.h>
int main(void)
{
char original[256] = {0};
char insertion[128] = {0};
char result[384] = {0};
int position = 0;
printf("Original string: ");
fgets(original, sizeof(original), stdin);
original[strcspn(original, "\n")] = '\0';
printf("String to insert: ");
fgets(insertion, sizeof(insertion), stdin);
insertion[strcspn(insertion, "\n")] = '\0';
printf("Position: ");
scanf("%d", &position);
size_t orig_len = strlen(original);
size_t insert_len = strlen(insertion);
// Handle position beyond string length
if (position >= (int)orig_len)
{
strcpy(result, original);
strcat(result, insertion);
}
else
{
// Copy before insertion point
for (size_t i = 0; i < (size_t)position; i++)
{
result[i] = original[i];
}
// Insert new string
for (size_t i = 0; i < insert_len; i++)
{
result[position + i] = insertion[i];
}
// Copy remaining characters
for (size_t i = (size_t)position; i < orig_len; i++)
{
result[insert_len + i] = original[i];
}
}
printf("Result: %s\n", result);
return 0;
}
7. Array-Name Semantics
The array name behaves differently depending on context:
| Context | Behavior |
|---|---|
sizeof(array_name) |
Represents total type size |
&array_name |
Adress of the entire array |
| All other contexts | Equivalent to &array_name[0] (pointer to first element) |
#include <stdio.h>
int main(void)
{
int data[5] = {1, 2, 3, 4, 5};
printf("data: %p\n", (void *)data);
printf("&data[0]: %p\n", (void *)&data[0]);
printf("&data: %p\n", (void *)&data);
printf("sizeof(data): %zu\n", sizeof(data));
return 0;
}
The addresses of data and &data[0] are numerically equal, but their types differ: int* versus int (*)[5].