Chapter 10: User-Defined Functions

📌 Learning Objectives
  • LO 10.1: Understand the need for user-defined functions
  • LO 10.2: Define and call functions with various categories
  • LO 10.3: Work with function arguments and return values
  • LO 10.4: Implement recursion and nesting of functions
  • LO 10.5: Pass arrays and strings to functions
  • LO 10.6: Understand scope, visibility, and lifetime of variables

10.1 Introduction to Functions

Functions are self-contained blocks of code that perform a particular task. They are the building blocks of C programs and enable modular programming.

                    Top-down Modular Programming
                    
                    ┌─────────────────────────────────────┐
                    │            MAIN PROGRAM             │
                    └─────────┬───────────────┬───────────┘
                              │               │
                    ┌─────────▼─────────┐ ┌───▼──────────┐
                    │    Function 1     │ │  Function 2  │
                    └─────────┬─────────┘ └───────┬──────┘
                              │                    │
                    ┌─────────▼─────────┐ ┌───────▼──────┐
                    │   Function 1.1    │ │ Function 2.1 │
                    └───────────────────┘ └──────────────┘

Fig. 10.1: Top-down modular programming using functions

Advantages of using functions:

10.2 A Multi-Function Program

📝 Worked-Out Problem 10.1

Simple program with multiple functions:

#include <stdio.h>

void printline(void) {
    int i;
    for (i = 1; i <= 35; i++)
        printf("-");
    printf("\n");
}

int main() {
    printline();
    printf("This illustrates the use of C functions\n");
    printline();
    return 0;
}
Output:
-----------------------------------
This illustrates the use of C functions
-----------------------------------

10.3 Elements of User-Defined Functions

Three elements are needed to use a function:

  1. Function definition: The actual code of the function
  2. Function call: Invoking the function
  3. Function declaration (prototype): Telling the compiler about the function

Function Definition Format

return_type function_name(parameter list)
{
    local variable declarations;
    executable statements;
    return statement;
}

Function Header Components

Function Body

The return Statement

return;                 // No value returned
return expression;      // Returns value of expression

Function Prototype

return_type function_name(parameter list);  // With parameter names
return_type function_name(type1, type2, ...); // Without parameter names
📌 Note: If no prototype is provided, C assumes the function returns int and takes any number of arguments. Always provide prototypes to avoid errors.

10.4 Category of Functions

Category 1: No arguments, no return values

📝 Worked-Out Problem 10.2

Functions with no arguments and no return values:

#include <stdio.h>

void printline(char c) {
    int i;
    for (i = 1; i <= 35; i++)
        printf("%c", c);
    printf("\n");
}

void value(void) {
    int year, period;
    float inrate, sum, principal;
    
    printf("Principal amount: ");
    scanf("%f", &principal);
    printf("Interest rate: ");
    scanf("%f", &inrate);
    printf("Period: ");
    scanf("%d", &period);
    
    sum = principal;
    year = 1;
    
    while (year <= period) {
        sum = sum * (1 + inrate);
        year++;
    }
    
    printf("Total amount = %.2f\n", sum);
}

int main() {
    char ch = '=';
    printline(ch);
    value();
    printline('*');
    return 0;
}

Category 2: Arguments but no return values

📝 Worked-Out Problem 10.3

One-way data communication (arguments, no return):

#include <stdio.h>

void printline(char ch, int len) {
    int i;
    for (i = 1; i <= len; i++)
        printf("%c", ch);
    printf("\n");
}

void value(float p, float r, int n) {
    int year;
    float sum;
    
    sum = p;
    year = 1;
    
    while (year <= n) {
        sum = sum * (1 + r);
        year++;
    }
    
    printf("Total amount = %.2f\n", sum);
}

int main() {
    float principal, inrate;
    int period;
    
    printf("Principal amount: ");
    scanf("%f", &principal);
    printf("Interest rate: ");
    scanf("%f", &inrate);
    printf("Period: ");
    scanf("%d", &period);
    
    printline('Z', 40);
    value(principal, inrate, period);
    printline('C', 40);
    
    return 0;
}

Category 3: Arguments with return values

📝 Worked-Out Problem 10.4

Two-way data communication:

#include <stdio.h>

void printline(char ch, int len) {
    int i;
    for (i = 1; i <= len; i++)
        printf("%c", ch);
    printf("\n");
}

