Unit 3 - Notes
CSE109
Unit 3: User defined functions and Storage classes
1. Introduction to Functions
A function is a self-contained block of statements that perform a coherent task of some kind. Every C program consists of one or more functions, one of which must be main().
Advantages of using functions:
- Modularity: Breaks down a large program into smaller, manageable sub-problems.
- Reusability: Code can be written once and executed multiple times.
- Debugging: Easier to locate and isolate errors.
- Maintenance: Logic changes need to be made in only one place.
2. Components of a Function
To use a function in C, three distinct steps are required:
2.1 Function Prototype (Declaration)
A prototype tells the compiler about the function's name, return type, and the number/type of arguments it accepts. It ensures type checking.
Syntax:
return_type function_name(type arg1, type arg2, ...);
Example:
int add(int a, int b); // Declaration
2.2 Function Definition
This is the actual code block that implements the logic of the function. It consists of the function header and the function body.
Syntax:
return_type function_name(type variable1, type variable2, ...) {
// Body of the function
// Statements
return value; // Optional, depends on return_type
}
2.3 Function Call
This is the statement that invokes the function to perform its task.
Syntax:
function_name(value1, value2, ...);
3. Different Types of Functions
Functions are classified based on arguments and return values.
Type 1: No Arguments and No Return Value
The function takes no input and returns nothing (void). It is usually used for printing or display logic.
void printMessage() {
printf("Hello World");
}
// Call: printMessage();
Type 2: No Arguments but Returns a Value
The function takes no input but performs a calculation and returns the result.
float getPi() {
return 3.14159;
}
// Call: float p = getPi();
Type 3: Arguments but No Return Value
The function accepts data to work on but prints the result or modifies a global state rather than returning a value.
void displaySum(int a, int b) {
printf("Sum is: %d", a + b);
}
// Call: displaySum(5, 10);
Type 4: Arguments and Returns a Value
The most common type. It takes input, processes it, and returns the output.
int multiply(int a, int b) {
return a * b;
}
// Call: int result = multiply(5, 5);
4. Function Calling Types (Parameter Passing)
There are two ways to pass data to a function in C.
4.1 Call by Value
- The value of the actual parameter is copied into the formal parameter.
- Changes made to the parameters inside the function do not affect the argument in the calling function.
- Memory is allocated separately for formal arguments.
Example:
void swap(int x, int y) {
int temp = x;
x = y;
y = temp;
// x and y are swapped here, but not in main
}
4.2 Call by Reference (Address)
- The address (memory location) of the actual parameter is passed to the function.
- Pointers are used to hold the addresses.
- Changes made to the parameters inside the function directly affect the argument in the calling function.
Example:
void swap(int *x, int *y) {
int temp = *x;
*x = *y;
*y = temp;
// The original variables in main are swapped
}
// Call: swap(&a, &b);
5. Math Library Functions
C provides a standard library <math.h> for common mathematical operations. Most of these functions accept and return data of type double.
| Function | Description | Example | Result |
|---|---|---|---|
ceil(x) |
Rounds up to the nearest integer | ceil(3.2) |
4.0 |
floor(x) |
Rounds down to the nearest integer | floor(3.9) |
3.0 |
sqrt(x) |
Calculates square root | sqrt(16.0) |
4.0 |
pow(x, y) |
Calculates x raised to power y | pow(2.0, 3.0) |
8.0 |
abs(x) |
Absolute value (integer) <stdlib.h> |
abs(-5) |
5 |
fabs(x) |
Absolute value (float) | fabs(-5.5) |
5.5 |
sin(x) |
Sine of x (x in radians) | sin(0.0) |
0.0 |
log(x) |
Natural logarithm (base e) | log(10.0) |
2.30 |
6. Recursion
Recursion is a process where a function calls itself directly or indirectly. A recursive function solves a problem by solving a smaller instance of the same problem.
Essential Components:
- Base Case: The condition that stops the recursion to prevent an infinite loop (Stack Overflow).
- Recursive Case: The part where the function calls itself.
Example: Factorial of a number
int factorial(int n) {
if (n == 0) // Base Case
return 1;
else // Recursive Case
return n * factorial(n - 1);
}
Pros vs. Cons:
- Pros: Code is cleaner and more mathematical for problems like Tree traversal or Tower of Hanoi.
- Cons: Uses more memory (stack space) and is generally slower than iteration (loops) due to function call overhead.
7. Scope Rules
7.1 Local Scope
- Variables declared inside a function or block.
- Visibility: Only within the function/block where they are declared.
- Lifetime: Created when the block is entered, destroyed when exited.
7.2 Global Scope
- Variables declared outside all functions (usually at the top of the program).
- Visibility: Accessible by all functions in the program.
- Lifetime: Persists for the entire duration of the program execution.
8. Storage Classes in C
Storage classes determine four aspects of a variable:
- Storage Location: Where the variable is stored (RAM or Register).
- Default Initial Value: Value if not initialized by the user.
- Scope: Where the variable can be accessed.
- Lifetime: How long the variable stays in memory.
There are four storage classes in C:
8.1 Auto (Automatic)
- Keyword:
auto - Storage: RAM (Stack).
- Default Value: Garbage value.
- Scope: Local to the block.
- Lifetime: Within the block.
- Note: All local variables are
autoby default.
void func() {
auto int a = 10; // Same as: int a = 10;
}
8.2 Extern (External)
- Keyword:
extern - Storage: RAM (Data Segment).
- Default Value: Zero.
- Scope: Global (can be accessed in other files if linked).
- Lifetime: Throughout the program execution.
- Usage: Used to tell the compiler that the variable is defined elsewhere (in another file or later in the same file).
extern int x; // Declaration (no memory allocated yet)
int x = 10; // Definition (memory allocated)
8.3 Register
- Keyword:
register - Storage: CPU Registers.
- Default Value: Garbage value.
- Scope: Local to the block.
- Lifetime: Within the block.
- Usage: Used for frequently accessed variables (like loop counters) to speed up execution.
- Constraint: You cannot use the
&(address of) operator on a register variable because it does not have a memory address.
register int i;
for(i = 0; i < 1000; i++) { ... }
8.4 Static
- Keyword:
static - Storage: RAM (Data Segment).
- Default Value: Zero.
- Scope: Local to the block (if inside a function) or Local to the file (if global).
- Lifetime: Throughout the program execution.
- Unique Feature: A static variable preserves its value between function calls. It is initialized only once.
Example of Static:
void counter() {
static int count = 0; // Initialized only once
count++;
printf("%d ", count);
}
int main() {
counter(); // Output: 1
counter(); // Output: 2 (remembers previous value)
counter(); // Output: 3
}
Summary Table of Storage Classes
| Class | Keyword | Storage | Default Value | Scope | Lifetime |
|---|---|---|---|---|---|
| Automatic | auto |
Stack | Garbage | Local | Local |
| External | extern |
Data Segment | Zero | Global | Global |
| Static | static |
Data Segment | Zero | Local | Global |
| Register | register |
CPU Register | Garbage | Local | Local |