Knowlet

Unit 2: Functions, Program Structure, and Recursion

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

A function has three parts:

  1. Function Definition: This is the actual code for the function.
     // return_type function_name(parameter_list) int add(int a, int b) { int sum = a + b; return sum; // Returns a value } void printHello() { // void means it returns nothing printf("Hello"); }
  2. Function Call: This is how you execute the function from main() or another function.
     int main() { int result = add(5, 10); // Accessing 'add' printHello(); // Accessing 'printHello' return 0; }
  3. Function Declaration (Prototype): See below.
  4. Function Prototypes

    A function prototype is a declaration that tells the compiler the function's name, return type, and the data types of its parameters.

    Why? If you define a function *after* main(), the compiler won't know it exists when main() tries to call it. A prototype at the top of the file solves this.

     #include  // Function Prototype int add(int a, int b); void printHello(void); // void in parameters means it takes no arguments int main() { int result = add(5, 10); // Compiler knows 'add' is valid return 0; } // Function Definition int add(int a, int b) { return a + b; } 

    The syllabus also mentions functions returning non-integers, which is standard. A function can return float, char, double, or even struct and void (which returns nothing).

    Passing Arguments (Pass by Value)

    By default, C uses "pass by value" when passing arguments. This means a *copy* of the variable's value is sent to the function. The original variable in main() is not affected.

     void increment(int x) { x = x + 1; // 'x' is a copy printf("Inside function: %d\n", x); // Prints 11 } int main() { int num = 10; increment(num); printf("Inside main: %d\n", num); // Still prints 10 return 0; } 
    To modify the original variable, you must pass a pointer to it (which is covered in Unit 3).

    2. Storage Classes

    Storage classes define the scope (visibility), lifetime (how long it exists), and storage location (e.g., memory, CPU register) of a variable.

    Keyword Storage Default Value Scope Lifetime
    auto Stack (RAM) Garbage Block (local) Within the block
    extern Data Segment (RAM) Zero Global (all files) Entire program
    static Data Segment (RAM) Zero Block (local) or File (global) Entire program
    register CPU Register Garbage Block (local) Within the block
    • auto: This is the default for all local variables. It's rarely written.
    • extern: Used to declare a global variable that is defined in *another* file.
    • static:
      • Inside a function: The variable retains its value between function calls (it's only initialized once).
      • Outside a function (global): The variable is only visible within that specific C file.
    • register: A *request* to the compiler to store the variable in a fast CPU register. The compiler can ignore this. You cannot take the address (&) of a register variable.

    3. Scope Rules and Block Structure

    Scope defines where a variable can be accessed.

    • Block Scope: A variable declared inside a block { ... } is only visible within that block. This includes function bodies and inner blocks.
    • Function Scope: Only used for goto labels.
    • File Scope (Global): A variable declared outside of any function is global and visible to all functions in the file from the point of declaration.

    Header files (e.g., #include ) are files containing function prototypes and definitions that are textually included in your program by the preprocessor.

    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 (to prevent an infinite loop).
    2. Recursive Step: The part that calls the function again, but with a "smaller" problem that moves it closer to the base case.

    Example: Factorial (n!)

     // Problem solving with recursion long factorial(int n) { // Base Case if (n == 0 || n == 1) { return 1; } // Recursive Step else { return n * factorial(n - 1); } } 
    Common Mistake: Forgetting the base case. This will cause the function to call itself forever, leading to a "Stack Overflow" error as the program runs out of memory for function calls.

    5. The C Preprocessor

    The preprocessor is a program that runs *before* the compiler. It modifies the source code based on directives (commands) that start with #.

    • #include: Pastes the content of another file (a header file) into your code.
      #include  // For standard library #include "myheader.h" // For your own files
    • #define: Used to define macros (constants or simple functions).
       // Defines a constant #define PI 3.14159 // Defines a function-like macro #define SQUARE(x) ((x) * (x)) // Usage: float area = PI * r * r; int r = SQUARE(5); // Becomes int r = ((5) * (5));
      Always wrap macro parameters in parentheses (x) to avoid operator precedence errors.

Did this resource help you study?

Share feedback or report issues to help improve this resource.