Docs

README

Passing Arrays to Functions in C

Table of Contents

  1. •Introduction
  2. •How Arrays are Passed
  3. •Passing 1D Arrays
  4. •Passing 2D Arrays
  5. •Passing Arrays by Reference
  6. •Array Size in Functions
  7. •Returning Arrays from Functions
  8. •Common Patterns
  9. •Best Practices
  10. •Summary

Introduction

Passing arrays to functions is essential for writing modular and reusable code. Understanding how C handles array parameters is crucial because arrays behave differently than regular variables when passed to functions.


How Arrays are Passed

Key Concept: Arrays Decay to Pointers

When you pass an array to a function, C does NOT copy the entire array. Instead, it passes the address of the first element (the array "decays" to a pointer).

int arr[5] = {1, 2, 3, 4, 5};
func(arr);

What happens:
ā”Œā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”
│ 1 │ 2 │ 3 │ 4 │ 5 │  ← Original array in memory
ā””ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”˜
  ↑
  │
  └── Address passed to function (pointer to first element)

Implications

AspectRegular VariablesArrays
Passed byValue (copy)Reference (address)
Changes in functionDon't affect originalAffect original
Memory overheadCopy of dataOnly address (8 bytes)
Size info preservedYesNo (decays to pointer)

Passing 1D Arrays

Method 1: Array Notation

void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main(void) {
    int numbers[5] = {10, 20, 30, 40, 50};
    printArray(numbers, 5);
    return 0;
}

Method 2: Pointer Notation

void printArray(int *arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);  // or *(arr + i)
    }
    printf("\n");
}

Method 3: Sized Array (Size Ignored)

void printArray(int arr[100], int size) {
    // The [100] is ignored by compiler!
    // It's treated as int *arr
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
}

All Three Are Equivalent

void func(int arr[]);    // Array notation
void func(int *arr);     // Pointer notation
void func(int arr[100]); // Sized (size ignored)

// All three declare the same function!

Passing 2D Arrays

Important Rule

For 2D arrays, all dimensions except the first must be specified.

int matrix[3][4];

To pass: func(matrix, 3);

Function must know column count to calculate:
Address of [i][j] = Base + (i Ɨ COLS + j) Ɨ sizeof(int)
                          ↑
                    Must know COLS!

Method 1: Full Dimensions

void printMatrix(int arr[3][4]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

Method 2: Omit First Dimension

void printMatrix(int arr[][4], int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

Method 3: Pointer to Array

void printMatrix(int (*arr)[4], int rows) {
    // arr is pointer to array of 4 ints
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

Method 4: Variable Length Arrays (C99+)

void printMatrix(int rows, int cols, int arr[rows][cols]) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

// Usage
int matrix[3][4] = {...};
printMatrix(3, 4, matrix);

Visual Comparison

Declaration              Meaning
───────────────────────────────────────────────────
int arr[]               Pointer to int
int arr[10]             Pointer to int (10 ignored)
int arr[][4]            Pointer to array of 4 ints
int arr[3][4]           Pointer to array of 4 ints
int (*arr)[4]           Pointer to array of 4 ints

Passing Arrays by Reference

Since arrays decay to pointers, modifications in the function affect the original array.

Modifying Array Elements

void doubleElements(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        arr[i] *= 2;  // Modifies original!
    }
}

int main(void) {
    int numbers[5] = {1, 2, 3, 4, 5};

    printf("Before: ");
    for (int i = 0; i < 5; i++) printf("%d ", numbers[i]);

    doubleElements(numbers, 5);

    printf("\nAfter:  ");
    for (int i = 0; i < 5; i++) printf("%d ", numbers[i]);
    // Output: 2 4 6 8 10

    return 0;
}

Preventing Modification with const

void printArray(const int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
        // arr[i] = 10;  // ERROR! Cannot modify const
    }
}

Why Use const?

1. Documents intent - "this function only reads"
2. Prevents accidental modification
3. Allows compiler optimizations
4. Can pass const arrays to the function

Array Size in Functions

The Problem

When an array decays to a pointer, size information is lost.

void func(int arr[]) {
    // sizeof(arr) gives pointer size (8 bytes), NOT array size!
    int size = sizeof(arr);  // WRONG! This is pointer size
}

The Solution: Pass Size Separately

void processArray(int arr[], int size) {
    // Use the size parameter
    for (int i = 0; i < size; i++) {
        // process arr[i]
    }
}

int main(void) {
    int data[100];
    int size = sizeof(data) / sizeof(data[0]);  // Calculate here
    processArray(data, size);
    return 0;
}

Common Pattern: Size Calculation

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))

int main(void) {
    int numbers[] = {1, 2, 3, 4, 5};
    processArray(numbers, ARRAY_SIZE(numbers));
    return 0;
}

Returning Arrays from Functions

You Cannot Directly Return Arrays

