C ProgrammingUnit 610 min read
Functions in C: Declaration, Definition, Calling, Types, and Applications
Unit 6 of C Programming: Explores functions as modular building blocks—how to define, declare, call, and use them (including recursion, scope, storage classes, and passing arrays/strings)—with practical examples, code traces, and real-world ties to apps like Daraz and eSewa.
Why Functions?
Functions are reusable blocks of code that perform a specific task. They improve modularity, readability, and maintainability by breaking programs into smaller, manageable parts.
1. Function Basics
Definition
A function is a named sequence of statements that performs a task and optionally returns a value.
Syntax
return_type function_name(parameter_list) {
// statements
return value; // optional
}
Key Components
- Return Type: Specifies the type of value returned (e.g.,
int,void). - Function Name: Must follow C naming rules (no spaces, starts with a letter).
- Parameters: Inputs passed to the function (optional).
- Body: Statements executed when the function is called.
- Return Statement: Optional; exits the function and returns a value.
2. Function Declaration vs. Definition
| Declaration | Definition |
|---|---|
| Tells the compiler the function exists. | Provides the actual code. |
Syntax: return_type function_name(parameters); |
Syntax: Full function body. |
Example: int sum(int a, int b); |
Example: int sum(int a, int b) { return a + b; } |
3. Calling a Function
Functions are called using their name followed by arguments (if any). Example:
#include <stdio.h>
int add(int x, int y) {
return x + y;
}
int main() {
int result = add(5, 3); // Function call
printf("Result: %d\n", result);
return 0;
}
Output:
Result: 8
4. Types of Functions
(a) Library Functions
Predefined functions in C (e.g., printf, scanf from <stdio.h>).
(b) User-Defined Functions
Functions written by the programmer (e.g., add, factorial).
(c) Recursive Functions
A function calls itself to solve smaller instances of the same problem. Example: Factorial using recursion.
flowchart TD A["main()"] --> B["call factorial(5)"] B --> C["factorial(5) calls factorial(4)"] C --> D["factorial(4) calls factorial(3)"] D --> E["factorial(3) calls factorial(2)"] E --> F["factorial(2) calls factorial(1)"] F --> G["factorial(1) returns 1"] G -->|"1"| H["factorial(2) returns 2*1"] H -->|"2"| I["factorial(3) returns 3*2"] I -->|"6"| J["factorial(4) returns 4*6"] J -->|"24"| K["factorial(5) returns 5*24"] K --> L["main() prints 120"]
Code Example:
#include <stdio.h>
int factorial(int n) {
if (n == 0) return 1;
return n * factorial(n - 1);
}
int main() {
printf("Factorial of 5: %d\n", factorial(5));
return 0;
}
Trace Table:
| Step | Function Call | Return Value |
|---|---|---|
| 1 | factorial(5) |
- |
| 2 | factorial(4) |
- |
| 3 | factorial(3) |
- |
| 4 | factorial(2) |
- |
| 5 | factorial(1) |
1 |
| 6 | factorial(2) |
2 |
| 7 | factorial(3) |
6 |
| 8 | factorial(4) |
24 |
| 9 | factorial(5) |
120 |
5. Scope and Storage Classes
(a) Local Variables
- Declared inside a function.
- Accessible only within that function.
- Example:
int add(int a, int b) { int sum = a + b; // Local variable return sum; }
(b) Global Variables
- Declared outside all functions.
- Accessible throughout the program.
- Example:
int global_var = 10; // Global variable int main() { printf("%d\n", global_var); return 0; }
(c) Storage Classes
| Storage Class | Scope | Lifetime | Example |
|---|---|---|---|
auto |
Local | Function call | int x; |
static |
Local/Global | Program lifetime | static int x; |
extern |
Global | Program lifetime | extern int y; |
register |
Local | Function call | register int x; |
6. Passing Arguments to Functions
(a) Pass by Value
- A copy of the variable is passed.
- Changes inside the function do not affect the original.
- Example:
void increment(int x) { x++; // Does not affect original 'a' } int main() { int a = 5; increment(a); printf("%d\n", a); // Output: 5 return 0; }
(b) Pass by Reference (Using Pointers)
- The address of the variable is passed.
- Changes inside the function affect the original.
- Example:
void increment(int *x) { (*x)++; // Modifies original 'a' } int main() { int a = 5; increment(&a); printf("%d\n", a); // Output: 6 return 0; }
7. Returning Arrays/Strings from Functions
(a) Returning an Array
- Arrays cannot be returned directly; use pointers.
- Example:
int* getArray() { int arr[] = {1, 2, 3}; return arr; // Returns pointer to array } int main() { int *ptr = getArray(); printf("%d\n", ptr[1]); // Output: 2 return 0; }
(b) Returning a String
- Strings are arrays of characters; return their address.
- Example:
char* greet() { char msg[] = "Hello"; return msg; // Returns pointer to string } int main() { char *str = greet(); printf("%s\n", str); // Output: Hello return 0; }
8. Variable Arguments (Varargs)
- Functions that accept a variable number of arguments.
- Use
stdarg.hheader. - Example:
#include <stdio.h> #include <stdarg.h> int sum(int count, ...) { va_list args; va_start(args, count); int total = 0; for (int i = 0; i < count; i++) { total += va_arg(args, int); } va_end(args); return total; } int main() { printf("%d\n", sum(3, 1, 2, 3)); // Output: 6 return 0; }
9. Inline Functions
- Functions expanded at compile time to avoid function call overhead.
- Use
__inline__orinlinekeyword. - Example:
inline int square(int x) { return x * x; } int main() { printf("%d\n", square(5)); // Compiled as `5 * 5` return 0; }
10. Macro vs. Function
| Macro | Function |
|---|---|
| Text substitution. | Actual code execution. |
Defined using #define. |
Defined using return_type. |
| No type checking. | Type checking. |
Example: #define PI 3.14 |
Example: float circleArea(float r) { return PI * r * r; } |
In the Real World
Daraz Order Processing
- Idea: Functions handle different steps (e.g.,
calculateShippingCost(),updateInventory()). - How: Each function modularizes a task (e.g.,
processPayment()for checkout).
- Idea: Functions handle different steps (e.g.,
eSewa Transaction Validation
- Idea: Functions validate user input (e.g.,
isValidAmount(),checkBalance()). - Worked Example: If a user inputs ₹1000,
isValidAmount(1000)returnstrueif the amount is within limits.
- Idea: Functions validate user input (e.g.,
Pathao Ride Routing
- Idea: Functions calculate routes (e.g.,
findShortestPath(),estimateFare()). - Real Tie: Uses Dijkstra’s algorithm (implemented as functions) to compute the fastest route between two points.
- Idea: Functions calculate routes (e.g.,
Exam Tip
- Focus Areas:
- Function Declaration/Definition: Always include return type and parameter list.
- Recursion: Practice tracing recursive calls (e.g., factorial, Fibonacci).
- Passing Arguments: Differentiate pass-by-value vs. pass-by-reference.
- Varargs: Know how to use
va_list,va_start, andva_arg.
- Common Mistakes:
- Forgetting to return a value in non-
voidfunctions. - Incorrectly passing arrays (use pointers).
- Misusing global/local variables.
- Forgetting to return a value in non-
- Practice Questions:
- Write a function to reverse a string using recursion.
- Implement a function to sort an array (e.g., bubble sort).
- Create a program with multiple functions handling different tasks (e.g.,
calculateArea(),printMenu()).
Worked Example: Sorting an Array Using Functions
Task: Sort an array of 10 integers in ascending order using a function.
#include <stdio.h>
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main() {
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
printf("Sorted array: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
return 0;
}
Output:
Sorted array: 11 12 22 25 34 64 90
Visuals
Figure 1: Function Call Stack Trace
flowchart TD
A["main()"] --> B["call factorial(3)"]
B --> C["factorial(3) calls factorial(2)"]
C --> D["factorial(2) calls factorial(1)"]
D --> E["factorial(1) returns 1"]
E --> F["factorial(2) returns 2"]
F --> G["factorial(3) returns 6"]
G --> H["main() prints 6"]Figure 2: Pass by Value vs. Pass by Reference
flowchart TD
A["Original Array: [10, 20, 30]"] --> B["Pass by Value"]
B --> C["Function Receives Copy: [10, 20, 30]"]
C --> D["Modification Inside Function: [100, 20, 30]"]
D --> E["Original Array Unchanged: [10, 20, 30]"]
A --> F["Pass by Reference"]
F --> G["Function Receives Address"]
G --> H["Modification Inside Function: [100, 20, 30]"]
H --> I["Original Array Modified: [100, 20, 30]"]Summary Table
| Concept | Key Points |
|---|---|
| Function Declaration | Syntax: return_type func_name(parameters); |
| Recursion | Function calls itself; use base case to stop recursion. |
| Pass by Value | Copy of variable is passed; original unchanged. |
| Pass by Reference | Address of variable is passed; original modified. |
| Varargs | Use stdarg.h for variable arguments. |
| Inline Functions | Expanded at compile time for efficiency. |
Based on the TU BIT syllabus for C Programming (BIT102), unit 6.
Discussion
Loading…