Arrays in C

Arrays are fundamental data structures in C that allow you to store multiple elements of the same type in contiguous memory locations. They provide efficient indexed access to elements and form the foundation for more complex data structures.


Table of Contents

Table of Contents

  1. What are Arrays?
  2. Array Declaration
  3. Array Initialization
  4. Accessing Array Elements
  5. Array Size and Memory Layout
  6. Multidimensional Arrays
  7. Arrays and Pointers
  8. Passing Arrays to Functions
  9. Array of Pointers
  10. Common Array Operations
  11. Variable Length Arrays (C99)
  12. Array Limitations and Pitfalls
  13. Best Practices

What are Arrays?

An array is a collection of elements of the same data type stored in contiguous memory locations. Each element can be accessed by its index (position) in the array.

Key Characteristics

  • Homogeneous: All elements must be of the same type
  • Contiguous: Elements are stored sequentially in memory
  • Fixed Size: Size is determined at compile time (except VLA)
  • Zero-based Indexing: First element is at index 0
  • Direct Access: Any element can be accessed in O(1) time

Visual Representation

Memory:  [1000] [1004] [1008] [1012] [1016]
Index:      0      1      2      3      4
Value:      5     10     15     20     25

Array Declaration

Syntax

data_type array_name[array_size];

Examples

int numbers[10];           // array of 10 integers
float temperatures[7];     // array of 7 floats
char name[50];             // array of 50 characters
double matrix[5][5];       // 2D array (5x5)

Important Notes

  • array_size must be a constant expression in traditional C
  • Size must be positive integer
  • Elements are uninitialized (contain garbage values)
const int SIZE = 100;
int valid[SIZE];           // OK if SIZE is constant
int n = 50;
int invalid[n];            // Not allowed in C89, but allowed in C99 (VLA)

Array Initialization

1. Initialization at Declaration

// Full initialization
int numbers[5] = {10, 20, 30, 40, 50};
// Partial initialization (remaining elements set to 0)
int numbers[5] = {10, 20};        // {10, 20, 0, 0, 0}
// Initialize all elements to 0
int zeros[10] = {0};               // All elements set to 0
// Initialize all elements to a specific value (not directly supported)
int all_fives[10] = {5};           // {5, 0, 0, 0, ...} NOT {5,5,5,5...}
// Compiler determines size
int auto_size[] = {1, 2, 3, 4, 5}; // size inferred as 5
// Designated initializers (C99)
int arr[10] = {[0] = 1, [5] = 2, [9] = 3}; // {1,0,0,0,0,2,0,0,0,3}

2. Character Array Initialization

// String initialization
char str1[] = "Hello";              // {'H','e','l','l','o','\0'}
char str2[6] = "Hello";              // Same as above
char str3[10] = "Hello";             // {'H','e','l','l','o','\0',0,0,0,0}
// Character by character
char str4[] = {'H', 'e', 'l', 'l', 'o', '\0'};

3. Multidimensional Array Initialization

// 2D array initialization
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
// Flattened initialization
int matrix2[2][3] = {1, 2, 3, 4, 5, 6};
// Partial initialization
int matrix3[2][3] = {
{1, 2},      // third element defaults to 0
{4}          // rest default to 0
};               // {{1,2,0}, {4,0,0}}

4. Static Initialization

static int counts[10] = {1, 2, 3};  // Static arrays are zero-initialized by default

Accessing Array Elements

Basic Access

#include <stdio.h>
int main() {
int numbers[5] = {10, 20, 30, 40, 50};
// Access individual elements
printf("First element: %d\n", numbers[0]);     // 10
printf("Third element: %d\n", numbers[2]);     // 30
printf("Last element: %d\n", numbers[4]);      // 50
// Modify elements
numbers[1] = 25;
printf("Modified second: %d\n", numbers[1]);   // 25
return 0;
}

Array Traversal

#include <stdio.h>
int main() {
int scores[] = {85, 92, 78, 90, 88};
int size = sizeof(scores) / sizeof(scores[0]);
// Using for loop
printf("All scores: ");
for (int i = 0; i < size; i++) {
printf("%d ", scores[i]);
}
printf("\n");
// Calculate sum and average
int sum = 0;
for (int i = 0; i < size; i++) {
sum += scores[i];
}
double average = (double)sum / size;
printf("Sum: %d, Average: %.2f\n", sum, average);
// Find maximum
int max = scores[0];
for (int i = 1; i < size; i++) {
if (scores[i] > max) {
max = scores[i];
}
}
printf("Maximum: %d\n", max);
return 0;
}