float value(float p, float r, int n) {
    int year;
    float sum;
    
    sum = p;
    year = 1;
    
    while (year <= n) {
        sum = sum * (1 + r);
        year++;
    }
    
    return sum;  // Return the computed value
}

int main() {
    float principal, inrate, amount;
    int period;
    
    printf("Principal amount: ");
    scanf("%f", &principal);
    printf("Interest rate: ");
    scanf("%f", &inrate);
    printf("Period: ");
    scanf("%d", &period);
    
    printline('*', 52);
    amount = value(principal, inrate, period);
    printf("Total amount = %.2f\n", amount);
    printline('=', 52);
    
    return 0;
}
Output:
****************************************************
Total amount = 1610.51
====================================================

Returning Float Values

📝 Worked-Out Problem 10.5

Function returning float/double:

#include <stdio.h>

double power(int x, int n) {
    int i;
    double result = 1.0;
    
    for (i = 1; i <= n; i++)
        result *= x;
    
    return result;
}

int main() {
    int x, n;
    
    printf("Enter x and n: ");
    scanf("%d %d", &x, &n);
    
    printf("%d to the power %d = %.0f\n", x, n, power(x, n));
    
    return 0;
}
Output:
Enter x and n: 5 4
5 to the power 4 = 625

Category 4: No arguments but returns a value

int get_number(void) {
    int num;
    printf("Enter a number: ");
    scanf("%d", &num);
    return num;
}

10.5 Nesting of Functions

C permits nesting of functions freely. A function can call another function, which can call another, and so on.

📝 Worked-Out Problem 10.6

Nested function calls:

#include <stdio.h>

int difference(int a, int b) {
    return (a - b);
}

float ratio(int a, int b, int c) {
    int diff = difference(b, c);
    if (diff != 0)
        return (float)a / diff;
    else
        return 0.0;
}

int main() {
    int a, b, c;
    float result;
    
    printf("Enter three numbers: ");
    scanf("%d %d %d", &a, &b, &c);
    
    result = ratio(a, b, c);
    
    if (result != 0.0)
        printf("a/(b-c) = %.2f\n", result);
    else
        printf("Division by zero\n");
    
    return 0;
}
Output:
Enter three numbers: 10 8 3
a/(b-c) = 2.00

10.6 Recursion

Recursion is a special case where a function calls itself.

📝 Worked-Out Problem 10.7

Factorial using recursion:

#include <stdio.h>

int factorial(int n) {
    if (n == 0 || n == 1)
        return 1;
    else
        return n * factorial(n - 1);
}

int main() {
    int num;
    
    printf("Enter a number: ");
    scanf("%d", &num);
    
    printf("Factorial of %d = %d\n", num, factorial(num));
    
    return 0;
}
Output:
Enter a number: 5
Factorial of 5 = 120

How it works for factorial(4):

factorial(4) = 4 * factorial(3)
            = 4 * 3 * factorial(2)
            = 4 * 3 * 2 * factorial(1)
            = 4 * 3 * 2 * 1
            = 24

📝 Worked-Out Problem 10.8

Fibonacci series using recursion:

#include <stdio.h>

int fibonacci(int n) {
    if (n == 0)
        return 0;
    else if (n == 1)
        return 1;
    else
        return fibonacci(n-1) + fibonacci(n-2);
}

int main() {
    int n, i;
    
    printf("Enter number of terms: ");
    scanf("%d", &n);
    
    printf("Fibonacci series: ");
    for (i = 0; i < n; i++)
        printf("%d ", fibonacci(i));
    printf("\n");
    
    return 0;
}
Output:
Enter number of terms: 10
Fibonacci series: 0 1 1 2 3 5 8 13 21 34
⚠️ Important: Recursive functions must have a condition that forces the function to return without making the recursive call. Otherwise, the function will never return (infinite recursion).

10.7 Passing Arrays to Functions

One-Dimensional Arrays

📝 Worked-Out Problem 10.9

Passing arrays to functions:

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

float mean(float arr[], int n) {
    float sum = 0;
    int i;
    for (i = 0; i < n; i++)
        sum += arr[i];
    return sum / n;
}

float std_dev(float arr[], int n) {
    float m = mean(arr, n);
    float sum = 0;
    int i;
    
    for (i = 0; i < n; i++)
        sum += (arr[i] - m) * (arr[i] - m);
    
    return sqrt(sum / n);
}

