Unit 2: Functions and Program Structure

Table of Contents

2.1 Functions and Program Structure

A function is a self-contained block of code that performs a specific task. Using functions makes code modular, reusable, and easier to debug.

Defining and Accessing Functions

// Function Definition
float calculateAverage(int a, int b) {
    float avg = (a + b) / 2.0;
    return avg;
}

int main() {
    int x = 10, y = 5;
    // Function Access (Call)
    float result = calculateAverage(x, y); 
    printf("Average: %.2f\n", result);
    return 0;
}

Passing Arguments to a Function

In C, arguments are passed by Pass-by-Value by default. This means the function receives a copy of the argument's value, and the original variable in the calling function is not changed. (We will see how to change this with pointers in Unit 3).

2.2 Function Prototypes and Return Types

Function Prototypes

A function prototype is a declaration of a function that tells the compiler about its name, return type, and parameters. It is crucial if you define the function after main().

#include <stdio.h>

// Function Prototype
float calculateAverage(int a, int b);

int main() {
    float result = calculateAverage(10, 5); // Compiler already knows what this is
    printf("Result: %.2f\n", result);
    return 0;
}

// Function Definition
float calculateAverage(int a, int b) {
    return (a + b) / 2.0;
}

Functions Returning Non-Integers

Functions can return any data type, such as float, double, char, or even pointers (Unit 3) and structures (Unit 4). The calculateAverage function above is an example of a function returning a float.

2.3 Storage Classes and Scope Rules

Storage classes determine a variable's scope, lifetime, and storage location.

Storage ClassKeywordStorageDefault ValueScopeLifetime
Automatic auto (rarely used) Stack Garbage Block (local) Within the block
External extern Data Segment Zero File (global) Entire program
Static static Data Segment Zero Block or File Entire program
Register register CPU Register (hint) Garbage Block (local) Within the block

Scope Rules

  • Block Structure (Local Scope): A variable declared inside a block { ... } is only accessible within that block.
  • File Scope (Global Scope): A variable declared outside all functions is global and accessible to all functions in that file.

Header Files

Files (e.g., stdio.h, math.h) containing function prototypes and definitions that can be included in our program using #include.

2.4 Recursion in C

Recursion is a process where a function calls itself. A recursive function must have two parts:

  1. Base Case: A condition that stops the recursion.
  2. Recursive Step: The part of the function that calls itself, moving closer to the base case.

Problem Solving: Factorial

long factorial(int n) {
    // 1. Base Case
    if (n == 0 || n == 1) {
        return 1;
    }
    // 2. Recursive Step
    else {
        return n * factorial(n - 1);
    }
}
Risk: If you forget the base case or never reach it, you will get a stack overflow error.

2.5 The C Preprocessor

The preprocessor is a program that processes your source code before it is passed to the compiler. Its directives start with #.

  • #include: Pastes the content of a header file into your code.
  • #define: Creates a macro, which is a fragment of code that is given a name.
    • As a constant: #define PI 3.14159
    • As a function-like macro: #define SQUARE(x) (x * x)
Always wrap macro arguments in parentheses to avoid operator precedence errors: #define SQUARE(x) ((x) * (x)).