Access with Pointers

int numbers[5] = {10, 20, 30, 40, 50};
// Array name is a constant pointer to first element
int *ptr = numbers;                 // points to numbers[0]
// Pointer arithmetic
printf("%d\n", *ptr);               // 10
printf("%d\n", *(ptr + 2));         // 30 (numbers[2])
printf("%d\n", ptr[3]);             // 40 (ptr[3] same as numbers[3])
// Differences: ptr is variable, numbers is constant
ptr++;                              // OK, now points to numbers[1]
// numbers++;                       // ERROR: numbers is constant

Array Size and Memory Layout

Determining Array Size

#include <stdio.h>
int main() {
int numbers[] = {10, 20, 30, 40, 50};
// Total bytes occupied
printf("Total size: %zu bytes\n", sizeof(numbers));     // 20 bytes (5 * 4)
// Size of one element
printf("Element size: %zu bytes\n", sizeof(numbers[0])); // 4 bytes
// Number of elements
int count = sizeof(numbers) / sizeof(numbers[0]);
printf("Number of elements: %d\n", count);               // 5
return 0;
}

Memory Layout

#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
printf("Array memory layout:\n");
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %-4d at address %p\n", i, arr[i], (void*)&arr[i]);
}
// Demonstrate contiguous memory
printf("\nAddress difference between elements:\n");
printf("&arr[1] - &arr[0] = %td bytes\n", 
(char*)&arr[1] - (char*)&arr[0]);  // Should be sizeof(int)
return 0;
}

Output:

Array memory layout:
arr[0] = 10  at address 0x7fff5fbff7a0
arr[1] = 20  at address 0x7fff5fbff7a4
arr[2] = 30  at address 0x7fff5fbff7a8
arr[3] = 40  at address 0x7fff5fbff7ac
arr[4] = 50  at address 0x7fff5fbff7b0
Address difference between elements:
&arr[1] - &arr[0] = 4 bytes

Multidimensional Arrays

2D Arrays (Matrices)

#include <stdio.h>
int main() {
// Declaration and initialization
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// Accessing elements
printf("matrix[1][2] = %d\n", matrix[1][2]);  // 7 (row 1, col 2)
// Traversing 2D array
printf("Matrix:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("%4d", matrix[i][j]);
}
printf("\n");
}
// Memory layout (row-major order)
printf("\nMemory layout (row-major):\n");
int *ptr = &matrix[0][0];
for (int i = 0; i < 12; i++) {
printf("%d ", ptr[i]);
}
printf("\n");
return 0;
}

3D Arrays

#include <stdio.h>
int main() {
// 3D array (2 layers, 3 rows, 4 columns)
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}
}
};
// Accessing elements
printf("cube[1][2][3] = %d\n", cube[1][2][3]);  // 24
// Traversing 3D array
for (int i = 0; i < 2; i++) {
printf("Layer %d:\n", i);
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 4; k++) {
printf("%4d", cube[i][j][k]);
}
printf("\n");
}
printf("\n");
}
return 0;
}

Array of Strings

#include <stdio.h>
int main() {
// 2D character array (array of strings)
char fruits[][10] = {
"Apple",
"Banana",
"Cherry",
"Date"
};
int num_fruits = sizeof(fruits) / sizeof(fruits[0]);
printf("Fruits:\n");
for (int i = 0; i < num_fruits; i++) {
printf("%s\n", fruits[i]);
}
// Modify a string
fruits[1][0] = 'b';  // Change 'B' to 'b'
printf("\nModified: %s\n", fruits[1]);  // "banana"
return 0;
}

Arrays and Pointers

Relationship Between Arrays and Pointers

#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
// arr is a constant pointer to arr[0]
int *ptr = arr;  // ptr points to arr[0]
printf("arr[0] address: %p\n", (void*)&arr[0]);
printf("arr address:    %p\n", (void*)arr);
printf("ptr points to:  %p\n", (void*)ptr);
// Array indexing vs pointer arithmetic
printf("\nArray indexing:\n");
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
printf("\nPointer arithmetic:\n");
for (int i = 0; i < 5; i++) {
printf("*(ptr + %d) = %d\n", i, *(ptr + i));
}
// Using pointer as array name
printf("\nptr[2] = %d\n", ptr[2]);  // Same as arr[2]
return 0;
}

Pointer to Array