int main() {
    float values[100];
    int n, i;
    
    printf("Enter number of elements: ");
    scanf("%d", &n);
    
    printf("Enter %d values:\n", n);
    for (i = 0; i < n; i++)
        scanf("%f", &values[i]);
    
    printf("Mean = %.2f\n", mean(values, n));
    printf("Standard Deviation = %.2f\n", std_dev(values, n));
    
    return 0;
}

Rules for Passing Arrays

Two-Dimensional Arrays

float average(int rows, int cols, int matrix[][cols]) {
    int i, j, sum = 0;
    for (i = 0; i < rows; i++)
        for (j = 0; j < cols; j++)
            sum += matrix[i][j];
    return (float)sum / (rows * cols);
}

10.8 Searching and Sorting with Functions

📝 Worked-Out Problem 10.10

Linear search using functions:

#include <stdio.h>

int linear_search(int arr[], int n, int key) {
    int i;
    for (i = 0; i < n; i++) {
        if (arr[i] == key)
            return i;
    }
    return -1;
}

int main() {
    int arr[100], n, key, pos, i;
    
    printf("Enter size of array: ");
    scanf("%d", &n);
    
    printf("Enter %d elements:\n", n);
    for (i = 0; i < n; i++)
        scanf("%d", &arr[i]);
    
    printf("Enter element to search: ");
    scanf("%d", &key);
    
    pos = linear_search(arr, n, key);
    
    if (pos != -1)
        printf("%d found at position %d\n", key, pos);
    else
        printf("%d not found\n", key);
    
    return 0;
}

📝 Worked-Out Problem 10.11

Bubble sort using functions:

#include <stdio.h>

void bubble_sort(int arr[], int n) {
    int i, j, temp;
    for (i = 0; i < n-1; i++) {
        for (j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

int main() {
    int arr[100], n, i;
    
    printf("Enter size of array: ");
    scanf("%d", &n);
    
    printf("Enter %d elements:\n", n);
    for (i = 0; i < n; i++)
        scanf("%d", &arr[i]);
    
    bubble_sort(arr, n);
    
    printf("Sorted array:\n");
    for (i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
    
    return 0;
}

10.9 Scope, Visibility, and Lifetime of Variables

Storage Classes

Storage Class Scope Lifetime Initialization
auto Local to block Within block Garbage (uninitialized)
register Local to block Within block Garbage
static Local to block Entire program Zero
extern Global Entire program Zero

Automatic Variables (auto)

void function() {
    int x;           // auto by default
    auto int y;      // explicitly auto
    
    x = 10;          // created when function called
    // destroyed when function exits
}

📝 Worked-Out Problem 10.12

Working of automatic variables:

#include <stdio.h>

void function1() {
    int m = 10;
    printf("function1: m = %d\n", m);
}

void function2() {
    int m = 100;
    printf("function2: m = %d\n", m);
    function1();
}

int main() {
    int m = 1000;
    printf("main: m = %d\n", m);
    function2();
    return 0;
}
Output:
main: m = 1000
function2: m = 100
function1: m = 10

External (Global) Variables

int global_var;  // Global variable

void function1() {
    global_var = 100;  // Can access global
}

void function2() {
    global_var = 200;  // Can modify global
}

📝 Worked-Out Problem 10.13

Properties of global variables:

#include <stdio.h>

int x = 10;  // Global variable

void function1() {
    x = x + 5;
    printf("function1: x = %d\n", x);
}

void function2() {
    int x = 50;  // Local variable hides global
    printf("function2: local x = %d\n", x);
    x = x + 10;
    printf("function2: local x after = %d\n", x);
}

void function3() {
    printf("function3: global x = %d\n", x);
}

int main() {
    printf("main: x = %d\n", x);
    function1();
    function2();
    function3();
    return 0;
}
Output:
main: x = 10
function1: x = 15
function2: local x = 50
function2: local x after = 60
function3: global x = 15

Static Variables

📝 Worked-Out Problem 10.14

Static variables retain values between calls:

#include <stdio.h>

void stat(void) {
    static int x = 0;  // Initialized only once
    x++;
    printf("x = %d\n", x);
}

int main() {
    stat();  // x = 1
    stat();  // x = 2
    stat();  // x = 3
    return 0;
}
Output:
x = 1
x = 2
x = 3

Register Variables

register int counter;  // Request to store in CPU register

External Declaration (extern)

// File1.c
int global_var = 100;

// File2.c
extern int global_var;  // Use variable from File1.c

Important Points to Remember

  • A function that returns a value can be used in expressions like any other C variable.
  • A function that returns a value cannot be used as a stand-alone statement.
  • It is a syntax error if the types in the declaration and function definition do not match.
  • A return statement is required if the return type is anything other than void.
  • If a function has no parameters, the parameter list must be declared as void.
  • Defining a function within another function is not allowed.
  • Functions return integer value by default.
  • Pass by value is the default; pass by address is used to modify calling function's variables.

Chapter Exercises

Review Questions

  1. State true or false:
    a) Any name can be used as a function name.
    b) A function without a return statement is illegal.
    c) The return type of a function is int by default.
    d) When variable values are passed to functions, a copy of them is created.
    e) A function can be defined within the main function.
    f) C functions can return only one value under their function name.
  2. What is prototyping? Why is it necessary?
  3. Distinguish between actual and formal arguments.
  4. What is the output of:
    int x = 5, y = 10;
    printf("%d", (x > y) ? x : y);

