Call By Reference And Call By Value In C

7 min read

Call by reference and call by value in C are two fundamental ways that functions receive data from the main program or from other functions. Consider this: understanding these concepts is essential for writing correct, efficient, and maintainable C code, because the choice between passing a value and passing a pointer can determine whether a function can modify the original data or only work with a copy. In C, most data is passed by value, but pointers allow programmers to simulate call by reference by passing the memory address of a variable. This article explains how both mechanisms work, shows practical examples, and highlights common mistakes that beginners often make.

This is the bit that actually matters in practice.

Introduction

In C, a function can accept parameters, and those parameters can behave in two very different ways. Any changes made inside the function do not affect the original variable in the calling code. When a function receives a call by value, it receives a copy of the original data. When a function receives data through a pointer, often described as call by reference in C, it receives the memory address of the original variable. This allows the function to access and modify the original data directly Simple, but easy to overlook..

The distinction matters because it affects program behavior, performance, and readability. For small data types such as integers, characters, or floating-point numbers, call by value is usually simple and safe. For larger structures, arrays, or cases where a function must update the caller’s data, passing pointers is often more practical.

What Is Call by Value?

Call by value means that the function receives a copy of the argument. In real terms, the original variable remains unchanged unless the function explicitly returns a new value. This is the default behavior for most primitive data types in C Less friction, more output..

Here's one way to look at it: if an integer variable is passed to a function, the function receives a new local variable with the same value. Changing that local variable inside the function does not change the variable in the caller.

Simple Call by Value Example

#include 

void increment(int number) {
    number = number + 1;
}

int main() {
    int value = 10;
    increment(value);
    printf("value = %d\n", value);
    return 0;
}

In this example, the function increment receives a copy of value. Inside the function, number is changed from 10 to 11, but the original value in main remains 10. The output is:

value = 10

This happens because number is a separate local variable. It exists only inside the function and is destroyed when the function returns That alone is useful..

What Is Call by Reference in C?

In C, there is no direct language feature called “call by reference” in the same way that some other languages have it. Instead, C uses pointers to achieve a similar effect. A pointer stores the memory address of another variable. When a function receives a pointer, it can access the variable located at that address That's the part that actually makes a difference..

This means the function can read or modify the original variable, not just a copy.

Pointer Example

#include 

void increment(int *number) {
    *number = *number + 1;
}

int main() {
    int value = 10;
    increment(&value);
    printf("value = %d\n", value);
    return 0;
}

In this version, the function receives an int *, which is a pointer to an integer. Practically speaking, the address-of operator & passes the address of value to the function. Inside the function, the dereference operator * accesses the value stored at that address.

The output is:

value = 11

Here, the original variable is changed because the function works with the memory location of value, not a copy of it Easy to understand, harder to ignore..

How Memory Changes During Function Calls

When a function is called, C creates local variables for its parameters. In call by value, these parameters are initialized with copies of the arguments. In pointer-based call by reference, the parameters are initialized with copies of the addresses, but the addresses point to the original data.

This distinction is important:

  • Call by value copies the data itself.
  • Pointer-based call by reference copies the address, but the address refers to the original data.

For example:

void changeByValue(int x) {
    x = 100;
}

void changeByPointer(int *x) {
    *x = 100;
}

If x is a local integer in main, calling changeByValue(x) changes only the local parameter. Calling changeByPointer(&x) changes the original variable Small thing, real impact..

Passing Arrays and Strings

Arrays in C are often passed to functions using pointers. When an array name is used as a function argument, it typically decays to a pointer to its first element. This means the function receives the address of the array, not a full copy of the array.

It sounds simple, but the gap is usually here Most people skip this — try not to..

For example:

void printArray(int arr[], int size) {
    for (int i = 

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

int main() {
    int numbers[] = {4, 7, 2, 9};
    int len = sizeof(numbers) / sizeof(numbers[0]);
    printArray(numbers, len);
    return 0;
}

When numbers is passed to printArray, the array name decays to a pointer to its first element (&numbers[0]). The function receives this pointer, treats it as int arr[], and can read or modify the original elements. If we wanted to change the array inside the function, we could write:

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

Calling doubleArray(numbers, len); would leave numbers containing {8, 14, 4, 18} after the call, demonstrating that the function operates on the original storage And that's really what it comes down to..

Passing Strings (Character Arrays)

In C, strings are null‑terminated arrays of char. Because an array name also decays to a pointer, a common idiom for string‑processing functions is to accept a char * (or char[]) parameter:

#include 

void toUpper(char *str) {
    while (*str) {
        if (*str >= 'a' && *str <= 'z')
            *str = *str - ('a' - 'A');
        str++;               // advance the pointer
    }
}

int main() {
    char greeting[] = "Hello, World!";
    toUpper(greeting);
    printf("%s\n", greeting);   // HELLO, WORLD!
    return 0;
}

Here toUpper receives the address of the first character of greeting. By dereferencing and incrementing the pointer, it walks through the string, converting each lowercase letter to uppercase in place. The original array is modified because the function works with the actual memory that holds the characters.

Const Correctness and Safety

If a function only needs to read the data without altering it, declaring the pointer parameter as const communicates intent and prevents accidental modification:

int stringLength(const char *s) {
    int len = 0;
    while (s[len] != '\0')
        len++;
    return len;
}

Now stringLength can safely accept both mutable arrays and string literals (e.g., stringLength("test");) because it promises not to write through the pointer Easy to understand, harder to ignore..

Multidimensional Arrays

When dealing with arrays of more than one dimension, only the first dimension decays to a pointer; the remaining dimensions must be known at compile time:

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

In this case, mat is adjusted by the compiler to a pointer to an array of cols integers, allowing the function to index into the original matrix without copying its contents Surprisingly effective..

Conclusion

C does not possess a built‑in “call by reference” mechanism, but the language’s pointer semantics give programmers precise control over whether a function works on a copy of a value or on the original object itself. Now, understanding the distinction between copying values and copying addresses is essential for writing correct, efficient C code—especially when manipulating arrays, strings, or more complex data structures. Practically speaking, by passing the address of a variable (&var) or relying on the automatic decay of array names to pointers, we enable functions to read and modify data stored in the caller’s scope. Proper use of const qualifiers further clarifies intent and helps prevent unintended side effects, making pointer‑based interfaces both powerful and safe.

Fresh Stories

Freshly Published

Parallel Topics

Related Reading

Thank you for reading about Call By Reference And Call By Value In C. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home