#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
// Pointer to entire array (not just first element)
int (*ptr_to_array)[5] = &arr;
// Access through pointer to array
printf("(*ptr_to_array)[2] = %d\n", (*ptr_to_array)[2]);  // 30
// Difference between array pointer and element pointer
int *ptr_to_element = arr;
printf("ptr_to_element + 1: %p\n", (void*)(ptr_to_element + 1));
printf("ptr_to_array + 1:   %p\n", (void*)(ptr_to_array + 1));
// ptr_to_array + 1 skips entire array (20 bytes)
return 0;
}

Passing Arrays to Functions

Method 1: Pass by Reference with Size

#include <stdio.h>
// Function that receives array as pointer
void print_array(int *arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
// Function that modifies array
void double_elements(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] *= 2;
}
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]);
printf("Original: ");
print_array(numbers, size);
double_elements(numbers, size);
printf("Doubled:  ");
print_array(numbers, size);
return 0;
}

Method 2: Pass 2D Arrays

#include <stdio.h>
// Must specify column size for 2D arrays
void print_matrix(int matrix[][4], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 4; j++) {
printf("%4d", matrix[i][j]);
}
printf("\n");
}
}
// Alternative: pass as pointer to array
void print_matrix2(int (*matrix)[4], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 4; j++) {
printf("%4d", matrix[i][j]);
}
printf("\n");
}
}
int main() {
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
printf("Matrix:\n");
print_matrix(matrix, 3);
printf("\nUsing pointer syntax:\n");
print_matrix2(matrix, 3);
return 0;
}

Method 3: Returning Arrays from Functions

#include <stdio.h>
#include <stdlib.h>
// Return dynamically allocated array
int* create_array(int size, int initial_value) {
int *arr = (int*)malloc(size * sizeof(int));
if (arr == NULL) {
return NULL;
}
for (int i = 0; i < size; i++) {
arr[i] = initial_value;
}
return arr;
}
// Return static array (BAD - returns pointer to local variable)
int* bad_function() {
int local_arr[5] = {1, 2, 3, 4, 5};
return local_arr;  // WRONG! local_arr goes out of scope
}
// Return static array (OK - static storage duration)
int* static_array() {
static int arr[5] = {10, 20, 30, 40, 50};
return arr;  // OK - static persists
}
int main() {
int *dynamic = create_array(10, 42);
if (dynamic != NULL) {
printf("First element: %d\n", dynamic[0]);
free(dynamic);  // Don't forget to free!
}
int *static_arr = static_array();
printf("Static array[2]: %d\n", static_arr[2]);  // 30
return 0;
}

Array of Pointers

Basic Array of Pointers

#include <stdio.h>
#include <stdlib.h>
int main() {
int a = 10, b = 20, c = 30, d = 40;
// Array of integer pointers
int *ptr_array[4];
ptr_array[0] = &a;
ptr_array[1] = &b;
ptr_array[2] = &c;
ptr_array[3] = &d;
// Access values through pointer array
for (int i = 0; i < 4; i++) {
printf("*ptr_array[%d] = %d\n", i, *ptr_array[i]);
}
// Modify through pointer array
*ptr_array[2] = 300;
printf("c after modification: %d\n", c);  // 300
return 0;
}

Array of Strings (Using Pointers)

#include <stdio.h>
int main() {
// Array of pointers to string literals
const char *colors[] = {
"Red",
"Green",
"Blue",
"Yellow"
};
int num_colors = sizeof(colors) / sizeof(colors[0]);
printf("Colors:\n");
for (int i = 0; i < num_colors; i++) {
printf("%s\n", colors[i]);
}
// Note: String literals are read-only
// colors[0][0] = 'R';  // Would cause undefined behavior
return 0;
}

Jagged Arrays (Rows of Different Lengths)

#include <stdio.h>
#include <stdlib.h>
int main() {
// Jagged array using array of pointers
int *jagged[3];
int sizes[3] = {3, 5, 2};
// Allocate rows of different sizes
for (int i = 0; i < 3; i++) {
jagged[i] = (int*)malloc(sizes[i] * sizeof(int));
// Initialize
for (int j = 0; j < sizes[i]; j++) {
jagged[i][j] = (i + 1) * (j + 1);
}
}
// Print jagged array
for (int i = 0; i < 3; i++) {
printf("Row %d (size %d): ", i, sizes[i]);
for (int j = 0; j < sizes[i]; j++) {
printf("%d ", jagged[i][j]);
}
printf("\n");
}
// Free memory
for (int i = 0; i < 3; i++) {
free(jagged[i]);
}
return 0;
}

