Function Call

Introduction

A function call in C is the process of executing a function by using its name followed by parentheses containing arguments. When a function is called, program control transfers to the function, executes its code, and then returns to the point where the function was called. Understanding function calls is essential for program flow control and code organization.

Key Concepts

Function Invocation: Executing a function by calling its name Arguments: Values passed to the function Return Value: Value returned by the function to the caller Call Stack: Memory structure that manages function calls

Basic Function Call Syntax

// For functions that return a value
variable = function_name(arguments);

// For void functions
function_name(arguments);

// For functions with no parameters
function_name();

Simple Function Calls

Basic Examples

#include <stdio.h>

// Function definitions
int add(int a, int b) {
    return a + b;
}

void greet(char name[]) {
    printf("Hello, %s!\n", name);
}

int getNumber() {
    return 42;
}

int main() {
    // Function call with return value
    int result = add(5, 3);
    printf("Sum: %d\n", result);
    
    // Direct function call in printf
    printf("Direct call result: %d\n", add(10, 20));
    
    // Void function call
    greet("Alice");
    
    // Function call with no parameters
    int number = getNumber();
    printf("Number: %d\n", number);
    
    return 0;
}

Function Calls in Expressions

#include <stdio.h>

int multiply(int x, int y) {
    return x * y;
}

int square(int n) {
    return n * n;
}

int main() {
    int a = 5, b = 3;
    
    // Function calls in arithmetic expressions
    int result1 = multiply(a, b) + square(2);
    printf("Result 1: %d\n", result1);
    
    // Function calls as function arguments
    int result2 = multiply(square(3), add(2, 4));
    printf("Result 2: %d\n", result2);
    
    // Function calls in conditional expressions
    if (multiply(a, b) > square(4)) {
        printf("Condition is true\n");
    }
    
    return 0;
}

Parameter Passing Examples

Call by Value

#include <stdio.h>

void modifyValue(int x) {
    x = x * 2;
    printf("Inside function: x = %d\n", x);
}

void processArray(int arr[], int size) {
    printf("Array in function: ");
    for (int i = 0; i < size; i++) {
        arr[i] *= 2; // This modifies the original array
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int number = 10;
    printf("Before call: number = %d\n", number);
    modifyValue(number);
    printf("After call: number = %d\n", number);
    
    int array[] = {1, 2, 3, 4, 5};
    printf("Original array: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
    
    processArray(array, 5);
    
    printf("Array after function call: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
    
    return 0;
}

Call by Reference (using pointers)

#include <stdio.h>

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

void updateValues(int *x, int *y, int *z) {
    *x += 10;
    *y *= 2;
    *z -= 5;
}

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 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);
    
    return 0;
}

Different Types of Function Calls

Recursive Function Calls

#include <stdio.h>

int factorial(int n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1); // Recursive call
}

void printNumbers(int n) {
    if (n > 0) {
        printf("%d ", n);
        printNumbers(n - 1); // Recursive call
    }
}

int main() {
    printf("Factorial of 5: %d\n", factorial(5));
    
    printf("Countdown: ");
    printNumbers(5);
    printf("\n");
    
    return 0;
}

Nested Function Calls

#include <stdio.h>
#include <math.h>

double calculateArea(double radius) {
    return 3.14159 * pow(radius, 2);
}

double calculateVolume(double radius, double height) {
    return calculateArea(radius) * height; // Nested call
}

int getMax(int a, int b) {
    return (a > b) ? a : b;
}

int getMaxOfThree(int x, int y, int z) {
    return getMax(getMax(x, y), z); // Nested calls
}

int main() {
    double volume = calculateVolume(3.0, 10.0);
    printf("Cylinder volume: %.2f\n", volume);
    
    int maximum = getMaxOfThree(15, 25, 20);
    printf("Maximum of three numbers: %d\n", maximum);
    
    return 0;
}

Function Calls with Different Data Types

String Function Calls

#include <stdio.h>
#include <string.h>

int stringLength(char str[]) {
    int length = 0;
    while (str[length] != '\0') {
        length++;
    }
    return length;
}

