A function is a self-contained block of code that performs a specific task. Using functions makes code modular, reusable, and easier to debug.
A function has three parts:
// 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");
}main() or another function.
int main() {
int result = add(5, 10); // Accessing 'add'
printHello(); // Accessing 'printHello'
return 0;
}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).
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;
}
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:
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.Scope defines where a variable can be accessed.
{ ... } is only visible within that block. This includes function bodies and inner blocks.goto labels.Header files (e.g., #include ) are files containing function prototypes and definitions that are textually included in your program by the preprocessor.
Recursion is a process where a function calls itself. A recursive function must have two parts:
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);
}
}
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));
(x) to avoid operator precedence errors.