Common Array Operations

1. Linear Search

#include <stdio.h>
int linear_search(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i;  // Return index if found
}
}
return -1;  // Not found
}
int main() {
int numbers[] = {34, 12, 78, 45, 90, 23};
int size = sizeof(numbers) / sizeof(numbers[0]);
int target = 45;
int index = linear_search(numbers, size, target);
if (index != -1) {
printf("Found %d at index %d\n", target, index);
} else {
printf("%d not found\n", target);
}
return 0;
}

2. Binary Search (Sorted Array)

#include <stdio.h>
int binary_search(int arr[], int size, int target) {
int left = 0, right = size - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
}
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
int main() {
int numbers[] = {12, 23, 34, 45, 78, 90};  // Must be sorted
int size = sizeof(numbers) / sizeof(numbers[0]);
int target = 34;
int index = binary_search(numbers, size, target);
if (index != -1) {
printf("Found %d at index %d\n", target, index);
} else {
printf("%d not found\n", target);
}
return 0;
}

3. Array Sorting (Bubble Sort)

#include <stdio.h>
#include <stdbool.h>
void bubble_sort(int arr[], int size) {
for (int i = 0; i < size - 1; i++) {
bool swapped = false;
for (int j = 0; j < size - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// Swap elements
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (!swapped) {
break;  // Array already sorted
}
}
}
void print_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int numbers[] = {64, 34, 25, 12, 22, 11, 90};
int size = sizeof(numbers) / sizeof(numbers[0]);
printf("Original: ");
print_array(numbers, size);
bubble_sort(numbers, size);
printf("Sorted:   ");
print_array(numbers, size);
return 0;
}

4. Array Reversal

#include <stdio.h>
void reverse_array(int arr[], int size) {
int left = 0, right = size - 1;
while (left < right) {
// Swap elements
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
int main() {
int numbers[] = {1, 2, 3, 4, 5, 6, 7};
int size = sizeof(numbers) / sizeof(numbers[0]);
printf("Original: ");
for (int i = 0; i < size; i++) printf("%d ", numbers[i]);
printf("\n");
reverse_array(numbers, size);
printf("Reversed: ");
for (int i = 0; i < size; i++) printf("%d ", numbers[i]);
printf("\n");
return 0;
}

5. Finding Duplicates

#include <stdio.h>
#include <stdbool.h>
void find_duplicates(int arr[], int size) {
bool found_duplicate = false;
for (int i = 0; i < size - 1; i++) {
for (int j = i + 1; j < size; j++) {
if (arr[i] == arr[j]) {
printf("Duplicate found: %d at indices %d and %d\n", 
arr[i], i, j);
found_duplicate = true;
break;
}
}
}
if (!found_duplicate) {
printf("No duplicates found\n");
}
}
int main() {
int numbers1[] = {1, 2, 3, 4, 5, 3, 6, 7};
int size1 = sizeof(numbers1) / sizeof(numbers1[0]);
printf("Array 1:\n");
find_duplicates(numbers1, size1);
int numbers2[] = {1, 2, 3, 4, 5, 6, 7};
int size2 = sizeof(numbers2) / sizeof(numbers2[0]);
printf("\nArray 2:\n");
find_duplicates(numbers2, size2);
return 0;
}

6. Array Rotation

#include <stdio.h>
// Rotate array left by k positions
void rotate_left(int arr[], int size, int k) {
k = k % size;  // Handle k >= size
// Create temporary array for first k elements
int temp[k];
for (int i = 0; i < k; i++) {
temp[i] = arr[i];
}
// Shift remaining elements left
for (int i = 0; i < size - k; i++) {
arr[i] = arr[i + k];
}
// Copy back temp elements
for (int i = 0; i < k; i++) {
arr[size - k + i] = temp[i];
}
}
void print_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int numbers[] = {1, 2, 3, 4, 5, 6, 7};
int size = sizeof(numbers) / sizeof(numbers[0]);
printf("Original: ");
print_array(numbers, size);
rotate_left(numbers, size, 3);
printf("Rotated:  ");
print_array(numbers, size);
return 0;
}

7. Array Intersection and Union

#include <stdio.h>
#include <stdbool.h>
void find_intersection(int arr1[], int size1, int arr2[], int size2) {
printf("Intersection: ");
for (int i = 0; i < size1; i++) {
for (int j = 0; j < size2; j++) {
if (arr1[i] == arr2[j]) {
printf("%d ", arr1[i]);
break;
}
}
}
printf("\n");
}
void find_union(int arr1[], int size1, int arr2[], int size2) {
// This is a simple approach (assumes no duplicates within arrays)
int union_size = size1 + size2;
int union_arr[union_size];
int index = 0;
// Copy first array
for (int i = 0; i < size1; i++) {
union_arr[index++] = arr1[i];
}
// Add elements from second array that aren't in first
for (int i = 0; i < size2; i++) {
bool found = false;
for (int j = 0; j < size1; j++) {
if (arr2[i] == arr1[j]) {
found = true;
break;
}
}
if (!found) {
union_arr[index++] = arr2[i];
}
}
printf("Union: ");
for (int i = 0; i < index; i++) {
printf("%d ", union_arr[i]);
}
printf("\n");
}
int main() {
int arr1[] = {1, 3, 4, 5, 7};
int arr2[] = {2, 3, 5, 6};
int size1 = sizeof(arr1) / sizeof(arr1[0]);
int size2 = sizeof(arr2) / sizeof(arr2[0]);
find_intersection(arr1, size1, arr2, size2);
find_union(arr1, size1, arr2, size2);
return 0;
}

Variable Length Arrays (C99)

VLA allows array size to be determined at runtime.

Basic VLA Usage

#include <stdio.h>
void process_vla(int n) {
// VLA - size determined at runtime
int vla[n];
// Initialize
for (int i = 0; i < n; i++) {
vla[i] = i * i;
}
// Print
for (int i = 0; i < n; i++) {
printf("%d ", vla[i]);
}
printf("\n");
}
int main() {
int size;
printf("Enter array size: ");
scanf("%d", &size);
process_vla(size);  // Works with runtime size
return 0;
}

2D VLA

#include <stdio.h>
// Function with VLA parameters
void print_matrix(int rows, int cols, int matrix[rows][cols]) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%4d", matrix[i][j]);
}
printf("\n");
}
}
int main() {
int rows = 3, cols = 4;
// 2D VLA
int matrix[rows][cols];
// Initialize
int counter = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = counter++;
}
}
print_matrix(rows, cols, matrix);
return 0;
}

