Storage Classes in C
Storage Classes in C
Storage Classes in C
In C programming, functions are essential to make the program modular, structured, and
easy to debug. Functions help break large programs into smaller, manageable parts, and can
be reused across different parts of the program.
1. User-Defined Functions
2. Built-in Functions (also called Library Functions)
1. User-Defined Functions
User-defined functions are those that a programmer creates to perform a specific task. These
functions allow code to be reusable, modular, and easier to manage.
Steps Involved:
This tells the compiler about the function name, its return type, and the parameters it accepts.
The declaration typically appears before the main() function.
Syntax:
Example:
b) Function Definition
This is where the actual code of the function is written. The definition includes the function
name, parameters, and the body of the function, which performs the task.
Syntax:
return_type function_name(parameter_type1 parameter1, parameter_type2
parameter2, ...) {
// Function body (the code that performs the task)
return value; // if the return type is not void
}
Example:
The function is invoked (or called) inside another function, usually main(), to perform the task.
When the function is called, control is transferred to the function definition.
Syntax:
function_name(arguments);
Example:
int result = add(5, 10); // Calls the 'add' function with arguments 5 and
10
// Function declaration
int add(int a, int b);
int main() {
int num1 = 5, num2 = 10;
// Function call
int sum = add(num1, num2);
// Function definition
int add(int a, int b) {
return a + b;
}
Syntax:
Example:
printf("Hello, World!\n");
Syntax:
Example:
1. nt num;
2. scanf("%d", &num); // Takes an integer input from the user
3.
Example:
pow(): This function calculates the power of a number. For example, pow(2, 3) gives 8
(2^3).
Syntax:
Example:
1. strlen(): This function returns the length of a string (excluding the null character \
0).
Syntax:
Example:
Syntax:
Example:
char dest[20];
strcpy(dest, "Hello World"); // Copies "Hello World" into dest
1. Time-Saving: These functions are pre-written and optimized, so you don't have to
write them yourself.
2. Reliability: Since they are part of standard libraries, they have been tested
extensively.
3. Ease of Use: Built-in functions make tasks like input/output and mathematical
operations much simpler.
Key Differences Between User-Defined and Built-in Functions
This library provides functions for input and output operations, such as reading from or
writing to the console.
a) printf()
Example:
printf("Hello, World!\n");
printf("The value of x is %d\n", x); // %d formats an integer
b) scanf()
Example:
int x;
scanf("%d", &x); // Reads an integer from the user
c) getchar()
int getchar(void);
Example:
char ch = getchar();
d) putchar()
Example:
putchar('A');
Example:
char str[50];
fgets(str, 50, stdin); // Reads up to 50 characters
f) puts()
Example:
puts("Hello, World!");
a) sqrt()
Example:
double result = sqrt(16.0); // result = 4.0
b) pow()
Example:
double result = pow(2.0, 3.0); // result = 8.0
c) abs()
Example:
int result = abs(-5); // result = 5
d) ceil()
Example:
double result = ceil(3.2); // result = 4.0
e) floor()
Purpose: Returns the largest integer less than or equal to a floating-point number.
Syntax:
Example:
double result = floor(3.8); // result = 3.0
Example:
double result = sin(3.14159 / 2); // result = 1.0 (approximation of
sin(90 degrees))
a) strlen()
Purpose: Returns the length of a string (excluding the null terminator \0).
Syntax:
Example:
int len = strlen("Hello"); // len = 5
b) strcpy()
Example:
char dest[20];
strcpy(dest, "Hello");
c) strcat()
Example:
char str1[20] = "Hello, ";
strcat(str1, "World!"); // str1 becomes "Hello, World!"
d) strcmp()
Purpose: Compares two strings. Returns 0 if they are equal, a negative value if the
first string is less than the second, and a positive value if the first string is greater.
Syntax:
Example:
int result = strcmp("abc", "abc"); // result = 0 (strings are equal)
Example:
strncpy(dest, "Hello", 3); // Copies "Hel" into dest
This library provides functions for memory allocation, random number generation, and other
utility functions.
Example:
int* arr = (int*) malloc(10 * sizeof(int)); // Allocates memory for
10 integers
free(arr); // Frees the allocated memory
b) exit()
Example:
if (error) {
exit(1); // Non-zero value indicates an error
}
c) rand(), srand()
int rand(void);
void srand(unsigned int seed);
Example:
srand(time(0)); // Seed the random number generator
int random_number = rand();
Example:
if (isalpha('A')) {
// Character is alphabetic
}
b) toupper(), tolower()
Example:
char upper = toupper('a'); // upper = 'A'
Storage Classes in C
In C, storage classes define the scope (visibility), lifetime (duration), and linkage
(accessibility) of variables and functions within a program. They determine where a variable
is stored, how long it stays in memory, and which parts of the program can access it. There
are four primary storage classes in C:
1. auto
2. register
3. static
4. extern
Each storage class modifies the behavior of variables in terms of scope, lifetime, and
linkage. Let’s go over each one in detail.
Scope: Local to the block where the variable is defined (i.e., function or loop).
Lifetime: Exists only during the execution of the block (local to the function).
Linkage: None (local to the block where it's defined).
The auto keyword is the default storage class for all local variables inside a function. Even if
you don't specify auto, the variables declared inside a function have automatic storage.
Example:
#include <stdio.h>
int main() {
auto int num = 10; // 'auto' is optional here
printf("num = %d\n", num);
return 0;
}
Output:
num = 10
In modern C, you rarely need to use auto explicitly because it’s automatically applied to
local variables.
The register keyword is used for variables that require quick access, like loop counters.
However, the actual decision to store the variable in a register is made by the compiler.
Example:
#include <stdio.h>
int main() {
register int i; // Request to store 'i' in a register
for (i = 0; i < 5; i++) {
printf("%d ", i);
}
return 0;
}
Output:
0 1 2 3 4
Note: Accessing the address of a register variable (e.g., with the & operator) is not allowed.
Scope:
o Inside a function: The variable is local to the function (not visible outside), but
it retains its value between function calls.
o Outside a function (global variable): The variable is visible only in the file
where it is defined.
Lifetime: Exists throughout the program's execution (even if defined inside a
function).
Linkage:
o Internal linkage if defined outside a function (visible only in the file).
o No linkage for variables inside a function (only within the function).
The static keyword preserves the value of a variable between function calls.
void count_calls() {
static int count = 0; // Static variable, retains value across calls
count++;
printf("This function is called %d times\n", count);
}
int main() {
count_calls();
count_calls();
count_calls();
return 0;
}
Output:
void display() {
printf("Global variable: %d\n", global_var);
}
int main() {
display();
return 0;
}
Output:
Global variable: 10
In this case, global_var is not accessible outside this file, providing encapsulation.
int main() {
printf("num = %d\n", num);
return 0;
}
File2.c:
#include <stdio.h>
void display() {
printf("num from another file = %d\n", num);
}
Both files share the same num variable. You can use num in both File1.c and File2.c.
Storage Classes:
auto is the default storage class for local variables and doesn’t need to be explicitly
mentioned.
register is a suggestion to store the variable in a register for faster access, but it’s up
to the compiler.
static helps preserve the value of a local variable between function calls or restricts
the visibility of a global variable to a single file.
extern allows sharing variables across multiple files in larger programs.
Functions in C Language: Detailed Explanation with Examples
1. Call by Value
2. Passing Arrays to Functions (Call by Reference)
3. Recursion
1. Call by Value
In call by value, when a function is called, the actual values of the arguments are passed to
the function. Changes made to the parameters inside the function do not affect the original
values.
Example:
#include <stdio.h>
int main() {
int x = 10, y = 20;
printf("Before function call: x = %d, y = %d\n", x, y);
swap(x, y);
printf("After function call: x = %d, y = %d\n", x, y);
return 0;
}
Output:
Before function call: x = 10, y = 20
Inside function: a = 20, b = 10
After function call: x = 10, y = 20
Explanation:
In the function swap(), values of x and y are copied into a and b. Inside the function,
swapping occurs, but it does not affect x and y in main(). This is because the values are
passed by value, and the function works on copies of the original values.
When an array is passed to a function, the address of the array is passed, not the actual
elements. This is often referred to as call by reference because the function operates on the
actual data stored in the array.
Example:
#include <stdio.h>
int main() {
int numbers[] = {1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]);
printf("Before modification:\n");
for(int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
modifyArray(numbers, size);
printf("After modification:\n");
for(int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}
Output:
Before modification:
1 2 3 4 5
After modification:
2 4 6 8 10
Explanation:
The array numbers[] is passed to the function modifyArray(). Inside the function, we
modify the elements of the array by doubling them. Since arrays are passed by
reference, the modifications made in the function reflect in the original array.
3. Recursion
Recursion is a technique where a function calls itself to solve a problem. Recursive functions
are useful for problems that can be broken down into smaller, similar problems (e.g.,
calculating factorial, Fibonacci sequence, etc.).
int main() {
int number = 5;
int result = factorial(number);
printf("Factorial of %d is %d\n", number, result);
return 0;
}
Output:
Factorial of 5 is 120
Explanation:
The function factorial() calls itself with a decremented value of n until it reaches the base case
(n == 0). This example shows how recursion simplifies a problem by repeatedly breaking it
into smaller parts until it reaches a solvable base case.
int fibonacci(int n) {
if (n == 0) {
return 0; // Base case 1: Fibonacci of 0 is 0
} else if (n == 1) {
return 1; // Base case 2: Fibonacci of 1 is 1
} else {
return fibonacci(n - 1) + fibonacci(n - 2); // Recursive call
}
}
int main() {
int terms = 10;
printf("Fibonacci Series up to %d terms:\n", terms);
for (int i = 0; i < terms; i++) {
printf("%d ", fibonacci(i));
}
printf("\n");
return 0;
}
Output:
Fibonacci Series up to 10 terms:
0 1 1 2 3 5 8 13 21 34
Explanation:
The fibonacci() function recursively calculates the Fibonacci numbers by breaking the
problem down into smaller subproblems until it reaches the base cases (Fibonacci of 0
and 1). The function calls itself twice to generate the series.
Key Differences Between Call by Value and Call by Reference (Passing
Arrays)