Arrays in C
Learn to store multiple values of the same type efficiently using arrays โ from simple lists to multi-dimensional tables.
๐ค What is an Array?
๐ก The "Boxes in a Row" Analogy
Imagine you need to store test scores for 5 students. You could create 5 separate variables:
int score1 = 85; int score2 = 90; int score3 = 78; int score4 = 92; int score5 = 88;
But what if you have 100 students? Or 1000? Creating individual variables is messy and hard to manage.
An array is like a row of numbered boxes where each box can hold one value, and all boxes are the same type:
Visual: Array as Numbered Boxes
Index: [0] [1] [2] [3] [4]
+---+ +---+ +---+ +---+ +---+
| 85| | 90| | 78| | 92| | 88|
+---+ +---+ +---+ +---+ +---+
scores[0] scores[1] scores[2] scores[3] scores[4]
All boxes are connected and share the same name "scores"
We access each box using its index number (0, 1, 2, 3, 4)
Key Points:
- Array stores multiple values of the same data type
- Each element has an index starting from 0 (not 1!)
- Array size is fixed once created
- Elements are stored in contiguous memory (next to each other)
๐พ How Arrays are Stored in Memory
๐ Memory Layout Visualization
When you create int scores[5] = {85, 90, 78, 92, 88};, here's what happens in memory:
Memory Address (hex) Variable Value
0x1000 scores[0] โ 85
0x1004 scores[1] โ 90 โ Each int takes 4 bytes
0x1008 scores[2] โ 78
0x100C scores[3] โ 92
0x1010 scores[4] โ 88
Base address = &scores[0] = 0x1000
The array name "scores" actually points to the first element!
๐งฎ Address Calculation
To find the address of scores[i]:
Address of scores[i] = Base Address + (i ร size of each element) Example: Where is scores[3]? Address = 0x1000 + (3 ร 4) = 0x1000 + 12 = 0x100C โ
๐ One-Dimensional Arrays
โ๏ธ Declaration and Initialization
Method 1: Declare first, assign later
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int scores[5]; // 5 integers โ
โ scores[0] = 85; // Assign to box 0 โ
โ scores[1] = 90; // Assign to box 1 โ
โ scores[2] = 78; โ
โ scores[3] = 92; โ
โ scores[4] = 88; โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Method 2: Declare and initialize together
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int scores[5] = {85, 90, 78, 92, 88}; โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Method 3: Partial initialization (rest become 0)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int scores[5] = {85, 90}; โ
โ Result: {85, 90, 0, 0, 0} โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Method 4: Let compiler count (size inferred)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ int scores[] = {85, 90, 78, 92, 88}; โ
โ Compiler automatically sets size = 5 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๏ธ Important: Index Starts at 0!
๐ Step-by-Step: How Indexing Works
Array: int scores[5] = {85, 90, 78, 92, 88};
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Position: 1st 2nd 3rd 4th 5th โ Human โ
โ Index: 0 1 2 3 4 โ C โ
โ Value: 85 90 78 92 88 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
To access elements:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ scores[0] gives you 85 โ First item โ
โ scores[1] gives you 90 โ Second item โ
โ scores[4] gives you 88 โ Fifth item โ
โ scores[5] โ ERROR! โ OUT OF BOUNDSโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐จ CRITICAL: scores[5] does NOT exist!
Valid indices are 0, 1, 2, 3, and 4 only
#include <stdio.h>
int main() {
// Declare and initialize
int scores[5] = {85, 90, 78, 92, 88};
// Access individual elements
printf("First student score: %d\n", scores[0]); // 85
printf("Third student score: %d\n", scores[2]); // 78
printf("Last student score: %d\n", scores[4]); // 88
// Modify an element
scores[1] = 95; // Changed 90 to 95
printf("Updated second score: %d\n", scores[1]);
// Calculate array size automatically
int n = sizeof(scores) / sizeof(scores[0]);
printf("Array size: %d elements\n", n);
return 0;
}
๐ Looping Through Arrays
๐ Traversal Process
Step-by-step: Printing all elements
Array: [85, 90, 78, 92, 88]
Size: 5
Iteration | i | scores[i] | Action
----------+---+-----------+------------------
1 | 0 | 85 | Print scores[0]
2 | 1 | 90 | Print scores[1]
3 | 2 | 78 | Print scores[2]
4 | 3 | 92 | Print scores[3]
5 | 4 | 88 | Print scores[4]
6 | 5 | STOP | i < 5 is false
Output: 85 90 78 92 88
#include <stdio.h>
int main() {
int scores[] = {85, 90, 78, 92, 88};
int n = sizeof(scores) / sizeof(scores[0]);
// Forward traversal
printf("All scores: ");
for (int i = 0; i < n; i++) {
printf("%d ", scores[i]);
}
printf("\n");
// Backward traversal
printf("Reverse: ");
for (int i = n - 1; i >= 0; i--) {
printf("%d ", scores[i]);
}
printf("\n");
// Calculate sum and average
int sum = 0;
for (int i = 0; i < n; i++) {
sum += scores[i]; // Add each element to sum
}
float average = (float)sum / n;
printf("Sum: %d, Average: %.2f\n", sum, average);
return 0;
}
๐ ๏ธ Common Array Operations
๐ Operation Examples
1. FIND MAXIMUM
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Start: max = first element (85) โ
โ Compare with 90 โ 90 is bigger โ
โ Compare with 78 โ 90 still biggest โ
โ Compare with 92 โ 92 is bigger! โ
โ Compare with 88 โ 92 still biggest โ
โ Result: 92 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
2. LINEAR SEARCH (Find 78)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Check index 0: 85 โ 78 โ continue โ
โ Check index 1: 90 โ 78 โ continue โ
โ Check index 2: 78 = 78 โ FOUND! โ
โ Return index 2 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
3. REVERSE ARRAY
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Original: [85, 90, 78, 92, 88] โ
โ Swap 0โ4: [88, 90, 78, 92, 85] โ
โ Swap 1โ3: [88, 92, 78, 90, 85] โ
โ Stop: middle reached โ
โ Result: [88, 92, 78, 90, 85] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
#include
// Find maximum element
int findMax(int arr[], int size) {
int max = arr[0];
for (int i = 1; i < size; i++) {
if (arr[i] > max)
max = arr[i];
}
return max;
}
// Linear search
int linearSearch(int arr[], int size, int key) {
for (int i = 0; i < size; i++) {
if (arr[i] == key)
return i; // Return index where found
}
return -1; // Not found
}
// Reverse array in-place
void reverseArray(int arr[], int size) {
for (int i = 0; i < size / 2; i++) {
int temp = arr[i];
arr[i] = arr[size - 1 - i];
arr[size - 1 - i] = temp;
}
}
// Print array
void printArray(int arr[], int size) {
printf("[ ");
for (int i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("]\n");
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int size = sizeof(arr) / sizeof(arr[0]);
printf("Original: ");
printArray(arr, size);
printf("Maximum: %d\n", findMax(arr, size));
int pos = linearSearch(arr, size, 22);
if (pos != -1)
printf("Found 22 at index %d\n", pos);
else
printf("22 not found\n");
reverseArray(arr, size);
printf("Reversed: ");
printArray(arr, size);
return 0;
}
๐ Two-Dimensional Arrays (2D Arrays)
๐ก The "Spreadsheet" Analogy
A 2D array is like a spreadsheet or table with rows and columns:
Visual: 2D Array as a Grid
Column 0 Column 1 Column 2
โ โ โ
Row 0 โ +----------+----------+----------+
| matrix | matrix | matrix |
| [0][0] | [0][1] | [0][2] |
| (1) | (2) | (3) |
+----------+----------+----------+
Row 1 โ | matrix | matrix | matrix |
| [1][0] | [1][1] | [1][2] |
| (4) | (5) | (6) |
+----------+----------+----------+
Row 2 โ | matrix | matrix | matrix |
| [2][0] | [2][1] | [2][2] |
| (7) | (8) | (9) |
+----------+----------+----------+
Declaration: int matrix[3][3] = {
{1, 2, 3}, // Row 0
{4, 5, 6}, // Row 1
{7, 8, 9} // Row 2
};
๐ Real-World Examples
- Seating Chart: Rows = rows of seats, Columns = seat numbers
- Game Board: Chess board, Tic-tac-toe, Sudoku
- Pixel Image: Rows = height, Columns = width
- Student Grades: Rows = students, Columns = subjects
๐ Memory Storage of 2D Arrays
2D arrays are stored in row-major order (row by row) in memory:
Logical View (3ร3 matrix):
1 2 3
4 5 6
7 8 9
Memory Layout (Row-Major Order):
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Address โ Value โ Element โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ 0x1000 โ 1 โ matrix[0][0] โ Row 0 starts here โ
โ 0x1004 โ 2 โ matrix[0][1] โ
โ 0x1008 โ 3 โ matrix[0][2] โ Row 0 ends here โ
โ 0x100C โ 4 โ matrix[1][0] โ Row 1 starts here โ
โ 0x1010 โ 5 โ matrix[1][1] โ
โ 0x1014 โ 6 โ matrix[1][2] โ Row 1 ends here โ
โ 0x1018 โ 7 โ matrix[2][0] โ Row 2 starts here โ
โ 0x101C โ 8 โ matrix[2][1] โ
โ 0x1020 โ 9 โ matrix[2][2] โ Row 2 ends here โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Formula to find address of matrix[i][j]:
Address = Base + (i ร columns + j) ร size_of_element
Example: Where is matrix[1][2]?
Address = 0x1000 + (1 ร 3 + 2) ร 4 = 0x1000 + 20 = 0x1014 โ
#include <stdio.h>
int main() {
// Declaration and initialization
int matrix[3][3] = {
{1, 2, 3}, // Row 0
{4, 5, 6}, // Row 1
{7, 8, 9} // Row 2
};
// Access elements
printf("Element at row 1, col 2: %d\n", matrix[1][2]); // 6
printf("Element at row 0, col 0: %d\n", matrix[0][0]); // 1
// Modify element
matrix[1][1] = 50;
printf("Updated middle element: %d\n", matrix[1][1]);
// Traverse 2D array
printf("\nMatrix:\n");
for (int i = 0; i < 3; i++) { // For each row
for (int j = 0; j < 3; j++) { // For each column
printf("%d ", matrix[i][j]);
}
printf("\n"); // New line after each row
}
return 0;
}
๐งฎ Matrix Operations
๐ Matrix Addition Step-by-Step
Matrix A: Matrix B: Result A + B:
โโโโโฌโโโโฌโโโโ โโโโโฌโโโโฌโโโโ โโโโโฌโโโโฌโโโโ
โ 1 โ 2 โ 3 โ โ 9 โ 8 โ 7 โ โ10 โ10 โ10 โ
โโโโโผโโโโผโโโโค + โโโโโผโโโโผโโโโค = โโโโโผโโโโผโโโโค
โ 4 โ 5 โ 6 โ โ 6 โ 5 โ 4 โ โ10 โ10 โ10 โ
โโโโโผโโโโผโโโโค โโโโโผโโโโผโโโโค โโโโโผโโโโผโโโโค
โ 7 โ 8 โ 9 โ โ 3 โ 2 โ 1 โ โ10 โ10 โ10 โ
โโโโโดโโโโดโโโโ โโโโโดโโโโดโโโโ โโโโโดโโโโดโโโโ
Calculation:
result[i][j] = A[i][j] + B[i][j]
result[0][0] = A[0][0] + B[0][0] = 1 + 9 = 10
result[0][1] = A[0][1] + B[0][1] = 2 + 8 = 10
result[0][2] = A[0][2] + B[0][2] = 3 + 7 = 10
...and so on for all elements
#include
#define ROWS 3
#define COLS 3
// Add two matrices
void addMatrices(int a[ROWS][COLS], int b[ROWS][COLS], int result[ROWS][COLS]) {
for (int i = 0; i < ROWS; i++)
for (int j = 0; j < COLS; j++)
result[i][j] = a[i][j] + b[i][j];
}
// Transpose matrix (rows become columns)
void transpose(int matrix[ROWS][COLS], int trans[COLS][ROWS]) {
for (int i = 0; i < ROWS; i++)
for (int j = 0; j < COLS; j++)
trans[j][i] = matrix[i][j]; // Swap row and column
}
// Print matrix
void printMatrix(int matrix[ROWS][COLS]) {
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++)
printf("%d ", matrix[i][j]);
printf("\n");
}
}
int main() {
int a[ROWS][COLS] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int b[ROWS][COLS] = {{9, 8, 7}, {6, 5, 4}, {3, 2, 1}};
int result[ROWS][COLS];
printf("Matrix A:\n");
printMatrix(a);
printf("\nMatrix B:\n");
printMatrix(b);
addMatrices(a, b, result);
printf("\nA + B:\n");
printMatrix(result);
return 0;
}
๐ Arrays and Pointers Relationship
๐ก The Key Insight
In C, arrays and pointers are closely related. The array name is actually a pointer to the first element!
Array: int arr[5] = {10, 20, 30, 40, 50};
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ The array name "arr" is equivalent to &arr[0] โ
โ โ
โ Memory Layout: โ
โ Address Value Expression Result โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ 0x1000 โ 10 arr[0] 10 โ
โ 0x1004 โ 20 arr[1] 20 โ
โ 0x1008 โ 30 arr[2] 30 โ
โ 0x100C โ 40 arr[3] 40 โ
โ 0x1010 โ 50 arr[4] 50 โ
โ โ โ
โ arr points here (address 0x1000) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Equivalent Ways to Access Elements:
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโ
โ Array Notation โ Pointer Notation โ Value โ
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโค
โ arr[0] โ *arr โ 10 โ
โ arr[1] โ *(arr + 1) โ 20 โ
โ arr[2] โ *(arr + 2) โ 30 โ
โ arr[i] โ *(arr + i) โ ... โ
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโ
Why does *(arr + 1) work?
โข arr is address 0x1000
โข arr + 1 adds sizeof(int) = 4 bytes
โข So arr + 1 = 0x1004 (address of arr[1])
โข *(arr + 1) dereferences to get value 20
#include
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // ptr points to first element
// Both give the same address
printf("arr = %p\n", (void*)arr);
printf("\u0026arr[0] = %p\n", (void*)&arr[0]);
printf("ptr = %p\n", (void*)ptr);
// Different ways to access elements
printf("\nElement at index 2:\n");
printf("Using array: arr[2] = %d\n", arr[2]);
printf("Using pointer: *(arr + 2) = %d\n", *(arr + 2));
printf("Using ptr: ptr[2] = %d\n", ptr[2]);
printf("Using ptr: *(ptr + 2) = %d\n", *(ptr + 2));
// Pointer arithmetic
printf("\nPointer arithmetic:\n");
printf("*ptr = %d\n", *ptr); // 10
ptr++; // Move to next element
printf("*ptr after ptr++ = %d\n", *ptr); // 20
return 0;
}
๐ค Passing Arrays to Functions
๐ก How It Works
When you pass an array to a function, you're actually passing a pointer to the first element. This means:
- The function can modify the original array (pass by reference)
- You must also pass the array size (the function can't determine it)
Passing Arrays to Functions:
1. ONE-DIMENSIONAL ARRAY
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ void modify(int arr[], int size) { โ
โ // arr is a pointer to first elem โ
โ arr[0] = 100; // Modifies originalโ
โ } โ
โ โ
โ // Call: โ
โ int nums[5] = {1, 2, 3, 4, 5}; โ
โ modify(nums, 5); // Pass name + size โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
2. TWO-DIMENSIONAL ARRAY
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ // Column size MUST be specified! โ
โ void print2D(int arr[][3], int rows) {โ
โ for (int i = 0; i < rows; i++) โ
โ for (int j = 0; j < 3; j++) โ
โ printf("%d ", arr[i][j]); โ
โ } โ
โ โ
โ // Call: โ
โ int matrix[2][3] = {{1,2,3},{4,5,6}}; โ
โ print2D(matrix, 2); โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
#include
// Pass 1D array - size needed
void doubleValues(int arr[], int size) {
printf("Doubling values...\n");
for (int i = 0; i < size; i++)
arr[i] *= 2; // Modifies original array!
}
// Pass 2D array - column size required
void print2D(int arr[][3], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++)
printf("%d ", arr[i][j]);
printf("\n");
}
}
// Using pointers
void printWithPointer(int *arr, int size) {
for (int i = 0; i < size; i++)
printf("%d ", *(arr + i));
printf("\n");
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int size = sizeof(arr) / sizeof(arr[0]);
printf("Before: ");
printWithPointer(arr, size);
doubleValues(arr, size);
printf("After: ");
printWithPointer(arr, size);
// 2D array
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
printf("\n2D Array:\n");
print2D(matrix, 2);
return 0;
}
โ ๏ธ Common Mistakes and How to Avoid Them
| Mistake | Wrong Code | Correct Code |
|---|---|---|
| Off-by-one error Using index 5 in array of size 5 |
int arr[5]; |
int arr[5]; |
| Array out of bounds Loop goes too far |
for(i=0; i<=5; i++) |
for(i=0; i<5; i++) |
| Confusing size with last index | // Accessing last element |
// Last element is at |
| Not passing size to function | void func(int arr[]) { |
void func(int arr[], int n) { |
| Forgetting 2D array needs column size | void func(int arr[][]) |
void func(int arr[][COLS]) |
| Array assignment Arrays can't be assigned |
int a[3] = {1,2,3}; |
// Copy element by element |
๐ Practice Problems
Level 1: Beginner
- Sum and Average: Write a program to read 10 numbers into an array and calculate their sum and average.
- Find Maximum: Find the largest number in an array of 20 integers.
- Count Even/Odd: Count how many even and odd numbers are in an array.
Level 2: Intermediate
- Reverse Array: Reverse an array without using a second array.
- Linear Search: Implement a search that returns all indices where the element appears.
- Matrix Diagonal Sum: Calculate the sum of diagonal elements in a square matrix.
Level 3: Advanced
- Matrix Multiplication: Multiply two matrices (must check dimensions are compatible).
- Transpose In-Place: Transpose a square matrix without using extra space.
- Rotate Matrix: Rotate a matrix 90 degrees clockwise.