Multiple Choice Questions

  1. Which of the following is true while passing an array to a function?
    a) The function is called by passing the array name without brackets
    b) The size of the array is not required in the formal parameter list
    c) The function prototype must show that the argument is an array
    d) All of the above
  2. Which of the following is true about automatic variables?
    a) They are declared inside a function
    b) They are created when the function is called and destroyed when it exits
    c) A variable without storage class specification is auto by default
    d) All of the above
  3. For which type of variable does the value persist till the end of the program?
    a) auto
    b) static
    c) register
    d) None
  4. If the number and type of arguments in a function declaration and definition do not match:
    a) The type in the definition is considered
    b) The type in the declaration is considered
    c) A compiler error is generated
    d) None

Debugging Exercises

Find errors in the following function definitions:

void printline()   // Missing semicolon?
{
    printf("Hello");
}

int sum(int a, b)  // Parameter b missing type
{
    return a + b;
}

float average(x, y)  // Missing parameter types
{
    return (x + y) / 2.0;
}

void display() {
    printf("Hello");
    return 5;  // Returning value from void function
}

Programming Exercises

  1. Write a function exchange to interchange the values of two variables (using pointers).
  2. Write a function to evaluate an n-order polynomial using Horner's method.
  3. Write a recursive function to generate and print the first n Fibonacci numbers.
  4. Write a function prime that returns 1 if its argument is prime, 0 otherwise.
  5. Write a function that converts all lowercase characters in a string to uppercase.
  6. Develop a top-down modular program to implement a calculator with functions for add, subtract, multiply, divide.
  7. Write a function to find the largest element of an m×n matrix.
  8. Write functions to perform string operations: copy, compare, concatenate (without using library functions).
  9. Write a recursive function to compute the GCD of two numbers.
  10. Write a function leap that receives a year and returns whether it's a leap year.

Interview Questions

  1. Is it possible to execute instructions after the main function has ended?
  2. What is the difference between formal arguments and actual arguments?
  3. What is the difference between 'call by value' and 'call by reference'?
  4. Write a recursive function to find the GCD of two numbers.
  5. What is the default return type of a function defined without a return type?
  6. What will be the output of:
    int a = 10, b = 20;
    a = a++ + ++b;
    b = ++a + b++;
    printf("%d %d", a, b);

Case Study: Calculation of Area Under a Curve

📝 Case Study: Computing area using trapezoidal rule

#include <stdio.h>

float f(float x) {
    return x * x + 1;  // Function f(x) = x² + 1
}

float area(float a, float b, int n) {
    float h = (b - a) / n;
    float sum = 0.5 * (f(a) + f(b));
    int i;
    
    for (i = 1; i < n; i++)
        sum += f(a + i * h);
    
    return sum * h;
}

int main() {
    float lower, upper;
    int intervals;
    
    printf("Enter lower limit: ");
    scanf("%f", &lower);
    printf("Enter upper limit: ");
    scanf("%f", &upper);
    printf("Enter number of trapezoids: ");
    scanf("%d", &intervals);
    
    printf("Area under f(x) = x² + 1 from %.2f to %.2f = %.4f\n",
           lower, upper, area(lower, upper, intervals));
    
    return 0;
}
Output:
Enter lower limit: 0
Enter upper limit: 3
Enter number of trapezoids: 100
Area under f(x) = x² + 1 from 0.00 to 3.00 = 12.0000

Note: The actual area (by integration) is 12.0. More trapezoids give better accuracy.