Skip to content

C Arrays — Declaration, Initialization, and Multi-Dimensional Arrays

DodaTech Updated 2026-06-28 9 min read

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

  1. What is the index of the first element in a C array? 0. Arrays are zero-indexed in C.

  2. 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.

  3. 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.

  4. How are 2D arrays stored in memory? In row-major order: all elements of row 0 first, then row 1, and so on.

  5. 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

Why do C arrays not have bounds checking?

Performance. Bounds checking every array access would slow programs significantly. C trusts the programmer to stay within bounds.

Can I change the size of an array after declaration?

No. Array sizes are fixed at declaration time. Use dynamic memory (malloc, realloc) for resizable arrays.

What is the difference between int arr[] and int *arr?

int arr[] in a declaration allocates storage. As a function parameter, int arr[] is identical to int *arr.

How do I pass a 2D array to a function?

You must specify all dimensions except the first: void func(int arr[][4], int rows) or void func(int rows, int cols, int arr[rows][cols]) with VLAs.

Can I initialize a char array with a string?

Yes: char name[] = 'Alice'; creates a 6-element array (including null terminator). This is covered in the strings lesson.

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.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro

Home Browse C