#define in C
In C programming, #define is a preprocessor directive that is used to define macros. The
macros are the identifiers defined by #define which are replaced by their value before
compilation. We can define constants and functions like macros using #define. The generics
in C are also implemented using the #define preprocessor directive along with _Generic.
Syntax of C #define
The syntax of #define preprocessor directive in C is:
For Defining Constants
#define MACRO_NAME value
For Defining Expressions
#define MACRO_NAME (expression within brackets)
For Defining Expression with Parameters
Arguments passed in the macros can be used in the expression.
#define MACRO_NAME(ARG1, ARG2,..) (expression within brackets)
Example 1:
In the below example, we have defined a macro ‘PI’ and assigned it a
constant value which we can use later in the program to calculate the area
of a circle.
// C Program to illustrate how to use #define to declare
// constants
#include <stdio.h>
// Defining macros with constant value
#define PI 3.14159265359
int main()
{
int radius = 21;
int area;
// Using macros to calculate area of circle
area = PI * radius * radius;
printf("Area of Circle of radius %d: %d", radius, area);
return 0;
}
Multidimensional Arrays in C – 2D and 3D
Arrays
Syntax
The general form of declaring N-dimensional arrays is shown below:
type arr_name[size1][size2]….[sizeN];
● type: Type of data to be stored in the array.
● arr_name: Name assigned to the array.
● size1, size2,…, sizeN: Size of each dimension.
Three-Dimensional (3D) Array in C
A Three-Dimensional Array or 3D array in C is a collection of
two-dimensional arrays. It can be visualized as multiple 2D arrays stacked
on top of each other.
Declaration of 3D Array in C
We can declare a 3D array with x 2D arrays each having m rows and n
columns using the syntax shown below:
type arr_name[x][m][n];
● type: Type of data to be stored in each element.
● arr_name: name of the array
● x: Number of 2D arrays. (also called depth of the array)
● m: Number of rows in each 2D array.
● n: Number of columns in each 2D array.
3D Array Traversal in C
To access an elements in 3D array, we use three indexes. One for depth,
one for row and one for column.
arr_name[d][i][j]
where, d, i and j are the indexes for depth (representing a specific 2D
array.), the row within that 2D array, and the column within that 2D array
respectively.
To traverse the entire 3D array, you need to use three nested loops: an
outer loop that goes through the depth (or the set of 2D arrays), a middle
loop goes through the rows of each 2D array and at last an inner loop
goes through each element of the current row.
Finding factorial:
// C program to find factorial of given number
#include <stdio.h>
// function to find factorial of given number
int factorial(int n)
{
if (n == 0)
return 1;
return n * factorial(n - 1);
}
int main()
{
int num = 5;
printf("Factorial of %d is %d", num, factorial(num));
return 0;
}
Program to print first N terms of Fibonacci Series:
#include <stdio.h>
// Function to print fibonacci series
void printFib(int n) {
if (n < 1) {
printf("Invalid Number of terms\n");
return;
}
// When number of terms is greater than 0
int prev1 = 1;
int prev2 = 0;
printf("%d ", prev2);
// If n is 1, then we do not need to
// proceed further
if (n == 1)
return;
printf("%d ", prev1);
// Print 3rd number onwards using
// the recursive formula
for (int i = 3; i <= n; i++) {
int curr = prev1 + prev2;
prev2 = prev1;
prev1 = curr;
printf("%d ", curr);
}
}
// Driver code
int main() {
int n = 9;
printFib(n);
return 0;
}
Linear Search Algorithm
In Linear Search, we iterate over all the elements of the array and check if
it the current element is equal to the target element. If we find any
element to be equal to the target element, then return the index of the
current element. Otherwise, if no element is equal to the target element,
then return -1 as the element is not found. Linear search is also known as
sequential search.
// C code to linearly search x in arr[].
#include <stdio.h>
int search(int arr[], int N, int x)
{
for (int i = 0; i < N; i++)
if (arr[i] == x)
return i;
return -1;
}
// Driver code
int main(void)
{
int arr[] = { 2, 3, 4, 10, 40 };
int x = 10;
int N = sizeof(arr) / sizeof(arr[0]);
// Function call
int result = search(arr, N, x);
(result == -1)
? printf("Element is not present in array")
: printf("Element is present at index %d", result);
return 0;
}
Binary Search
Conditions to apply Binary Search Algorithm in a
Data Structure
To apply Binary Search algorithm:
● The data structure must be sorted.
● Access to any element of the data structure should take
constant time.
Below is the step-by-step algorithm for Binary Search:
● Divide the search space into two halves by finding the middle
index “mid”.
● Compare the middle element of the search space with the key.
● If the key is found at middle element, the process is
terminated.
● If the key is not found at middle element, choose which half
will be used as the next search space.
○ If the key is smaller than the middle element,
then the left side is used for next search.
○ If the key is larger than the middle element,
then the right side is used for next search.
● This process is continued until the key is found or the total
search space is exhausted.
// Iterative method
#include <stdio.h>
int binarySearch(int array[], int x, int low, int high)
{
// Repeat until the pointers low and high meet each
// other
while (low <= high) {
int mid = low + (high - low) / 2;
if (array[mid] == x)
return mid;
if (array[mid] < x)
low = mid + 1;
else
high = mid - 1;
}
return -1;
}
int main( )
{
int array[] = { 2, 4, 5, 7, 14, 17, 19, 22 };
int n = sizeof(array) / sizeof(array[0]);
int x = 22;
int result = binarySearch(array, x, 0, n - 1);
if (result == -1)
printf("Not found");
else
printf(" %d", result);
return 0;
}
Recursive code
// C program to implement recursive Binary Search
#include <stdio.h>
// A recursive binary search function. It returns
// location of x in given array arr[low..high] is present,
// otherwise -1
int binarySearch(int arr[], int low, int high, int x)
{
if (high >= low) {
int mid = low + (high - low) / 2;
// If the element is present at the middle
// itself
if (arr[mid] == x)
return mid;
// If element is smaller than mid, then
// it can only be present in left subarray
if (arr[mid] > x)
return binarySearch(arr, low, mid - 1, x);
// Else the element can only be present
// in right subarray
return binarySearch(arr, mid + 1, high, x);
}
// We reach here when element is not
// present in array
return -1;
}
// Driver code
int main()
{
int arr[] = { 2, 3, 4, 10, 40 };
int n = sizeof(arr) / sizeof(arr[0]);
int x = 10;
int result = binarySearch(arr, 0, n - 1, x);
if (result == -1) printf("Element is not present in array");
else printf("Element is present at index %d", result);
return 0;
}
Linear Search Binary Search
In linear search input data need In binary search input data need
not to be in sorted. to be in sorted order.
It is also called half-interval
It is also called sequential search.
search.
The time complexity of linear The time complexity of binary
search O(n). searchO(log n).
Multidimensional array can be Only single dimensional array is
used. used.
Linear search performs equality Binary search performs ordering
comparisons comparisons
It is less complex. It is more complex.
It is very slow process. It is very fast process.
Bubble Sort
Bubble Sort is the simplest sorting algorithm that works by repeatedly
swapping the adjacent elements if they are in the wrong order. This
algorithm is not suitable for large data sets as its average and
worst-case time complexity are quite high.
● We sort the array using multiple passes. After the first pass,
the maximum element goes to end (its correct position). Same
way, after second pass, the second largest element goes to
second last position and so on.
● In every pass, we process only those elements that have
already not moved to correct position. After k passes, the
largest k elements must have been moved to the last k
positions.
● In a pass, we consider remaining elements and compare all
adjacent and swap if larger element is before a smaller
element. If we keep doing this, we get the largest (among the
remaining elements) at its correct position.
// Optimized implementation of Bubble sort
#include <stdbool.h>
#include <stdio.h>
void swap(int* xp, int* yp){
int temp = *xp;
*xp = *yp;
*yp = temp;
}
// An optimized version of Bubble Sort
void bubbleSort(int arr[], int n){
int i, j;
bool swapped;
for (i = 0; i < n - 1; i++) {
swapped = false;
for (j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(&arr[j], &arr[j + 1]);
swapped = true;
}
}
// If no two elements were swapped by inner loop,
// then break
if (swapped == false)
break;
}
}
// Function to print an array
void printArray(int arr[], int size){
int i;
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
}
int main(){
int arr[] = { 64, 34, 25, 12, 22, 11, 90 };
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
printf("Sorted array: \n");
printArray(arr, n);
return 0;
}
Insertion Sort Algorithm
Insertion sort is a simple sorting algorithm that works by iteratively
inserting each element of an unsorted list into its correct position in a
sorted portion of the list. It is like sorting playing cards in your hands.
You split the cards into two groups: the sorted cards and the unsorted
cards. Then, you pick a card from the unsorted group and put it in the
right place in the sorted group.
● We start with the second element of the array as the first
element is assumed to be sorted.
● Compare the second element with the first element if the
second element is smaller then swap them.
● Move to the third element, compare it with the first two
elements, and put it in its correct position
● Repeat until the entire array is sorted.
// C program for implementation of Insertion Sort
#include <stdio.h>
/* Function to sort array using insertion sort */
void insertionSort(int arr[], int n)
{
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
/* A utility function to print array of size n */
void printArray(int arr[], int n)
{
for (int i = 0; i < n; ++i)
printf("%d ", arr[i]);
printf("\n");
}
// Driver method
int main()
{
int arr[] = { 12, 11, 13, 5, 6 };
int n = sizeof(arr) / sizeof(arr[0]);
insertionSort(arr, n);
printArray(arr, n);
return 0;
}
/* This code is contributed by Hritik Shah. */
Selection Sort
Selection Sort is a comparison-based sorting algorithm. It sorts an
array by repeatedly selecting the smallest (or largest) element from the
unsorted portion and swapping it with the first unsorted element. This
process continues until the entire array is sorted.
1. First we find the smallest element and swap it with the first
element. This way we get the smallest element at its correct
position.
2. Then we find the smallest among remaining elements (or
second smallest) and swap it with the second element.
3. We keep doing this until we get all elements moved to correct
position.
// C program for implementation of selection sort
#include <stdio.h>
void selectionSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
// Assume the current position holds
// the minimum element
int min_idx = i;
// Iterate through the unsorted portion
// to find the actual minimum
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[min_idx]) {
// Update min_idx if a smaller element is found
min_idx = j;
}
}
// Move minimum element to its
// correct position
int temp = arr[i];
arr[i] = arr[min_idx];
arr[min_idx] = temp;
}
}
void printArray(int arr[], int n) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
printf("Original array: ");
printArray(arr, n);
selectionSort(arr, n);
printf("Sorted array: ");
printArray(arr, n);
return 0;
}
Square Root of a Number
[Naive Approach] Using a loop
As, we know that square root of a positive integer is always greater than
or equal to one. So we start iterating from 1 and calculate the square of
each number. We continue the iteration until we reach to an integer whose
square is greater than the given integer, then the integer just before it will
be our answer.
// C program to find the square root of
// given integer using a loop
#include <stdio.h>
int floorSqrt(int n) {
// Start iteration from 1 until the
// square of a number exceeds n
int res = 1;
while (res * res <= n) {
res++;
}
// return the largest integer whose
// square is less than or equal to n
return res - 1;
}
int main() {
int n = 11;
printf("%d", floorSqrt(n));
return 0;
}
[Expected Approach] Using Binary Search
The square root of an integer follows a monotonic pattern, because as we
increase any number, it’s square also increases. If the square of a number
is greater than given integer, then square root will definitely exist before
this number. Conversely, if the square of a number is less than or equal to
n, then either this number is the square root or it lies after this number.
Therefore, we can use binary search to find the square root of n. Initial
search space will be 1 to the given integer itself, because square root of
any positive integer always exists within this range.
// C program to find the square root of given integer
// using binary search
#include <stdio.h>
int floorSqrt(int n) {
// Initial search space
int lo = 1, hi = n;
int res = 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
// If square of mid is less than or equal to n
// update the result and search in upper half
if (mid * mid <= n) {
res = mid;
lo = mid + 1;
}
// If square of mid exceeds n,
// search in the lower half
else {
hi = mid - 1;
}
}
return res;
}
int main() {
int n = 11;
printf("%d", floorSqrt(n));
return 0;
}
Array Reverse – Complete Tutorial
Given an array arr[], the task is to reverse the array. Reversing an array
means rearranging the elements such that the first element becomes the
last, the second element becomes second last and so on.
[Naive Approach] Using a temporary array – O(n) Time and O(n)
Space
The idea is to use a temporary array to store the reverse of the array.
● Create a temporary array of same size as the original array.
● Now, copy all elements from original array to the temporary array
in reverse order.
● Finally, copy all the elements from temporary array back to the
original array.
// C Program to reverse an array using temporary array
#include <stdio.h>
#include <stdlib.h>
// function to reverse an array
void reverseArray(int arr[], int n) {
// Temporary array to store elements in reversed order
int temp[n];
// Copy elements from original array to temp in reverse order
for(int i = 0; i < n; i++)
temp[i] = arr[n - i - 1];
// Copy elements back to original array
for(int i = 0; i < n; i++)
arr[i] = temp[i];
}
int main() {
int arr[] = { 1, 4, 3, 2, 6, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
reverseArray(arr, n);
for(int i = 0; i < n; i++)
printf("%d ", arr[i]);
return 0;
}
[Expected Approach – 1] Using Two Pointers – O(n) Time and
O(1) Space
The idea is to maintain two pointers: left and right, such that left points at
the beginning of the array and right points to the end of the array.
While left pointer is less than the right pointer, swap the elements at
these two positions. After each swap, increment the left pointer and
decrement the right pointer to move towards the center of array. This will
swap all the elements in the first half with their corresponding element in
the second half.
// C Program to reverse an array using Two Pointers
#include <stdio.h>
// Function to swap two numbers
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// function to reverse an array
void reverseArray(int arr[], int n) {
// Initialize left to the beginning and right to the end
int left = 0, right = n - 1;
// Iterate till left is less than right
while (left < right) {
// Swap the elements at left and right position
swap(&arr[left], &arr[right]);
// Increment the left pointer
left++;
// Decrement the right pointer
right--;
}
}
int main() {
int arr[] = { 1, 4, 3, 2, 6, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
reverseArray(arr, n);
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
return 0;
}
[Expected Approach – 2] By Swapping Elements – O(n) Time
and O(1) Space
The idea is to iterate over the first half of the array and swap each
element with its corresponding element from the end. So, while iterating
over the first half, any element at index i is swapped with the element at
index (n – i – 1).
// C Program to reverse an array by swapping elements
#include <stdio.h>
// function to reverse an array
void reverseArray(int arr[], int n) {
// Iterate over the first half and for every index i,
// swap arr[i] with arr[n - i - 1]
for (int i = 0; i < n / 2; i++) {
int temp = arr[i];
arr[i] = arr[n - i - 1];
arr[n - i - 1] = temp;
}
}
int main() {
int arr[] = { 1, 4, 3, 2, 6, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
reverseArray(arr, n);
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
return 0;
}
[Alternate Approach] Using Recursion – O(n) Time and O(n)
Space
The idea is to use recursion and define a recursive function that takes a
range of array elements as input and reverses it. Inside the recursive
function,
● Swap the first and last element.
● Recursively call the function with the remaining subarray.
// C Program to reverse an array using Recursion
#include <stdio.h>
// recursive function to reverse an array from l to r
void reverseArrayRec(int arr[], int l, int r) {
if(l >= r)
return;
// Swap the elements at the ends
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
// Recur for the remaining array
reverseArrayRec(arr, l + 1, r - 1);
}
// function to reverse an array
void reverseArray(int arr[], int n) {
reverseArrayRec(arr, 0, n - 1);
}
int main() {
int arr[] = { 1, 4, 3, 2, 6, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
reverseArray(arr, n);
for(int i = 0; i < n; i++)
printf("%d ", arr[i]);
return 0;
}
Reverse String in C
In C, reversing a string means rearranging the characters such that the last
character becomes the first, the second-to-last character becomes the
second, and so on. In this article, we will learn how to reverse string in C.
The most straightforward method to reverse string is by using two
pointers to swap the corresponding characters starting from beginning
and the end while moving the indexes towards each other till they meet
each other.
#include <stdio.h>
#include <string.h>
void rev(char* s) {
// Initialize l and r pointers
int l = 0;
int r = strlen(s) - 1;
char t;
// Swap characters till l and r meet
while (l < r) {
// Swap characters
t = s[l];
s[l] = s[r];
s[r] = t;
// Move pointers towards each other
l++;
r--;
}
}
int main() {
char s[100] = "abcde";
// Reversing s
rev(s);
printf("%s", s);
return 0;
}
Using Recursion
The two-pointer approach can also be implemented using recursion. Just
pass the left and the right index pointer as argument to the recursive
function and move them towards each other in each recursive call.
#include <stdio.h>
#include <string.h>
void rev(char* s, int l, int r) {
// Base case is when l becomes greater than r
if (l >= r) return;
// Swap characters
char t = s[l];
s[l] = s[r];
s[r] = t;
// Recursively call the function with updated
// index pointers
rev(s, l + 1, r - 1);
}
int main() {
char s[100] = "abcde";
rev(s, 0, strlen(s) - 1);
printf("%s", s);
return 0;
}
Using Temporary Array
Store the reverse of string in a temporary array by traversing it from the
back and copying each character to the other array. Then copy the
reversed string from another array into the original string.
#include <stdio.h>
#include <string.h>
void rev(char* s) {
char t[100];
int len = strlen(s);
int i = 0;
// Push all characters of string s onto t
while (len > 0) t[i++] = s[len-- - 1];
t[i] = '\0';
// Copying all characters from t to
// original string s
strcpy(s, t);
}
int main() {
char s[100] = "abcde";
// Reversing string s
rev(s);
printf("%s", s);
return 0;
}
Using Library Function
In C, strrev() defined inside <string.h> can be used to reverse a string. This
function provides the simplest method to reverse the string.
#include <stdio.h>
#include <string.h>
int main() {
char s[] = "abcde";
// Reversing string using strrev()
printf("%s", strrev(s));
return 0;
}
# 🧱 Structures and Unions in C – Theory & Examples
---
##🟦 1. **Structures**
### 📘 **Theory:**
A **structure** in C is a **user-defined data type** that allows grouping
variables of **different types** under one name. It is used to create a
complex data type that models real-world entities (like students,
employees, etc.).
### ✅ **Syntax:**
```c
struct StructureName {
data_type member1;
data_type member2;
...
};
```
---
### 🧪 **Example: Basic Structure**
```c
#include <stdio.h>
struct Student {
int roll;
char name[50];
};
int main() {
struct Student s1 = {101, "Punam"};
printf("Roll: %d, Name: %s\n", [Link], [Link]);
return 0;
}
```
---
##🔁 2. **Accessing and Initializing Structures**
### 🧠 **Theory:**
- **Access members:** using dot operator (`[Link]`)
- **Initialize:** either during declaration or later
```c
struct Student s1 = {101, "Punam"};
[Link] = 102;
strcpy([Link], "Aman");
```
---
##🧩 3. **Nested Structures**
### 📘 **Theory:**
A structure defined **inside another structure** is called a **nested
structure**.
### ✅ **Example:**
```c
struct Date {
int day, month, year;
};
struct Student {
int roll;
struct Date dob;
};
int main() {
struct Student s = {1, {10, 12, 2003}};
printf("DOB: %d/%d/%d\n", [Link], [Link], [Link]);
return 0;
}
```
---
##📚 4. **Array of Structures**
### 📘 **Theory:**
You can declare an array of structures to handle multiple records of the
same type.
### ✅ **Example:**
```c
struct Student {
int roll;
char name[50];
};
int main() {
struct Student students[2] = {{1, "Punam"}, {2, "Ankit"}};
for(int i = 0; i < 2; i++) {
printf("%d %s\n", students[i].roll, students[i].name);
}
return 0;
}
```
---
##🧾 5. **Structures and Functions**
### 📘 **Theory:**
Structures can be passed to functions **by value or by reference (using
pointers)**.
### ✅ **Example:**
```c
void display(struct Student s) {
printf("Roll: %d\n", [Link]);
}
void modify(struct Student *s) {
s->roll = 500;
}
```
---
##🔄 6. **Self-Referential Structure**
### 📘 **Theory:**
A structure that contains a **pointer to itself**. Commonly used in **linked
lists** and trees.
### ✅ **Example:**
```c
struct Node {
int data;
struct Node* next;
};
```
---
##🟨 7. **Union**
### 📘 **Theory:**
A **union** is similar to a structure, but all members **share the same
memory**. Only **one member holds a value at a time**.
### ✅ **Syntax:**
```c
union Data {
int i;
float f;
char str[20];
};
```
### ✅ **Example:**
```c
#include <stdio.h>
union Data {
int i;
float f;
};
int main() {
union Data d;
d.i = 10;
printf("%d\n", d.i);
d.f = 5.5;
printf("%f\n", d.f); // d.i is now overwritten
return 0;
}
```
---
## ⚖️ Structure vs Union
| Feature | Structure | Union |
|------------------|----------------------|---------------------|
| Memory allocation| Separate for each | Shared among all |
| Data access | All at the same time | One at a time |
| Use case | Complex data | Memory saving cases |
---
##🏷️ 8. **typedef**
### 📘 **Theory:**
`typedef` creates a **new alias name** for a data type, especially useful
with structs.
### ✅ **Example:**
```c
typedef struct {
int id;
char name[20];
} Student;
int main() {
Student s1 = {1, "Punam"};
printf("%s\n", [Link]);
return 0;
}
```
Now we don’t need to write `struct` again and again.
---
##🔢 9. **Enumerations (enum)**
### 📘 **Theory:**
An `enum` defines a set of **named integer constants**. It improves
**readability** of code, like for `Status`, `Days`, etc.
### ✅ **Example:**
```c
enum Status { OFF, ON, STANDBY };
int main() {
enum Status s = ON;
printf("%d\n", s); // Outputs: 1
return 0;
}
```
### 🔁 You can also assign custom values:
```c
enum Days { MON = 1, TUE = 10, WED = 100 };
```
---
## 🧠 Summary
| Concept | Description |
|------------------------|-----------------------------------------------------
---|
| `struct` | Groups multiple data types |
| Nested Struct | Struct inside another struct |
| Array of Structs | Multiple records (e.g., list of students) |
| Self-Referential Struct| Used in linked list, trees |
| `union` | One-at-a-time memory usage |
| `typedef` | Type alias for cleaner code |
| `enum` | Named constants (e.g., `RED`, `GREEN`, `BLUE`) |
---
Would you like me to compile this into a PDF next, or generate example
code for each one in separate `.c` files?