VLA Limitations

// VLAs cannot be:
// - Static or global
// - Initialized at declaration (except with = {0})
// - Have static storage duration
// static int vla[n];     // ERROR: static can't be VLA
// int vla2[n] = {1,2,3}; // ERROR: can't initialize VLA
// But can do:
int vla[n];
for (int i = 0; i < n; i++) vla[i] = 0;  // Manual initialization

Array Limitations and Pitfalls

1. Array Index Out of Bounds

#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
// No bounds checking in C!
arr[5] = 60;   // Buffer overflow - undefined behavior
arr[-1] = 5;   // Also possible - undefined behavior
printf("arr[5] = %d\n", arr[5]);  // May crash or print garbage
return 0;
}

2. Array Decay to Pointer

#include <stdio.h>
void print_size(int arr[]) {
printf("In function: sizeof(arr) = %zu\n", sizeof(arr));  // 8 (pointer size)
}
int main() {
int arr[10];
printf("In main: sizeof(arr) = %zu\n", sizeof(arr));      // 40 (10 * 4)
print_size(arr);
return 0;
}

3. Returning Local Arrays

#include <stdio.h>
int* bad_function() {
int local_array[5] = {1, 2, 3, 4, 5};
return local_array;  // WRONG! local_array goes out of scope
}
int* good_function() {
static int static_array[5] = {1, 2, 3, 4, 5};
return static_array;  // OK - static persists
}
int main() {
int *ptr = good_function();  // OK
printf("%d\n", ptr[2]);      // 3
// ptr = bad_function();      // Undefined behavior
// printf("%d\n", ptr[2]);    // May crash or print garbage
return 0;
}

4. No Built-in Copy or Compare

#include <stdio.h>
#include <string.h>  // For memcpy
int main() {
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5];
// arr2 = arr1;                    // ERROR: can't assign arrays
// Must copy element by element
for (int i = 0; i < 5; i++) {
arr2[i] = arr1[i];
}
// Or use memcpy
memcpy(arr2, arr1, sizeof(arr1));
// Compare arrays
int equal = 1;
for (int i = 0; i < 5; i++) {
if (arr1[i] != arr2[i]) {
equal = 0;
break;
}
}
// Or use memcmp
equal = memcmp(arr1, arr2, sizeof(arr1)) == 0;
return 0;
}

