Call by Value and Call by Reference

C Programming | BTech First Semester
Dr. Mohsin Dar | Assistant Professor | Cloud & Software Operations Cluster | SOCS | UPES
Lecture 14 | Unit III: Array and Function
Duration: 50 minutes

Learning Objectives

By the end of this lecture, students will be able to:

1. Introduction to Parameter Passing

In C programming, when we call a function and pass arguments to it, there are different ways these arguments can be passed. The two primary methods are:

Parameter Passing Methods:

  • Call by Value: A copy of the actual argument is passed to the function
  • Call by Reference: The address (reference) of the actual argument is passed to the function

Understanding these concepts is crucial for effective memory management and achieving desired program behavior.

2. Call by Value

2.1 Definition and Concept

In call by value, a copy of the actual parameter's value is passed to the function. The function works with this copy, and any changes made to the parameter inside the function do not affect the original variable.

Memory Representation - Call by Value

main()
x = 10
function()
copy = 10

Changes to 'copy' don't affect 'x'

2.2 Example: Simple Call by Value

#include <stdio.h>

// Function that receives value by copy
void increment(int num) {
    num = num + 1;  // This only changes the local copy
    printf("Inside function: num = %d\n", num);
}

int main() {
    int x = 10;
    
    printf("Before function call: x = %d\n", x);
    increment(x);  // Pass value of x
    printf("After function call: x = %d\n", x);
    
    return 0;
}
                
Output:
Before function call: x = 10
Inside function: num = 11
After function call: x = 10

Key Observation:

Notice that the value of 'x' in main() remains unchanged (10) even though 'num' was incremented inside the function. This demonstrates that the function worked with a copy of the original value.

2.3 Characteristics of Call by Value

3. Call by Reference

3.1 Definition and Concept

In call by reference, the address of the actual parameter is passed to the function. The function receives a pointer to the original variable, allowing it to directly modify the original value.

Memory Representation - Call by Reference

main()
x = 10
Address: 1000
function()
*ptr → 1000

Changes through 'ptr' directly affect 'x'

3.2 Example: Call by Reference using Pointers

#include <stdio.h>

// Function that receives address (reference)
void increment(int *num) {
    *num = *num + 1;  // This changes the original value
    printf("Inside function: *num = %d\n", *num);
}

int main() {
    int x = 10;
    
    printf("Before function call: x = %d\n", x);
    increment(&x);  // Pass address of x
    printf("After function call: x = %d\n", x);
    
    return 0;
}
                
Output:
Before function call: x = 10
Inside function: *num = 11
After function call: x = 11

Key Observation:

The value of 'x' in main() has changed to 11 because the function modified the original variable through its address. The function parameter 'num' is a pointer that points to the memory location of 'x'.

3.3 Practical Example: Swapping Two Numbers

Incorrect Approach (Call by Value):

#include <stdio.h>

// This won't work - call by value
void swap_incorrect(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    printf("Inside function: a = %d, b = %d\n", a, b);
}

int main() {
    int x = 5, y = 10;
    
    printf("Before swap: x = %d, y = %d\n", x, y);
    swap_incorrect(x, y);
    printf("After swap: x = %d, y = %d\n", x, y);
    
    return 0;
}
                
Output:
Before swap: x = 5, y = 10
Inside function: a = 10, b = 5
After swap: x = 5, y = 10

Correct Approach (Call by Reference):

#include <stdio.h>

// This works - call by reference
void swap_correct(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
    printf("Inside function: *a = %d, *b = %d\n", *a, *b);
}

int main() {
    int x = 5, y = 10;
    
    printf("Before swap: x = %d, y = %d\n", x, y);
    swap_correct(&x, &y);  // Pass addresses
    printf("After swap: x = %d, y = %d\n", x, y);
    
    return 0;
}
                
Output:
Before swap: x = 5, y = 10
Inside function: *a = 10, *b = 5
After swap: x = 10, y = 5

4. Detailed Comparison

Aspect Call by Value Call by Reference
Parameter Passed Copy of actual value Address of actual variable
Memory Usage More (due to copying) Less (only address is copied)
Original Data Safety Safe (cannot be modified) Can be modified accidentally
Function Parameter Regular variable Pointer variable
Function Call Syntax function_name(variable) function_name(&variable)
Function Definition return_type func(datatype param) return_type func(datatype *param)
Access Value Direct access Through dereference (*)
Performance Slower for large data Faster (no copying overhead)
Use Case When original data should not change When function needs to modify original data

5. Advanced Examples

5.1 Array Processing Example

Arrays are always passed by reference in C (array name represents the address of first element):

#include <stdio.h>

void modify_array(int arr[], int size) {
    // Arrays are passed by reference automatically
    for(int i = 0; i < size; i++) {
        arr[i] = arr[i] * 2;  // Modifies original array
    }
}

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

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int size = 5;
    
    printf("Original array: ");
    display_array(numbers, size);
    
    modify_array(numbers, size);  // No & needed for arrays
    
    printf("Modified array: ");
    display_array(numbers, size);
    
    return 0;
}
                
Output:
Original array: 1 2 3 4 5
Modified array: 2 4 6 8 10

5.2 Multiple Return Values using Call by Reference

#include <stdio.h>

// Function to perform multiple operations and return multiple results
void calculate(int a, int b, int *sum, int *diff, int *product) {
    *sum = a + b;
    *diff = a - b;
    *product = a * b;
}

int main() {
    int num1 = 15, num2 = 5;
    int addition, subtraction, multiplication;
    
    printf("Numbers: %d and %d\n", num1, num2);
    
    // Pass addresses to get multiple results
    calculate(num1, num2, &addition, &subtraction, &multiplication);
    
    printf("Sum: %d\n", addition);
    printf("Difference: %d\n", subtraction);
    printf("Product: %d\n", multiplication);
    
    return 0;
}
                
Output:
Numbers: 15 and 5
Sum: 20
Difference: 10
Product: 75

6. Common Mistakes and Best Practices

Common Mistakes:

  1. Forgetting to use & operator: When you want to pass by reference but forget &
  2. Incorrect pointer syntax: Using * when not needed or missing * when dereferencing
  3. Assuming call by value will modify original: Expecting changes in call by value functions
  4. Null pointer dereferencing: Not checking if pointer is valid before using

Best Practices:

  • Use call by value when you don't need to modify the original variable
  • Use call by reference when the function needs to modify the original variable
  • Always validate pointers before dereferencing them
  • Use const keyword for parameters that shouldn't be modified
  • Choose meaningful parameter names to indicate their purpose

6.1 Safe Call by Reference with const

#include <stdio.h>

// Using const to prevent accidental modification
void print_value(const int *ptr) {
    printf("Value: %d\n", *ptr);
    // *ptr = 100;  // This would cause compilation error due to const
}

// Function that safely modifies the value
void safe_increment(int *ptr) {
    if (ptr != NULL) {  // Always check for null pointer
        (*ptr)++;
    }
}

int main() {
    int x = 42;
    
    print_value(&x);    // Safe - cannot modify x
    safe_increment(&x); // Safe - with null check
    print_value(&x);
    
    return 0;
}
                

Practice Exercise

Problem: Write a C program that includes the following functions:

  1. A function to find both maximum and minimum values in an array (use call by reference to return both values)
  2. A function to calculate the factorial of a number (use call by value)
  3. A function to reverse an array in-place (use call by reference)

Hint: Think about which functions need to modify original data and which ones don't.

Summary

In this lecture, we explored the fundamental concepts of parameter passing in C:

Next Lecture Preview: We will explore advanced pointer concepts and dynamic memory allocation.