Mastering Functions in C: From Library Usage to Custom Implementation
What Is a Function?
In computer science, a function is a self-contained block of code designed to perform a specific task. It encapsulates logic, accepts inputs, and returns outputs—promoting modularity and reusability. In C, functions serve as building blocks for programs, allowing developers to break complex problems into manageable pieces.
Types of Functions
Functions in C fall into two main categories:
- Standard Library Functions: Predefined functions provided by the compiler vendor.
- User-Defined Functions: Custom functions created by programmers to meet specific needs.
Standard Library Functions
These are part of the C standard library and offer common operations like input/output, string manipulation, and mathematical computations.
Common Examples
pow() – Computes powers.
#include <stdio.h>
#include <math.h>
int main() {
double result = pow(4.0, 3.0);
printf("%.f\n", result);
return 0;
}
strcpy() – Copies strings.
#include <stdio.h>
#include <string.h>
int main() {
char dest[20] = {0};
const char* src = "Hello C";
strcpy(dest, src);
printf("%s\n", dest);
return 0;
}
memset() – Fills memory with a byte value.
#include <stdio.h>
#include <string.h>
int main() {
char buffer[10] = "Hello, X";
memset(buffer, 'h', 5);
printf("%s\n", buffer);
return 0;
}
Tip: Use cplusplus.com for comprehensive documentation on standard library functions.
User-Defined Functions
Programmers define their own functions with custom names, parameters, return types, and logic.
Structure
A function consists of:
- Return type
- Function name
- Parameters (formal arguments)
- Function body
When no return value is needed, use void.
Example: Find Maximum of Two Integers
int find_max(int a, int b) {
return (a > b) ? a : b;
}
#include <stdio.h>
int main() {
int x, y;
scanf("%d %d", &x, &y);
printf("Max: %d\n", find_max(x, y));
return 0;
}
Swapping Two Variables
Passing values by value doesn't modify original variables because formal parameters are copies.
To truly swap values, pass addresses using pointers:
void swap_values(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
#include <stdio.h>
int main() {
int num1 = 5, num2 = 10;
printf("Before: %d %d\n", num1, num2);
swap_values(&num1, &num2);
printf("After: %d %d\n", num1, num2);
return 0;
}
Funcsion Declaration vs Definition
- Declaration: Tells the compiler about the function’s name, return type, and parameters. Placed before usage.
- Definition: Contains the actual implementation.
// Declaration
int add_numbers(int x, int y);
int main() {
int a = 3, b = 7;
int sum = add_numbers(a, b);
printf("Sum: %d\n", sum);
return 0;
}
// Definition
int add_numbers(int x, int y) {
return x + y;
}
Parameters: Actual vs Formal
- Actual Parameters (Arguments): Values passed during function call (constants, variables, expressions, or function calls).
- Formal Parameters: Variables defined in the function header. They receive a copy of the actual values.
Modifying formal parameters does not affect the original data unless addresses are passed.
Function Call Mechanisms
- Call by Value: Copies the argument value; changes inside the function don’t affect the caller.
- Call by Reference (Address Passing): Passes the address of the variable; modifications reflect outside the function.
Use call by reference when you need to modify external variables.
Practice Exercises
- Check if a number is prime
#include <stdbool.h>
#include <math.h>
bool is_prime(int n) {
if (n < 2) return false;
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0) return false;
}
return true;
}
- Determine leap year
bool is_leap(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
- Binary Search in Sorted Array
int binary_search(const int arr[], int target, int size) {
int left = 0, right = size - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
Note: Using
left + (right - left) / 2avoids integer overflow compared to(left + right) / 2.
- Increment a Variable Each Call
void increment(int* val) {
(*val)++;
}
// Or return new value
int inc(int val) {
return val + 1;
}
Nested and Chained Function Calls
- Nested Call: One function calls another.
void print_line() {
printf("Hello\n");
}
void print_three() {
for (int i = 0; i < 3; i++)
print_line();
}
- Chained Access: The return value of one function serves as an argument to another.
printf("Length: %d\n", strlen(strcat(buffer, "world")));
Example:
printf("%d", printf("%d", printf("%d", 43)));prints43, then2, then1.
Header Files
Organize reusable declarations in .h files.
// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
bool is_prime(int n);
int binary_search(const int arr[], int target, int size);
#endif
Include in source files via #include "math_utils.h".
This modular approach enhances maintainability and reduces redundancy.