Best Practices

1. Always Check Array Bounds

#include <stdio.h>
#include <assert.h>
void safe_set(int arr[], int size, int index, int value) {
assert(index >= 0 && index < size);  // Debug check
if (index >= 0 && index < size) {    // Runtime check
arr[index] = value;
}
}
int main() {
int numbers[10];
safe_set(numbers, 10, 5, 42);    // OK
safe_set(numbers, 10, 15, 42);   // Caught by assert
return 0;
}

2. Use Named Constants for Array Sizes

#define MAX_STUDENTS 100
#define NAME_LENGTH 50
int student_ids[MAX_STUDENTS];
char student_names[MAX_STUDENTS][NAME_LENGTH];
// Better than magic numbers
// int student_ids[100];
// char student_names[100][50];

3. Pass Size with Arrays

// GOOD: Pass size explicitly
void process_array(int arr[], size_t size) {
for (size_t i = 0; i < size; i++) {
// process arr[i]
}
}
// BAD: Relying on sentinel or global
void process_array_bad(int arr[]) {
// Can't know size without additional information
}

4. Initialize Arrays

// GOOD
int arr[10] = {0};           // All elements zero
int arr2[] = {1, 2, 3, 4, 5}; // Compiler counts elements
// BAD
int arr3[10];                 // Contains garbage values

5. Use sizeof for Portability

// GOOD
int arr[20];
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
arr[i] = i;
}
// BAD
for (int i = 0; i < 20; i++) {  // Hard-coded size
arr[i] = i;
}

6. Be Careful with String Arrays

#include <string.h>
char name[20] = "John";        // Room for "John" plus null terminator
// char name2[4] = "John";     // ERROR: no room for null terminator
strcpy(name, "Christopher");    // Safe: 20 > 11 + 1
// strcpy(name, "Christopher Alexandros"); // Unsafe: would overflow

7. Consider Using Dynamic Allocation for Large Arrays

#include <stdlib.h>
// For large arrays or variable size
int *large_array = malloc(1000000 * sizeof(int));
if (large_array != NULL) {
// Use array
free(large_array);  // Don't forget to free
}

8. Document Array Assumptions

/**
* Finds maximum value in array
* @param arr Array of integers
* @param size Number of elements (must be > 0)
* @return Maximum value
*/
int find_max(int arr[], size_t size) {
// Implementation
}

Summary Table

OperationSyntaxExample
Declarationtype name[size];int scores[10];
Initializationtype name[] = {vals};int nums[] = {1,2,3};
Accessname[index]scores[5] = 95;
Size calculationsizeof(arr)/sizeof(arr[0])int size = sizeof(nums)/sizeof(nums[0]);
2D declarationtype name[rows][cols];int matrix[3][4];
2D accessname[row][col]matrix[1][2] = 42;
Pass to functionfunc(arr, size);print_array(nums, 5);
Dynamic arraymalloc(size * sizeof(type))int *arr = malloc(n * sizeof(int));

Common Array Patterns Cheat Sheet

// 1. Traverse array
for (int i = 0; i < size; i++) {
// process array[i]
}
// 2. Find maximum/minimum
int max = arr[0];
for (int i = 1; i < size; i++) {
if (arr[i] > max) max = arr[i];
}
// 3. Calculate sum
int sum = 0;
for (int i = 0; i < size; i++) {
sum += arr[i];
}
// 4. Copy array
int dest[size];
for (int i = 0; i < size; i++) {
dest[i] = src[i];
}
// 5. Reverse array
for (int i = 0; i < size/2; i++) {
int temp = arr[i];
arr[i] = arr[size-1-i];
arr[size-1-i] = temp;
}
// 6. Search for value
int found = -1;
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
found = i;
break;
}
}
// 7. 2D array traversal
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
// process matrix[i][j]
}
}

Conclusion

Arrays are a fundamental data structure in C that every programmer must master. Key takeaways:

  • Arrays store multiple elements of the same type contiguously
  • Access is via zero-based indices
  • No bounds checking - programmer must ensure safety
  • Array names decay to pointers in most contexts
  • Size must be known to avoid buffer overflows
  • Multidimensional arrays are arrays of arrays
  • VLAs provide runtime sizing (C99)
  • Arrays and pointers are closely related but not identical

Understanding arrays thoroughly is essential for effective C programming, as they form the basis for strings, matrices, and many other data structures.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper