Arrays in C
Store multiple values of the same type together! Learn 1D arrays (lists), 2D arrays (tables), and how arrays are stored in memory.
What You Will Learn
- โCreate and initialize arrays
- โAccess elements using index (arr[0])
- โLoop through arrays
- โWork with 2D arrays (rows and columns)
01What is an Array?
An array is a collection of elements of the same data type stored in contiguous (adjacent) memory locations. Think of it like a row of boxes, where each box can hold one value and has a number (index) to identify it.
๐ฏ Why Use Arrays?
Without Arrays โ
int score1 = 85;int score2 = 90;int score3 = 78;int score4 = 92;int score5 = 88;// Tedious with 100 students!With Arrays โ
int scores[5] = {85, 90, 78, 92, 88};// One variable for all 5 scores!// Easy to loop throughKey Array Facts
- โข All elements must be the same type (all int, all float, etc.)
- โข Array size is fixed once declared (cannot grow or shrink)
- โข Index starts at 0, not 1 (first element is array[0])
- โข Elements are stored in contiguous memory
02One-Dimensional (1D) Arrays
A 1D array is the simplest form โ a single row of elements. Like a list of items.
Declaration Syntax
๐ This snippet shows the basic syntax for declaring arrays of different data types.
1// Syntax: dataType arrayName[size];23int numbers[5]; // Array of 5 integers4float prices[10]; // Array of 10 floats5char letters[26]; // Array of 26 charactersInitialization Methods
๐ This program demonstrates 5 different ways to create and fill arrays with values. Run it to see how each method works.
1#include <stdio.h>23int main() {4 // Method 1: Initialize at declaration5 int scores[5] = {85, 90, 78, 92, 88};6 7 // Method 2: Partial initialization (remaining = 0)8 int values[5] = {10, 20}; // {10, 20, 0, 0, 0}9 10 // Method 3: All zeros11 int zeros[5] = {0}; // {0, 0, 0, 0, 0}12 13 // Method 4: Let compiler count size14 int auto_size[] = {1, 2, 3, 4}; // Size = 415 16 // Method 5: Initialize after declaration17 int grades[3];18 grades[0] = 95;19 grades[1] = 87;20 grades[2] = 91;21 22 // Accessing elements23 printf("First score: %d\n", scores[0]); // 8524 printf("Last score: %d\n", scores[4]); // 8825 26 // Calculate size27 int size = sizeof(scores) / sizeof(scores[0]);28 printf("Array size: %d\n", size); // 529 30 return 0;31}๐ How This Program Works
int scores[5] = {85, 90, 78, 92, 88} โ Creates an array of 5 integers and fills them with values at once.
int values[5] = {10, 20} โ Only first 2 values given; remaining 3 are automatically set to 0.
int auto_size[] = {1, 2, 3, 4} โ Compiler counts elements and sets size = 4 automatically.
scores[0] accesses the first element (85), scores[4] accesses the last (88).
sizeof(scores) / sizeof(scores[0]) โ Calculates array size: total bytes รท bytes per element = number of elements.
๐ง Memory Layout of 1D Array
When you create int arr[5], the computer allocates 5 ร 4 = 20 bytes of contiguous memory (assuming int is 4 bytes).
Memory Layout: int arr[5] = {10, 20, 30, 40, 50}
arr[0]
arr[1]
arr[2]
arr[3]
arr[4]
1000
1004
1008
1012
1016
Memory addresses (each int = 4 bytes)
Memory Size Calculation
Total memory = number_of_elements ร size_of_each_element
For int arr[5]: 5 ร 4 bytes = 20 bytes
๐ Address Calculation in 1D Arrays
The CPU uses a simple formula to find any element's memory address. This is why arrays allow O(1) constant-time access โ no matter which index you access!
๐ข The Address Formula
Address of arr[i] = Base Address + (i ร size_of_element)
Base Address
Starting memory location of arr[0]
i (Index)
Position of element (0, 1, 2...)
size_of_element
Bytes per element (int=4, char=1)
Example: int arr[5] with Base Address = 1000
| Index (i) | Calculation | Address | Value |
|---|---|---|---|
| 0 | 1000 + (0 ร 4) | 1000 | 10 |
| 1 | 1000 + (1 ร 4) | 1004 | 20 |
| 2 | 1000 + (2 ร 4) | 1008 | 30 |
| 3 | 1000 + (3 ร 4) | 1012 | 40 |
| 4 | 1000 + (4 ร 4) | 1016 | 50 |
๐ This program prints the actual memory address of each array element and shows how the formula calculates them.
1#include <stdio.h>23int main() {4 int arr[5] = {10, 20, 30, 40, 50};5 6 // Base address (address of first element)7 printf("Base Address (arr or &arr[0]): %p\n", (void*)arr);8 9 // Calculate and verify addresses10 for (int i = 0; i < 5; i++) {11 // Manual calculation12 // Address = Base + (i ร sizeof(int))13 printf("arr[%d]: Address = %p, ", i, (void*)&arr[i]);14 printf("Calculated = Base + (%d ร %zu) = %p\n", 15 i, sizeof(int), (void*)(arr + i));16 }17 18 // Pointer arithmetic does this automatically!19 // arr + i is same as &arr[i]20 printf("\narr + 2 = %p (same as &arr[2])\n", (void*)(arr + 2));21 22 return 0;23}๐ก Why This Matters
Because of this formula, accessing arr[0] or arr[999999]takes the same time! The CPU just does one multiplication and one addition โ instant O(1) access.
Looping Through Arrays
๐ This program uses a for loop to print all elements with their addresses, then calculates sum and average.
1#include <stdio.h>23int main() {4 int numbers[5] = {10, 20, 30, 40, 50};5 int size = sizeof(numbers) / sizeof(numbers[0]);6 7 // Base address of array8 printf("Base Address: %p\n\n", (void*)numbers);9 10 // Print all elements with their addresses11 printf("Array elements with addresses:\n");12 printf("-----------------------------------------------\n");13 printf("Index | Value | Address | Address Calculation\n");14 printf("-----------------------------------------------\n");15 for (int i = 0; i < size; i++) {16 printf(" %d | %2d | %p | Base + (%d ร %zu)\n", 17 i, numbers[i], (void*)&numbers[i], i, sizeof(int));18 }19 printf("-----------------------------------------------\n");20 21 // Calculate sum22 int sum = 0;23 for (int i = 0; i < size; i++) {24 sum += numbers[i];25 }26 printf("\nSum: %d\n", sum);27 printf("Average: %.2f\n", (float)sum / size);28 29 return 0;30}$ ./array_loop
Base Address: 0x7ffd5c3e1a00
Array elements with addresses:
-----------------------------------------------
Index | Value | Address | Calculation
-----------------------------------------------
0 | 10 | 0x7ffd5c3e1a00 | Base + (0 ร 4)
1 | 20 | 0x7ffd5c3e1a04 | Base + (1 ร 4)
2 | 30 | 0x7ffd5c3e1a08 | Base + (2 ร 4)
3 | 40 | 0x7ffd5c3e1a0c | Base + (3 ร 4)
4 | 50 | 0x7ffd5c3e1a10 | Base + (4 ร 4)
-----------------------------------------------
Sum: 150
Average: 30.00
๐ How This Loop Works Step-by-Step
sizeof(numbers) / sizeof(numbers[0]) calculates size: 20 bytes รท 4 bytes = 5 elements.
for (int i = 0; i < size; i++) โ Loop runs 5 times: i = 0, 1, 2, 3, 4. Stops when i becomes 5.
numbers[i] โ Each iteration accesses a different element: numbers[0]=10, numbers[1]=20, etc.
sum += numbers[i] โ Adds each element to sum: 0+10+20+30+40+50 = 150.
(float)sum / size โ Casts sum to float for decimal division: 150.0 รท 5 = 30.00.
03Two-Dimensional (2D) Arrays
A 2D array is like a table with rows and columns. Think of it as a grid, spreadsheet, or a matrix.
Real-World Examples of 2D Arrays
Spreadsheet
Rows ร Columns of data
Image Pixels
Width ร Height grid
Chess Board
8 ร 8 squares
Declaration & Initialization
๐ This program shows 3 ways to create 2D arrays and how to access elements using [row][column] notation.
1#include <stdio.h>23int main() {4 // Syntax: dataType name[rows][columns];5 6 // Method 1: Full initialization7 int matrix[3][4] = {8 {1, 2, 3, 4}, // Row 09 {5, 6, 7, 8}, // Row 110 {9, 10, 11, 12} // Row 211 };12 13 // Method 2: Linear initialization (fills row by row)14 int grid[2][3] = {1, 2, 3, 4, 5, 6};15 // Same as: {{1,2,3}, {4,5,6}}16 17 // Method 3: Partial initialization18 int partial[2][3] = {{1, 2}, {4}};19 // Result: {{1,2,0}, {4,0,0}}20 21 // Accessing elements: array[row][column]22 printf("matrix[0][0] = %d\n", matrix[0][0]); // 123 printf("matrix[1][2] = %d\n", matrix[1][2]); // 724 printf("matrix[2][3] = %d\n", matrix[2][3]); // 1225 26 return 0;27}๐ง Memory Layout of 2D Array
Even though we think of 2D arrays as tables, they're stored in memory as one continuous block (row-major order). Row 0 comes first, then Row 1, etc.
int matrix[2][3] โ Logical View vs Memory View
Logical View (How We Think)
| Col 0 | Col 1 | Col 2 | |
|---|---|---|---|
| Row 0 | 1 | 2 | 3 |
| Row 1 | 4 | 5 | 6 |
Memory View (How It's Actually Stored)
[0][0]
[0][1]
[0][2]
[1][0]
[1][1]
[1][2]
Contiguous memory: Row 0 โ Row 1 (row-major order)
2D Array Memory Calculation
Total memory = rows ร columns ร size_of_element
For int matrix[3][4]: 3 ร 4 ร 4 bytes = 48 bytes
๐ Address Calculation in 2D Arrays
For 2D arrays, the formula must account for row-major order โ complete rows are stored one after another. To find any element, we first "skip" complete rows, then move within that row.
๐ข Row-Major Order Formula
Address of arr[i][j] = Base + ((i ร COLS) + j) ร size
Base
Address of arr[0][0]
i ร COLS
Skip i complete rows
+ j
Move j columns in row
ร size
Bytes per element
Example: int matrix[3][4] with Base = 2000
Each row has 4 columns (COLS = 4)
| Element | Formula | Calculation | Address |
|---|---|---|---|
| arr[0][0] | 2000 + ((0ร4)+0)ร4 | 2000 + 0 | 2000 |
| arr[0][2] | 2000 + ((0ร4)+2)ร4 | 2000 + 8 | 2008 |
| arr[1][0] | 2000 + ((1ร4)+0)ร4 | 2000 + 16 | 2016 |
| arr[1][3] | 2000 + ((1ร4)+3)ร4 | 2000 + 28 | 2028 |
| arr[2][1] | 2000 + ((2ร4)+1)ร4 | 2000 + 36 | 2036 |
๐ This program demonstrates how to manually calculate the address of matrix[1][2] using the row-major formula, then verifies it matches the actual address.
1#include <stdio.h>23int main() {4 int matrix[3][4] = {5 {1, 2, 3, 4},6 {5, 6, 7, 8},7 {9, 10, 11, 12}8 };9 10 int rows = 3, cols = 4;11 int *base = &matrix[0][0]; // Base address12 13 printf("Base Address: %p\n\n", (void*)base);14 15 // Calculate address for matrix[1][2]16 int i = 1, j = 2;17 18 // Formula: Base + ((i ร COLS) + j) ร sizeof(element)19 int offset = (i * cols) + j; // Linear position: 1ร4 + 2 = 620 int *calculated_addr = base + offset;21 22 printf("Finding matrix[%d][%d]:\n", i, j);23 printf(" Step 1: Skip %d complete rows = %d ร %d = %d elements\n", 24 i, i, cols, i * cols);25 printf(" Step 2: Move %d columns in current row\n", j);26 printf(" Step 3: Total offset = %d elements = %d bytes\n", 27 offset, offset * (int)sizeof(int));28 printf(" Calculated Address: %p\n", (void*)calculated_addr);29 printf(" Actual Address (&matrix[%d][%d]): %p\n", i, j, (void*)&matrix[i][j]);30 printf(" Value: %d\n", *calculated_addr);31 32 return 0;33}๐ง Think of it Like This
To reach arr[2][1] in a 3ร4 matrix:
Step 1: Skip 2 complete rows = 2 ร 4 = 8 elements
Step 2: Move 1 column into row 2 = 1 element
Total: 8 + 1 = 9 elements from base = 9 ร 4 = 36 bytes
Looping Through 2D Arrays
๐ This program uses nested loops (outer for rows, inner for columns) to print the matrix as a table, show address calculations for each element, and calculate the total sum.
1#include <stdio.h>23int main() {4 int matrix[3][4] = {5 {1, 2, 3, 4},6 {5, 6, 7, 8},7 {9, 10, 11, 12}8 };9 10 int rows = 3;11 int cols = 4;12 int *base = &matrix[0][0];13 14 printf("Base Address: %p\n\n", (void*)base);15 16 // Print as table17 printf("Matrix:\n");18 for (int i = 0; i < rows; i++) {19 for (int j = 0; j < cols; j++) {20 printf("%3d ", matrix[i][j]);21 }22 printf("\n");23 }24 25 // Show address calculation for each element26 printf("\nAddress Calculation (Row-Major Order):\n");27 printf("----------------------------------------------------------\n");28 printf("Element | Value | Offset Calculation | Address\n");29 printf("----------------------------------------------------------\n");30 for (int i = 0; i < rows; i++) {31 for (int j = 0; j < cols; j++) {32 int offset = (i * cols) + j;33 printf("matrix[%d][%d] | %2d | (%dร%d)+%d = %2d elements | %p\n",34 i, j, matrix[i][j], i, cols, j, offset, (void*)&matrix[i][j]);35 }36 }37 printf("----------------------------------------------------------\n");38 39 // Calculate sum40 int sum = 0;41 for (int i = 0; i < rows; i++) {42 for (int j = 0; j < cols; j++) {43 sum += matrix[i][j];44 }45 }46 printf("\nSum of all elements: %d\n", sum);47 48 return 0;49}$ ./2d_array_loop
Base Address: 0x7ffd5c3e1a20
Matrix:
1 2 3 4
5 6 7 8
9 10 11 12
Address Calculation (Row-Major Order):
----------------------------------------------------------
Element | Value | Offset Calculation | Address
----------------------------------------------------------
matrix[0][0] | 1 | (0ร4)+0 = 0 elements | 0x7ffd...1a20
matrix[0][1] | 2 | (0ร4)+1 = 1 elements | 0x7ffd...1a24
matrix[0][2] | 3 | (0ร4)+2 = 2 elements | 0x7ffd...1a28
matrix[1][0] | 5 | (1ร4)+0 = 4 elements | 0x7ffd...1a30
matrix[1][2] | 7 | (1ร4)+2 = 6 elements | 0x7ffd...1a38
...
----------------------------------------------------------
Sum of all elements: 78
04Three-Dimensional (3D) Arrays
A 3D array adds another dimension โ think of it as multiple 2D tables stacked together. It has layers, rows, and columns.
Real-World Examples of 3D Arrays
Multiple Spreadsheets
Sheets ร Rows ร Columns
Video Frames
Frames ร Height ร Width
Building Floors
Floors ร Rows ร Rooms
Declaration & Initialization
๐ This program creates a 3D array (2 layers ร 3 rows ร 4 columns) and shows how to access elements using [layer][row][column] notation.
1#include <stdio.h>23int main() {4 // Syntax: dataType name[layers][rows][columns];5 6 // 3D Array: 2 layers, each with 3 rows and 4 columns7 int cube[2][3][4] = {8 // Layer 0 (first 2D table)9 {10 {1, 2, 3, 4},11 {5, 6, 7, 8},12 {9, 10, 11, 12}13 },14 // Layer 1 (second 2D table)15 {16 {13, 14, 15, 16},17 {17, 18, 19, 20},18 {21, 22, 23, 24}19 }20 };21 22 // Accessing elements: array[layer][row][column]23 printf("cube[0][0][0] = %d\n", cube[0][0][0]); // 124 printf("cube[0][2][3] = %d\n", cube[0][2][3]); // 1225 printf("cube[1][1][2] = %d\n", cube[1][1][2]); // 1926 27 return 0;28}๐ง Memory Layout of 3D Array
3D arrays are also stored in contiguous memory. Layer 0 comes first (all its rows), then Layer 1, and so on.
int cube[2][2][3] โ Visualization
Layer 0 (cube[0])
| 1 | 2 | 3 |
| 4 | 5 | 6 |
Layer 1 (cube[1])
| 7 | 8 | 9 |
| 10 | 11 | 12 |
In memory: [1,2,3,4,5,6] โ [7,8,9,10,11,12] (Layer 0 โ Layer 1)
3D Array Memory Calculation
Total memory = layers ร rows ร columns ร size_of_element
For int cube[2][3][4]: 2 ร 3 ร 4 ร 4 bytes = 96 bytes
๐ Address Calculation in 3D Arrays
For 3D arrays, we extend the formula: first skip complete layers, then skip rows within that layer, then move within the row.
๐ข 3D Array Address Formula
Address of arr[i][j][k] = Base + [(i ร ROWS ร COLS) + (j ร COLS) + k] ร size
i ร ROWS ร COLS
Skip i complete layers
j ร COLS
Skip j rows in layer
k
Column offset in row
ร size
Bytes per element
Example: int cube[2][3][4] with Base = 3000
2 layers ร 3 rows ร 4 columns
| Element | Calculation | Offset | Address |
|---|---|---|---|
| cube[0][0][0] | (0ร3ร4)+(0ร4)+0 = 0 | 0 ร 4 = 0 | 3000 |
| cube[0][1][2] | (0ร3ร4)+(1ร4)+2 = 6 | 6 ร 4 = 24 | 3024 |
| cube[1][0][0] | (1ร3ร4)+(0ร4)+0 = 12 | 12 ร 4 = 48 | 3048 |
| cube[1][2][3] | (1ร3ร4)+(2ร4)+3 = 23 | 23 ร 4 = 92 | 3092 |
๐ This program finds the address of cube[1][2][3] by calculating: skip 1 layer + skip 2 rows + move 3 columns, then verifies the result.
1#include <stdio.h>23int main() {4 int cube[2][3][4] = {5 {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}},6 {{13,14,15,16}, {17,18,19,20}, {21,22,23,24}}7 };8 9 int layers = 2, rows = 3, cols = 4;10 int *base = &cube[0][0][0];11 12 printf("Base Address: %p\n\n", (void*)base);13 14 // Calculate address for cube[1][2][3]15 int i = 1, j = 2, k = 3;16 17 // Formula: Base + (iรROWSรCOLS + jรCOLS + k) ร size18 int offset = (i * rows * cols) + (j * cols) + k;19 int *calculated = base + offset;20 21 printf("Finding cube[%d][%d][%d]:\n", i, j, k);22 printf(" Skip %d layers: %d ร %d ร %d = %d elements\n", 23 i, i, rows, cols, i * rows * cols);24 printf(" Skip %d rows: %d ร %d = %d elements\n", 25 j, j, cols, j * cols);26 printf(" Column offset: %d elements\n", k);27 printf(" Total: %d + %d + %d = %d elements = %d bytes\n",28 i * rows * cols, j * cols, k, offset, offset * 4);29 printf(" Address: %p, Value: %d\n", (void*)calculated, *calculated);30 31 return 0;32}Looping Through 3D Arrays
๐ This program uses 3 nested loops (layers โ rows โ columns) to print each layer as a separate table and calculate the total sum of all 24 elements.
1#include <stdio.h>23int main() {4 int cube[2][3][4] = {5 {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}},6 {{13,14,15,16}, {17,18,19,20}, {21,22,23,24}}7 };8 9 int layers = 2, rows = 3, cols = 4;10 11 // Print all layers12 for (int l = 0; l < layers; l++) {13 printf("=== Layer %d ===\n", l);14 for (int r = 0; r < rows; r++) {15 for (int c = 0; c < cols; c++) {16 printf("%3d ", cube[l][r][c]);17 }18 printf("\n");19 }20 printf("\n");21 }22 23 // Calculate total sum24 int sum = 0;25 for (int l = 0; l < layers; l++) {26 for (int r = 0; r < rows; r++) {27 for (int c = 0; c < cols; c++) {28 sum += cube[l][r][c];29 }30 }31 }32 printf("Total sum: %d\n", sum); // 30033 34 return 0;35}05Array Memory Size Summary
| Array Type | Declaration | Elements | Memory (int=4 bytes) |
|---|---|---|---|
| 1D | int arr[5] | 5 | 5 ร 4 = 20 bytes |
| 2D | int arr[3][4] | 3 ร 4 = 12 | 12 ร 4 = 48 bytes |
| 3D | int arr[2][3][4] | 2 ร 3 ร 4 = 24 | 24 ร 4 = 96 bytes |
๐ This simple program uses sizeof() to print the actual memory size of 1D, 2D, and 3D arrays. Run it to verify the calculations!
1#include <stdio.h>23int main() {4 int arr1D[5];5 int arr2D[3][4];6 int arr3D[2][3][4];7 8 printf("Size of int: %zu bytes\n", sizeof(int));9 printf("1D array [5]: %zu bytes\n", sizeof(arr1D));10 printf("2D array [3][4]: %zu bytes\n", sizeof(arr2D));11 printf("3D array [2][3][4]: %zu bytes\n", sizeof(arr3D));12 13 return 0;14}06Common Mistakes
โ Array Index Out of Bounds
int arr[5] = {1, 2, 3, 4, 5};printf("%d", arr[5]); // ERROR! Valid indices are 0-4printf("%d", arr[-1]); // ERROR! No negative indicesC doesn't check array bounds! Accessing invalid indices causes undefined behavior.
โ Forgetting Array Indices Start at 0
int scores[5] = {85, 90, 78, 92, 88};// First element is scores[0], NOT scores[1]// Last element is scores[4], NOT scores[5]โ Using sizeof() Wrong in Functions
void printArray(int arr[]) { // sizeof(arr) returns pointer size, NOT array size! int size = sizeof(arr) / sizeof(arr[0]); // WRONG!}// Solution: Pass size as a parameter07Summary
What You Learned:
- โ1D Arrays: Single row of elements, accessed with arr[i]
- โ2D Arrays: Table with rows/columns, accessed with arr[row][col]
- โ3D Arrays: Stacked tables, accessed with arr[layer][row][col]
- โMemory: Arrays are stored in contiguous memory (row-major order)
- โIndex: Always starts at 0, last element is at size-1
08Next Steps
Continue learning about other derived data types: