C Arrays — Declaration, Initialization, and Multi-Dimensional Arrays
In this tutorial, you will learn about C Arrays. We cover key concepts, practical examples, and best practices to help you master this topic.
C arrays are contiguous memory blocks that store multiple values of the same type, accessed by index. Arrays provide efficient random access and form the foundation for strings, matrices, and buffers.
Why It Matters
Arrays are the most fundamental data structure in C. Every collection of data -- whether it is a string of characters, a buffer of bytes, or a matrix of numbers -- is stored as an array. Understanding how arrays work in memory directly affects your ability to write correct and efficient code. Unlike higher-level languages, C arrays have no bounds checking, giving you full control and full responsibility.
Real-World Use
Image processing represents pictures as two-dimensional arrays of pixels. Audio processing uses arrays of samples. Network protocols read data into byte arrays. Durga Antivirus Pro reads file content into byte arrays for signature scanning. The Linux kernel uses arrays for Process tables, file descriptors, and buffer caches.
What You Will Learn
- Declaring and initializing one-dimensional arrays
- Accessing array elements with index notation
- Understanding array memory layout
- Working with multi-dimensional arrays
- Common array operations and algorithms
- Array size calculation with sizeof
Learning Path
flowchart LR A[Loops] --> B[Arrays
You are here] B --> C[Strings] C --> D[Pointers] D --> E[Pointer Arithmetic] style B fill:#f90,color:#fff
Declaring and Initializing Arrays
#include <stdio.h>
int main() {
// Declare an array of 5 integers
int numbers[5];
// Initialize individual elements
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
numbers[3] = 40;
numbers[4] = 50;
// Initialize at declaration
int values[5] = {1, 2, 3, 4, 5};
// Partial initialization: remaining elements are 0
int partial[5] = {1, 2}; // {1, 2, 0, 0, 0}
// Size inferred from initializer
int inferred[] = {10, 20, 30}; // size = 3
// Initialize all to zero
int zeros[100] = {0};
printf("First: %d, Last: %d\n", inferred[0], inferred[2]);
// First: 10, Last: 30
return 0;
}
Expected output: First: 10, Last: 30
Accessing Array Elements
Array indices start at 0 and go to size-1. Accessing outside this range is undefined behavior:
#include <stdio.h>
int main() {
int scores[] = {85, 90, 78, 92, 88};
int count = sizeof(scores) / sizeof(scores[0]);
printf("Array size: %zu elements\n", count);
// Loop through array
printf("Scores: ");
for (int i = 0; i < count; i++) {
printf("%d ", scores[i]);
}
printf("\n");
// Calculate average
int sum = 0;
for (int i = 0; i < count; i++) {
sum += scores[i];
}
printf("Average: %.1f\n", (double)sum / count);
// Find maximum
int max = scores[0];
for (int i = 1; i < count; i++) {
if (scores[i] > max) {
max = scores[i];
}
}
printf("Maximum: %d\n", max);
return 0;
}
Expected output:
Array size: 5 elements
Scores: 85 90 78 92 88
Average: 86.6
Maximum: 92
Array Memory Layout
Arrays store elements consecutively in memory. Each element is sizeof(type) bytes apart:
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
printf("Array address: %p\n", arr);
printf("Size of array: %zu bytes\n", sizeof(arr));
printf("Size of element: %zu bytes\n", sizeof(arr[0]));
printf("Number of elements: %zu\n", sizeof(arr) / sizeof(arr[0]));
// Print addresses of each element
for (int i = 0; i < 5; i++) {
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
Expected output (addresses will vary):
Array address: 0x7fff12345670
Size of array: 20 bytes
Size of element: 4 bytes
Number of elements: 5
&arr[0] = 0x7fff12345670
&arr[1] = 0x7fff12345674
&arr[2] = 0x7fff12345678
&arr[3] = 0x7fff1234567c
&arr[4] = 0x7fff12345680
Each element is 4 bytes apart (the size of int on this system). The array itself occupies 20 contiguous bytes.
Multi-Dimensional Arrays
C supports arrays with multiple dimensions:
#include <stdio.h>
int main() {
// 2D array: 3 rows, 4 columns
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// Access element at row 1, column 2
printf("matrix[1][2] = %d\n", matrix[1][2]); // 7
// Nested loops to print matrix
printf("Matrix:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("%3d ", matrix[i][j]);
}
printf("\n");
}
// 3D 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}
}
};
printf("cube[1][2][3] = %d\n", cube[1][2][3]); // 24
return 0;
}
Expected output:
matrix[1][2] = 7
Matrix:
1 2 3 4
5 6 7 8
9 10 11 12
cube[1][2][3] = 24
Memory Layout of 2D Arrays
Two-dimensional arrays are stored in row-major order: all elements of row 0 come first, then row 1, and so on:
#include <stdio.h>
int main() {
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
// Actually stored as: 1, 2, 3, 4, 5, 6 in memory
int *ptr = &matrix[0][0];
for (int i = 0; i < 6; i++) {
printf("%d ", ptr[i]);
}
printf("\n");
// Output: 1 2 3 4 5 6
return 0;
}
Variable-Length Arrays (VLAs)
C99 introduced variable-length arrays whose size is determined at runtime:
#include <stdio.h>
int main() {
int n;
printf("Enter array size: ");
scanf("%d", &n);
// VLA -- size determined at runtime
int vla[n];
for (int i = 0; i < n; i++) {
vla[i] = i * i;
}
printf("VLA elements: ");
for (int i = 0; i < n; i++) {
printf("%d ", vla[i]);
}
printf("\n");
return 0;
}
VLAs are allocated on the stack, so large sizes cause stack overflow. They are optional in C11 and not supported in C++ or MSVC.
Array Initialization Techniques
#include <stdio.h>
int main() {
// Designated initializers (C99+)
int arr[10] = {[0] = 10, [5] = 20, [9] = 30};
// Result: {10, 0, 0, 0, 0, 20, 0, 0, 0, 30}
// Initialize range
int range[10] = {[0 ... 4] = 1, [5 ... 9] = 2};
// Result: {1, 1, 1, 1, 1, 2, 2, 2, 2, 2}
// Copy array (must use loop, not assignment)
int source[5] = {1, 2, 3, 4, 5};
int dest[5];
for (int i = 0; i < 5; i++) {
dest[i] = source[i];
}
// Or use memcpy from string.h
// memcpy(dest, source, sizeof(source));
for (int i = 0; i < 5; i++) {
printf("%d ", dest[i]);
}
printf("\n");
// Output: 1 2 3 4 5
return 0;
}
Arrays as Function Parameters
When you pass an array to a function, it decays to a pointer:
#include <stdio.h>
// Array parameter decays to pointer
int sum_array(int arr[], int size) {
int total = 0;
for (int i = 0; i < size; i++) {
total += arr[i];
}
return total;
}
// Equivalent pointer notation
int sum_ptr(int *arr, int size) {
int total = 0;
for (int i = 0; i < size; i++) {
total += *(arr + i);
}
return total;
}
int main() {
int numbers[] = {10, 20, 30, 40, 50};
int size = sizeof(numbers) / sizeof(numbers[0]);
printf("Sum: %d\n", sum_array(numbers, size));
printf("Sum: %d\n", sum_ptr(numbers, size));
// sizeof inside the function does NOT work!
// Because arr is a pointer, sizeof(arr) = 8 not 20
// Always pass the size separately
return 0;
}
Expected output:
Sum: 150
Sum: 150
Common Mistakes
1. Off-by-One Index Errors
int arr[5] = {0, 1, 2, 3, 4};
arr[5] = 10; // Buffer overflow! Valid indices are 0-4
Always remember: indices go from 0 to size-1.
2. Not Passing Array Size to Functions
void process(int arr[]) {
// sizeof(arr) is sizeof(int*), not the array size!
}
Always pass the size separately. Arrays decay to pointers in function parameters.
3. Confusing Array Declaration with Pointer
int *ptr; // Pointer, not an array
int arr[5]; // Array of 5 ints
Pointers and arrays are different. An array is a contiguous block; a pointer holds an address.
4. Returning Local Arrays from Functions
int *get_array() {
int arr[5] = {1, 2, 3, 4, 5};
return arr; // ERROR: arr is local, destroyed after return
}
Use dynamic memory allocation (malloc) for arrays that outlive the function.
5. Using Large VLAs on the Stack
int n = 10000000;
int vla[n]; // Stack overflow for large sizes
VLAs use stack memory. For large arrays, use malloc instead.
Practice Questions
What is the index of the first element in a C array? 0. Arrays are zero-indexed in C.
How do you calculate the number of elements in an array?
sizeof(arr) / sizeof(arr[0])-- but only works where the array is declared, not in function parameters.What is array decay? When an array is passed to a function, it decays to a pointer to its first element. The size information is lost.
How are 2D arrays stored in memory? In row-major order: all elements of row 0 first, then row 1, and so on.
Challenge: Write a program that transposes a 3x3 matrix (rows become columns and vice versa).
Mini Project: Matrix Operations
#include <stdio.h>
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("%3d ", matrix[i][j]);
}
printf("\n");
}
}
int main() {
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
int b[2][3] = {{7, 8, 9}, {10, 11, 12}};
int sum[2][3];
int product[2][3] = {0};
// Add matrices
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
sum[i][j] = a[i][j] + b[i][j];
}
}
printf("Matrix A + B:\n");
print_matrix(2, 3, sum);
return 0;
}
FAQ
What is Next
Now that you understand arrays, proceed to Strings in C to learn about character arrays, the null terminator, and C string library functions.