Introduction
Call by value and call by reference are two fundamental methods of parameter passing in C programming. Understanding these concepts is crucial for effective function design and memory management. Call by value passes copies of arguments, while call by reference passes memory addresses, allowing functions to modify the original variables.
Key Concepts
Call by Value: Passing copies of actual parameters to function parameters Call by Reference: Passing addresses of actual parameters using pointers Parameter: Variable in function definition that receives values Argument: Actual value passed to the function during call
Call by Value
Basic Concept
In call by value, copies of the actual arguments are passed to function parameters. Changes made to parameters inside the function do not affect the original variables.
#include <stdio.h>
void modifyValue(int x) {
printf("Inside function - before modification: x = %d\n", x);
x = x * 2;
printf("Inside function - after modification: x = %d\n", x);
}
int main() {
int number = 10;
printf("Before function call: number = %d\n", number);
modifyValue(number);
printf("After function call: number = %d\n", number);
return 0;
}
/* Output:
Before function call: number = 10
Inside function - before modification: x = 10
Inside function - after modification: x = 20
After function call: number = 10
*/
Multiple Parameters Example
#include <stdio.h>
int calculateSum(int a, int b, int c) {
printf("Inside function: a=%d, b=%d, c=%d\n", a, b, c);
a = a + 100; // This won't affect original variables
b = b + 200;
c = c + 300;
printf("Modified inside function: a=%d, b=%d, c=%d\n", a, b, c);
return a + b + c;
}
int main() {
int x = 5, y = 10, z = 15;
printf("Before function call: x=%d, y=%d, z=%d\n", x, y, z);
int result = calculateSum(x, y, z);
printf("Sum result: %d\n", result);
printf("After function call: x=%d, y=%d, z=%d\n", x, y, z);
return 0;
}
Array Parameters (Special Case)
#include <stdio.h>
void modifyArray(int arr[], int size) {
printf("Inside function - original array:\n");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// Modifying array elements
for (int i = 0; i < size; i++) {
arr[i] = arr[i] * 2;
}
printf("Inside function - modified array:\n");
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 in main:\n");
for (int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
modifyArray(numbers, size);
printf("Array in main after function call:\n");
for (int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}
Call by Reference
Using Pointers for Call by Reference
#include <stdio.h>
void swapValues(int *a, int *b) {
printf("Inside function - before swap: *a=%d, *b=%d\n", *a, *b);
int temp = *a;
*a = *b;
*b = temp;
printf("Inside function - after swap: *a=%d, *b=%d\n", *a, *b);
}
void modifyValue(int *ptr) {
printf("Inside function - original value: %d\n", *ptr);
*ptr = *ptr * 3;
printf("Inside function - modified value: %d\n", *ptr);
}
int main() {
int first = 25, second = 40;
printf("Before swap: first=%d, second=%d\n", first, second);
swapValues(&first, &second);
printf("After swap: first=%d, second=%d\n", first, second);
int number = 15;
printf("\nBefore modification: number=%d\n", number);
modifyValue(&number);
printf("After modification: number=%d\n", number);
return 0;
}
Multiple Variable Modification
#include <stdio.h>
void updateValues(int *x, int *y, int *z) {
printf("Inside function - original values: x=%d, y=%d, z=%d\n", *x, *y, *z);
*x = *x + 10;
*y = *y * 2;
*z = *z - 5;
printf("Inside function - updated values: x=%d, y=%d, z=%d\n", *x, *y, *z);
}
void calculateResults(int a, int b, int *sum, int *product, int *difference) {
*sum = a + b;
*product = a * b;
*difference = (a > b) ? (a - b) : (b - a);
}
int main() {
int a = 5, b = 10, c = 20;
printf("Before update: a=%d, b=%d, c=%d\n", a, b, c);
updateValues(&a, &b, &c);
printf("After update: a=%d, b=%d, c=%d\n", a, b, c);
int num1 = 15, num2 = 8;
int sum, product, difference;
calculateResults(num1, num2, &sum, &product, &difference);
printf("\nCalculations for %d and %d:\n", num1, num2);
printf("Sum: %d, Product: %d, Difference: %d\n", sum, product, difference);
return 0;
}
Practical Examples
Student Record Management
#include <stdio.h>
#include <string.h>
typedef struct {
char name[50];
int rollNo;
float marks;
char grade;
} Student;
// Call by value - student data is copied
void displayStudent(Student s) {
printf("Name: %s\n", s.name);
printf("Roll No: %d\n", s.rollNo);
printf("Marks: %.2f\n", s.marks);
printf("Grade: %c\n", s.grade);
}
// Call by reference - student data can be modified
void updateMarks(Student *s, float newMarks) {
s->marks = newMarks;
// Update grade based on marks
if (newMarks >= 90) s->grade = 'A';
else if (newMarks >= 80) s->grade = 'B';
else if (newMarks >= 70) s->grade = 'C';
else if (newMarks >= 60) s->grade = 'D';
else s->grade = 'F';
}
int main() {
Student student1 = {"John Doe", 101, 75.5, 'C'};
printf("Original student data:\n");
displayStudent(student1);
printf("\nUpdating marks to 88.5...\n");
updateMarks(&student1, 88.5);
printf("\nUpdated student data:\n");
displayStudent(student1);
return 0;
}
Mathematical Operations
#include <stdio.h>
#include <math.h>
// Call by value - returning single result
double calculateArea(double radius) {
return 3.14159 * radius * radius;
}
// Call by reference - returning multiple results
void calculateCircleProperties(double radius, double *area, double *circumference, double *diameter) {
*area = 3.14159 * radius * radius;
*circumference = 2 * 3.14159 * radius;
*diameter = 2 * radius;
}
// Call by reference - input validation and modification
int validateAndCorrect(int *value, int min, int max) {
if (*value < min) {
*value = min;
return 0; // Value was corrected
} else if (*value > max) {
*value = max;
return 0; // Value was corrected
}
return 1; // Value was valid
}
int main() {
double radius = 5.0;
// Using call by value
double area1 = calculateArea(radius);
printf("Area (call by value): %.2f\n", area1);
// Using call by reference
double area2, circumference, diameter;
calculateCircleProperties(radius, &area2, &circumference, &diameter);
printf("\nCircle properties (call by reference):\n");
printf("Area: %.2f\n", area2);
printf("Circumference: %.2f\n", circumference);
printf("Diameter: %.2f\n", diameter);
// Input validation example
int score = 150; // Invalid score
printf("\nOriginal score: %d\n", score);
if (validateAndCorrect(&score, 0, 100)) {
printf("Score is valid: %d\n", score);
} else {
printf("Score was corrected to: %d\n", score);
}
return 0;
}
Advanced Examples
Dynamic Memory and Pointers
#include <stdio.h>
#include <stdlib.h>
void allocateMemory(int **ptr, int size) {
*ptr = (int*)malloc(size * sizeof(int));
if (*ptr == NULL) {
printf("Memory allocation failed!\n");
} else {
printf("Memory allocated for %d integers\n", size);
}
}
void fillArray(int *arr, int size) {
for (int i = 0; i < size; i++) {
arr[i] = (i + 1) * 10;
}
}
void modifyArrayValues(int *arr, int size, int multiplier) {
for (int i = 0; i < size; i++) {
arr[i] *= multiplier;
}
}
int main() {
int *numbers = NULL;
int size = 5;
// Allocate memory using call by reference
allocateMemory(&numbers, size);
if (numbers != NULL) {
// Fill array
fillArray(numbers, size);
printf("Original array: ");
for (int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
// Modify array values
modifyArrayValues(numbers, size, 3);
printf("Modified array: ");
for (int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
free(numbers);
}
return 0;
}
Function Pointer Examples
#include <stdio.h>
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
// Call by value with function pointer
int calculate(int x, int y, int (*operation)(int, int)) {
return operation(x, y);
}
// Call by reference with function pointer
void performOperation(int *result, int a, int b, int (*operation)(int, int)) {
*result = operation(a, b);
}
int main() {
int num1 = 15, num2 = 3;
// Call by value with function pointer
int result1 = calculate(num1, num2, add);
int result2 = calculate(num1, num2, multiply);
printf("Call by value results:\n");
printf("Addition: %d\n", result1);
printf("Multiplication: %d\n", result2);
// Call by reference with function pointer
int result3, result4;
performOperation(&result3, num1, num2, add);
performOperation(&result4, num1, num2, multiply);
printf("\nCall by reference results:\n");
printf("Addition: %d\n", result3);
printf("Multiplication: %d\n", result4);
return 0;
}
Performance Considerations
Memory Usage Comparison
#include <stdio.h>
typedef struct {
int data[1000];
char info[100];
} LargeStruct;
// Call by value - creates a copy (expensive)
void processByValue(LargeStruct s) {
printf("Processing large structure by value\n");
s.data[0] = 999; // This won't affect original
}
// Call by reference - passes address (efficient)
void processByReference(LargeStruct *s) {
printf("Processing large structure by reference\n");
s->data[0] = 999; // This will affect original
}
// Call by reference (read-only) - efficient and safe
void displayByReference(const LargeStruct *s) {
printf("Displaying structure data: %d\n", s->data[0]);
// s->data[0] = 100; // This would cause compilation error
}
int main() {
LargeStruct bigData = {{0}, "Sample Info"};
bigData.data[0] = 100;
printf("Original value: %d\n", bigData.data[0]);
// Call by value (slow, doesn't modify original)
processByValue(bigData);
printf("After call by value: %d\n", bigData.data[0]);
// Call by reference (fast, modifies original)
processByReference(&bigData);
printf("After call by reference: %d\n", bigData.data[0]);
// Read-only reference (fast, safe)
displayByReference(&bigData);
return 0;
}
Common Mistakes and Best Practices
Mistake 1: Forgetting to Use Address Operator
// Wrong way
int value = 10;
modifyValue(value); // Won't modify original value
// Correct way
int value = 10;
modifyValue(&value); // Will modify original value
Mistake 2: Not Checking Null Pointers
void safeFunction(int *ptr) {
if (ptr == NULL) {
printf("Error: Null pointer passed\n");
return;
}
*ptr = 100; // Safe to dereference
}
Best Practices
// Use const for read-only parameters
void printArray(const int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
}
// Clear function names indicating parameter type
void updateValueByReference(int *value);
void calculateSumByValue(int a, int b);
Summary
Call by value and call by reference are essential parameter passing mechanisms in C. Call by value is safer and simpler but creates copies, while call by reference is more efficient for large data and allows modification of original variables. Choose the appropriate method based on your needs: use call by value for small data and when you don’t need to modify originals, and use call by reference for large data structures or when you need to modify multiple variables. Always validate pointers and use const for read-only reference parameters.
Part of BCA Programming with C Course (UGCOA22J201)