void stringCopy(char dest[], char src[]) {
    int i = 0;
    while (src[i] != '\0') {
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';
}

int main() {
    char message[] = "Hello World";
    char copy[50];
    
    int len = stringLength(message);
    printf("Length of '%s': %d\n", message, len);
    
    stringCopy(copy, message);
    printf("Copied string: %s\n", copy);
    
    return 0;
}

Structure Function Calls

#include <stdio.h>

typedef struct {
    int x, y;
} Point;

typedef struct {
    char name[30];
    int age;
    float salary;
} Employee;

Point createPoint(int x, int y) {
    Point p;
    p.x = x;
    p.y = y;
    return p;
}

void printEmployee(Employee emp) {
    printf("Name: %s, Age: %d, Salary: %.2f\n", emp.name, emp.age, emp.salary);
}

void updateSalary(Employee *emp, float increment) {
    emp->salary += increment;
}

int main() {
    Point p1 = createPoint(10, 20);
    printf("Point: (%d, %d)\n", p1.x, p1.y);
    
    Employee emp = {"John Doe", 30, 50000.0};
    printf("Before update: ");
    printEmployee(emp);
    
    updateSalary(&emp, 5000.0);
    printf("After update: ");
    printEmployee(emp);
    
    return 0;
}

Function Pointers and Calls

Basic Function Pointer Calls

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int multiply(int a, int b) {
    return a * b;
}

int calculate(int x, int y, int (*operation)(int, int)) {
    return operation(x, y);
}

int main() {
    // Function pointer declaration and assignment
    int (*mathOp)(int, int);
    
    mathOp = add;
    printf("Addition: %d\n", mathOp(5, 3));
    
    mathOp = multiply;
    printf("Multiplication: %d\n", mathOp(5, 3));
    
    // Passing function as parameter
    printf("Using function parameter: %d\n", calculate(4, 6, add));
    printf("Using function parameter: %d\n", calculate(4, 6, multiply));
    
    return 0;
}

Error Handling in Function Calls

Checking Return Values

#include <stdio.h>

int safeDivide(int a, int b, int *result) {
    if (b == 0) {
        return 0; // Error: division by zero
    }
    *result = a / b;
    return 1; // Success
}

int validateInput(int value) {
    if (value < 0 || value > 100) {
        return 0; // Invalid input
    }
    return 1; // Valid input
}

int main() {
    int dividend = 20, divisor = 0, result;
    
    if (safeDivide(dividend, divisor, &result)) {
        printf("Division result: %d\n", result);
    } else {
        printf("Error: Cannot divide by zero\n");
    }
    
    int userInput = 150;
    if (validateInput(userInput)) {
        printf("Input %d is valid\n", userInput);
    } else {
        printf("Input %d is invalid\n", userInput);
    }
    
    return 0;
}

Practical Function Call Examples

Calculator Program

#include <stdio.h>

float add(float a, float b) { return a + b; }
float subtract(float a, float b) { return a - b; }
float multiply(float a, float b) { return a * b; }
float divide(float a, float b) { 
    return (b != 0) ? a / b : 0; 
}

void displayMenu() {
    printf("\n=== Calculator ===\n");
    printf("1. Addition\n");
    printf("2. Subtraction\n");
    printf("3. Multiplication\n");
    printf("4. Division\n");
    printf("5. Exit\n");
    printf("Choose operation: ");
}

int main() {
    int choice;
    float num1, num2, result;
    
    while (1) {
        displayMenu();
        scanf("%d", &choice);
        
        if (choice == 5) break;
        
        if (choice >= 1 && choice <= 4) {
            printf("Enter two numbers: ");
            scanf("%f %f", &num1, &num2);
            
            switch (choice) {
                case 1: result = add(num1, num2); break;
                case 2: result = subtract(num1, num2); break;
                case 3: result = multiply(num1, num2); break;
                case 4: result = divide(num1, num2); break;
            }
            printf("Result: %.2f\n", result);
        } else {
            printf("Invalid choice!\n");
        }
    }
    
    return 0;
}

Best Practices for Function Calls

Clear and Meaningful Calls

// Good - clear function calls with meaningful variable names
int studentCount = getStudentCount();
float averageGrade = calculateAverage(grades, studentCount);
bool isPassed = checkPassingGrade(averageGrade, PASSING_THRESHOLD);

// Poor - unclear function calls
int x = func1();
float y = func2(data, x);
bool z = func3(y, 60);

Proper Error Checking

#include <stdio.h>

int openFile(char filename[]) {
    // Simulated file opening
    if (filename == NULL) return 0;
    printf("File '%s' opened successfully\n", filename);
    return 1;
}

int main() {
    char filename[] = "data.txt";
    
    // Always check return values for error conditions
    if (openFile(filename)) {
        printf("File operations can proceed\n");
        // Perform file operations
    } else {
        printf("Error: Failed to open file\n");
        return 1; // Exit with error code
    }
    
    return 0;
}

Common Mistakes in Function Calls

  1. Wrong Number of Arguments: Ensure argument count matches parameters
  2. Type Mismatches: Pass arguments of correct data types
  3. Ignoring Return Values: Check return values for error conditions
  4. Uninitialized Variables: Initialize variables before passing to functions
  5. Missing Function Prototypes: Declare functions before calling them

Summary

Function calls are fundamental to C programming, enabling code reuse and modular design. Understanding how to properly call functions with correct arguments, handle return values, and manage different parameter passing methods is essential. Proper function calling practices include error checking, meaningful variable names, and following consistent coding conventions for maintainable and reliable programs.


Part of BCA Programming with C Course (UGCOA22J201)