Learning Objectives
- Understand the concept and importance of functions in C
- Learn function declaration, definition, and calling
- Master parameter passing techniques
- Understand return values and return types
- Explore scope and lifetime of variables
- Learn about recursive functions
- Apply functions with arrays and strings
1. Introduction to Functions
What is a Function?
A function is a self-contained block of code that performs a specific task. Functions are the building blocks of C programs that help in:
- Code Reusability: Write once, use multiple times
- Modularity: Break complex problems into smaller parts
- Maintainability: Easier to debug and modify
- Readability: Makes code more organized and understandable
Key Point: Functions help us implement the "Divide and Conquer" approach in programming, where we solve a large problem by breaking it down into smaller, manageable sub-problems.
Types of Functions
| Type |
Description |
Examples |
| Library Functions |
Pre-defined functions provided by C |
printf(), scanf(), strlen(), strcpy() |
| User-defined Functions |
Functions created by the programmer |
add(), factorial(), display() |
2. Function Syntax and Structure
General Function Syntax:
return_type function_name(parameter_list) {
return value;
}
Components of a Function
- Return Type: Data type of the value returned (int, float, char, void)
- Function Name: Identifier used to call the function
- Parameter List: Input values (optional)
- Function Body: Code that performs the task
- Return Statement: Returns a value to the caller (optional for void)
Simple Function Example:
#include <stdio.h>
int add(int a, int b);
int main() {
int result = add(5, 3);
printf("Sum = %d\n", result);
return 0;
}
int add(int a, int b) {
return a + b;
}
Output: Sum = 8
3. Parameters and Arguments
Function Categories Based on Parameters and Return Values
| Category |
Parameters |
Return Value |
Example |
| No parameters, no return |
None |
void |
void display() |
| No parameters, with return |
None |
Any type |
int getNumber() |
| With parameters, no return |
Yes |
void |
void print(int x) |
| With parameters, with return |
Yes |
Any type |
int multiply(int a, int b) |
Examples of Different Function Types:
#include <stdio.h>
void greet() {
printf("Hello, World!\n");
}
int getCurrentYear() {
return 2024;
}
void displaySquare(int num) {
printf("Square of %d is %d\n", num, num * num);
}
float calculateArea(float radius) {
return 3.14159 * radius * radius;
}
int main() {
greet();
int year = getCurrentYear();
displaySquare(5);
float area = calculateArea(2.5);
printf("Current year: %d\n", year);
printf("Area of circle: %.2f\n", area);
return 0;
}
Output:
Hello, World!
Square of 5 is 25
Current year: 2024
Area of circle: 19.63
Parameter Passing Methods
1. Call by Value (Pass by Value)
In this method, the actual values of arguments are copied to function parameters. Changes made to parameters inside the function do not affect the original variables.
#include <stdio.h>
void modifyValue(int x) {
x = x + 10;
printf("Inside function: x = %d\n", x);
}
int main() {
int num = 5;
printf("Before function call: num = %d\n", num);
modifyValue(num);
printf("After function call: num = %d\n", num);
return 0;
}
Output:
Before function call: num = 5
Inside function: x = 15
After function call: num = 5
2. Call by Reference (Pass by Reference)
In this method, the address of variables is passed to function parameters using pointers. Changes made inside the function affect the original variables.
#include <stdio.h>
void modifyValue(int *x) {
*x = *x + 10;
printf("Inside function: *x = %d\n", *x);
}
int main() {
int num = 5;
printf("Before function call: num = %d\n", num);
modifyValue(&num);
printf("After function call: num = %d\n", num);
return 0;
}
Output:
Before function call: num = 5
Inside function: *x = 15
After function call: num = 15
4. Functions with Arrays and Strings
Functions with Arrays
When passing arrays to functions, the array name acts as a pointer to the first element. The size of the array is usually passed as a separate parameter.
Array Processing Functions:
#include <stdio.h>
void displayArray(int arr[], int size) {
printf("Array elements: ");
for(int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int arraySum(int arr[], int size) {
int sum = 0;
for(int i = 0; i < size; i++) {
sum += arr[i];
}
return sum;
}
int findMax(int arr[], int size) {
int max = arr[0];
for(int i = 1; i < size; i++) {
if(arr[i] > max) {
max = arr[i];
}
}
return max;
}
int main() {
int numbers[] = {10, 25, 3, 48, 17, 9, 33};
int size = sizeof(numbers) / sizeof(numbers[0]);
displayArray(numbers, size);
int total = arraySum(numbers, size);
int maximum = findMax(numbers, size);
printf("Sum of elements: %d\n", total);
printf("Maximum element: %d\n", maximum);
return 0;
}
Output:
Array elements: 10 25 3 48 17 9 33
Sum of elements: 145
Maximum element: 48
Functions with Strings
String Processing Functions:
#include <stdio.h>
int stringLength(char str[]) {
int length = 0;
while(str[length] != '\0') {
length++;
}
return length;
}
void reverseString(char str[]) {
int length = stringLength(str);
for(int i = 0; i < length/2; i++) {
char temp = str[i];
str[i] = str[length-1-i];
str[length-1-i] = temp;
}
}
int countVowels(char str[]) {
int count = 0;
for(int i = 0; str[i] != '\0'; i++) {
if(str[i] == 'a' || str[i] == 'e' || str[i] == 'i' ||
str[i] == 'o' || str[i] == 'u' ||
str[i] == 'A' || str[i] == 'E' || str[i] == 'I' ||
str[i] == 'O' || str[i] == 'U') {
count++;
}
}
return count;
}
int main() {
char text[] = "Programming";
printf("Original string: %s\n", text);
printf("Length: %d\n", stringLength(text));
printf("Vowel count: %d\n", countVowels(text));
reverseString(text);
printf("Reversed string: %s\n", text);
return 0;
}
Output:
Original string: Programming
Length: 11
Vowel count: 3
Reversed string: gnimmargorP
5. Recursive Functions
What is Recursion?
Recursion is a programming technique where a function calls itself to solve a problem. Every recursive function must have:
- Base Case: A condition that stops the recursion
- Recursive Case: The function calling itself with modified parameters
Important: Without a proper base case, recursive functions will run infinitely, causing a stack overflow error.
Factorial Calculation using Recursion:
#include <stdio.h>
long long factorial(int n) {
if(n == 0 || n == 1) {
return 1;
}
else {
return n * factorial(n - 1);
}
}
int main() {
int num = 5;
printf("%d! = %lld\n", num, factorial(num));
return 0;
}
Output: 5! = 120
Fibonacci Series using Recursion:
#include <stdio.h>
int fibonacci(int n) {
if(n == 0) return 0;
if(n == 1) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
void printFibonacci(int terms) {
printf("Fibonacci Series: ");
for(int i = 0; i < terms; i++) {
printf("%d ", fibonacci(i));
}
printf("\n");
}
int main() {
printFibonacci(10);
return 0;
}
Output: Fibonacci Series: 0 1 1 2 3 5 8 13 21 34
Recursion vs Iteration
| Aspect |
Recursion |
Iteration |
| Memory Usage |
Higher (function call stack) |
Lower (variables only) |
| Speed |
Slower (function call overhead) |
Faster |
| Code Readability |
More readable for some problems |
Less readable for complex problems |
| Stack Overflow Risk |
Yes (for deep recursion) |
No |
6. Scope and Lifetime of Variables
Variable Scope
Scope determines where in the program a variable can be accessed.
| Scope Type |
Description |
Lifetime |
| Local Variables |
Declared inside functions |
Function execution time |
| Global Variables |
Declared outside all functions |
Entire program execution |
| Formal Parameters |
Function parameters |
Function execution time |
Variable Scope Example:
#include <stdio.h>
int globalVar = 100;
void function1(int param) {
int localVar = 10;
printf("Inside function1:\n");
printf("Global variable: %d\n", globalVar);
printf("Local variable: %d\n", localVar);
printf("Parameter: %d\n", param);
globalVar = 200;
}
void function2() {
int localVar = 20;
printf("Inside function2:\n");
printf("Global variable: %d\n", globalVar);
printf("Local variable: %d\n", localVar);
}
int main() {
int localVar = 30;
printf("In main function:\n");
printf("Global variable: %d\n", globalVar);
printf("Local variable: %d\n", localVar);
function1(50);
function2();
printf("Back in main:\n");
printf("Global variable: %d\n", globalVar);
return 0;
}
Output:
In main function:
Global variable: 100
Local variable: 30
Inside function1:
Global variable: 100
Local variable: 10
Parameter: 50
Inside function2:
Global variable: 200
Local variable: 20
Back in main:
Global variable: 200
Storage Classes
| Storage Class |
Keyword |
Scope |
Lifetime |
Initial Value |
| Automatic |
auto |
Local |
Function execution |
Garbage value |
| Register |
register |
Local |
Function execution |
Garbage value |
| Static |
static |
Local/Global |
Program execution |
0 or NULL |
| External |
extern |
Global |
Program execution |
0 or NULL |
Static Variables Example:
#include <stdio.h>
void counter() {
static int count = 0;
count++;
printf("Function called %d times\n", count);
}
int main() {
for(int i = 0; i < 5; i++) {
counter();
}
return 0;
}
Output:
Function called 1 times
Function called 2 times
Function called 3 times
Function called 4 times
Function called 5 times
7. Advanced Function Concepts
Function Pointers
Function pointers are variables that store the address of functions. They enable dynamic function calls and callback mechanisms.
Function Pointer Example:
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
int main() {
int (*operation)(int, int);
operation = add;
printf("Addition: %d\n", operation(5, 3));
operation = multiply;
printf("Multiplication: %d\n", operation(5, 3));
return 0;
}
Output:
Addition: 8
Multiplication: 15
Math Library Functions
C provides various mathematical functions in the math.h library:
Using Math Library Functions:
#include <stdio.h>
#include <math.h>
int main() {
double x = 16.0, y = 2.5;
printf("sqrt(%.1f) = %.2f\n", x, sqrt(x));
printf("pow(%.1f, %.1f) = %.2f\n", x, y, pow(x, y));
printf("sin(90 degrees) = %.2f\n", sin(90 * 3.14159/180));
printf("log(%.1f) = %.2f\n", x, log(x));
printf("ceil(%.1f) = %.0f\n", y, ceil(y));
printf("floor(%.1f) = %.0f\n", y, floor(y));
return 0;
}
Output:
sqrt(16.0) = 4.00
pow(16.0, 2.5) = 128.00
sin(90 degrees) = 1.00
log(16.0) = 2.77
ceil(2.5) = 3
floor(2.5) = 2
8. Practical Programming Problems
Problem 1: Calculator using Functions
#include <stdio.h>
float add(float a, float b) { return a + b; }
float subtract(float a, float b) { return a - b; }
float multiply(float a, float b) { return a * b; }
float divide(float a, float b) {
if(b != 0) return a / b;
else {
printf("Error: Division by zero!\n");
return 0;
}
}
void displayMenu() {
printf("\n=== Calculator ===\n");
printf("1. Addition\n");
printf("2. Subtraction\n");
printf("3. Multiplication\n");
printf("4. Division\n");
printf("5. Exit\n");
printf("Enter your choice: ");
}
int main() {
int choice;
float num1, num2, result;
do {
displayMenu();
scanf("%d", &choice);
if(choice >= 1 && choice <= 4) {
printf("Enter two numbers: ");
scanf("%f %f", &num1, &num2);
switch(choice) {
case 1: result = add(num1, num2); break;
case 2: result = subtract(num1, num2); break;
case 3: result = multiply(num1, num2); break;
case 4: result = divide(num1, num2); break;
}
if(choice != 4 || num2 != 0) {
printf("Result: %.2f\n", result);
}
}
} while(choice != 5);
printf("Thank you for using the calculator!\n");
return 0;
}
Problem 2: Prime Number Functions
#include <stdio.h>
#include <stdbool.h>
bool isPrime(int n) {
if(n <= 1) return false;
if(n <= 3) return true;
if(n % 2 == 0 || n % 3 == 0) return false;
for(int i = 5; i * i <= n; i += 6) {
if(n % i == 0 || n % (i + 2) == 0) {
return false;
}
}
return true;
}
void printPrimesInRange(int start, int end) {
printf("Prime numbers between %d and %d:\n", start, end);
for(int i = start; i <= end; i++) {
if(isPrime(i)) {
printf("%d ", i);
}
}
printf("\n");
}
int countPrimesInRange(int start, int end) {
int count = 0;
for(int i = start; i <= end; i++) {
if(isPrime(i)) count++;
}
return count;
}
int main() {
int start = 10, end = 50;
printPrimesInRange(start, end);
printf("Total prime numbers: %d\n", countPrimesInRange(start, end));
int testNumbers[] = {17, 25, 29, 35, 41};
int size = sizeof(testNumbers) / sizeof(testNumbers[0]);
printf("\nTesting individual numbers:\n");
for(int i = 0; i < size; i++) {
printf("%d is %s\n", testNumbers[i],
isPrime(testNumbers[i]) ? "prime" : "not prime");
}
return 0;
}
Output:
Prime numbers between 10 and 50:
11 13 17 19 23 29 31 37 41 43 47
Total prime numbers: 11
Testing individual numbers:
17 is prime
25 is not prime
29 is prime
35 is not prime
41 is prime
9. Best Practices and Common Mistakes
Best Practices
- Use meaningful function names that describe what the function does
- Keep functions small and focused - one function, one responsibility
- Always declare function prototypes before using them
- Use const for parameters that shouldn't be modified
- Add comments to explain complex logic
- Handle edge cases and error conditions
- Use appropriate return types and parameter types
Common Mistakes to Avoid
- Missing return statements in non-void functions
- Forgetting to declare function prototypes
- Infinite recursion due to missing or incorrect base cases
- Not handling division by zero in mathematical functions
- Modifying array parameters unintentionally
- Incorrect parameter passing (value vs reference)
- Not initializing local variables
Good vs Bad Function Examples:
int func(int x, int y) {
int result;
if(x > 0) {
result = x + y;
}
return result;
}
int calculateSum(int num1, int num2) {
int sum = 0;
sum = num1 + num2;
return sum;
}
10. Summary and Key Takeaways
What We Learned Today
- Functions are reusable blocks of code that perform specific tasks
- Functions can have parameters and return values
- Parameter passing can be by value or by reference
- Arrays and strings are passed to functions as pointers
- Recursion allows functions to call themselves
- Variable scope determines where variables can be accessed
- Static variables retain their values between function calls
- Function pointers enable dynamic function selection
Practice Problems for Students
- Write a function to find the GCD of two numbers using recursion
- Create a function to sort an array using bubble sort
- Implement a function to check if a string is a palindrome
- Write a function to convert decimal to binary
- Create a function to find the second largest element in an array
- Implement a function to count the frequency of each character in a string
- Write a recursive function to solve Tower of Hanoi problem
- Create a function to perform matrix multiplication
Next Lecture Preview
In our next lecture, we'll explore Pointers in C, which will help you understand:
- Memory addresses and pointer variables
- Pointer arithmetic and operations
- Dynamic memory allocation
- Pointers with arrays and functions
- Double pointers and pointer to pointers