// WRONG! Cannot return array
int[] getArray(void) {
    int arr[5] = {1, 2, 3, 4, 5};
    return arr;  // Error!
}

Method 1: Modify Passed Array

void fillArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        arr[i] = i + 1;
    }
}

int main(void) {
    int result[5];
    fillArray(result, 5);  // result is filled
    return 0;
}

Method 2: Use Static Array (Not Recommended)

int* getArray(void) {
    static int arr[5] = {1, 2, 3, 4, 5};
    return arr;  // OK because static persists
}
// Warning: Same array returned every call!

Method 3: Dynamic Allocation (Advanced)

int* createArray(int size) {
    int *arr = malloc(size * sizeof(int));
    for (int i = 0; i < size; i++) {
        arr[i] = i + 1;
    }
    return arr;
}

int main(void) {
    int *arr = createArray(5);
    // Use arr...
    free(arr);  // Don't forget!
    return 0;
}

Method 4: Return Through Struct

#define MAX_SIZE 100

typedef struct {
    int data[MAX_SIZE];
    int size;
} IntArray;

IntArray createArray(int n) {
    IntArray result = {.size = n};
    for (int i = 0; i < n; i++) {
        result.data[i] = i + 1;
    }
    return result;
}

Common Patterns

Pattern 1: Search Function

int findElement(const int arr[], int size, int target) {
    for (int i = 0; i < size; i++) {
        if (arr[i] == target) {
            return i;  // Found at index i
        }
    }
    return -1;  // Not found
}

Pattern 2: Aggregation Functions

int sum(const int arr[], int size) {
    int total = 0;
    for (int i = 0; i < size; i++) {
        total += arr[i];
    }
    return total;
}

double average(const int arr[], int size) {
    if (size == 0) return 0.0;
    return (double)sum(arr, size) / size;
}

int max(const int arr[], int size) {
    int maxVal = arr[0];
    for (int i = 1; i < size; i++) {
        if (arr[i] > maxVal) {
            maxVal = arr[i];
        }
    }
    return maxVal;
}

Pattern 3: Transformation Function

void transform(int arr[], int size, int (*operation)(int)) {
    for (int i = 0; i < size; i++) {
        arr[i] = operation(arr[i]);
    }
}

int square(int x) { return x * x; }
int doubleIt(int x) { return x * 2; }

// Usage
transform(numbers, 5, square);

Pattern 4: Filter/Copy Pattern

int filterPositive(const int src[], int srcSize, int dest[]) {
    int count = 0;
    for (int i = 0; i < srcSize; i++) {
        if (src[i] > 0) {
            dest[count++] = src[i];
        }
    }
    return count;  // Return new size
}

Pattern 5: Swap Function for Sorting

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

void bubbleSort(int arr[], int size) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = 0; j < size - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(&arr[j], &arr[j + 1]);
            }
        }
    }
}

Best Practices

1. Always Pass Size

// GOOD
void process(int arr[], int size);

// BAD - How many elements?
void process(int arr[]);

2. Use const for Read-Only

// Document that array won't be modified
int sum(const int arr[], int size);
void print(const int arr[], int size);

3. Use Meaningful Parameter Names

// GOOD
void copyArray(const int source[], int dest[], int count);

// BAD
void copyArray(const int a[], int b[], int n);

4. Validate Parameters

int sum(const int arr[], int size) {
    if (arr == NULL || size <= 0) {
        return 0;
    }
    // ... rest of function
}

5. Use Macros for Size Calculation

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))

int arr[] = {1, 2, 3, 4, 5};
process(arr, ARRAY_SIZE(arr));

6. Document Array Ownership

// Caller owns the array - function just reads
void analyze(const int data[], int size);

// Function modifies caller's array
void sort(int data[], int size);

// Function allocates - caller must free
int* createCopy(const int src[], int size);

Summary

Quick Reference

Array TypeFunction ParameterNotes
1D int arr[]int arr[] or int *arrPass size separately
2D int arr[][N]int arr[][N] or int (*arr)[N]Columns must be specified
Constconst int arr[]Prevents modification

Key Points

āœ“ Arrays decay to pointers when passed to functions
āœ“ Modifications affect the original array
āœ“ Size information is lost - always pass size
āœ“ Use const for read-only parameters
āœ“ Cannot return local arrays directly
āœ“ For 2D arrays, specify all dimensions except first

Function Declaration Equivalents

// These are ALL equivalent for 1D:
void f(int arr[]);
void f(int arr[100]);
void f(int *arr);

// These are ALL equivalent for 2D with 4 columns:
void f(int arr[][4]);
void f(int arr[3][4]);
void f(int (*arr)[4]);

Next Steps

After mastering passing arrays to functions:

  1. •Study Arrays and Pointers relationship in depth
  2. •Learn about Character Arrays (strings)
  3. •Explore Dynamic Memory Allocation for flexible arrays

"Pass the address, not the data - that's how C handles arrays."

README - C Programming Tutorial | DeepML