Experiment No.
– 1
Study of hardware and software requirements of different operating systems
(UNIX,LINUX,WINDOWS XP, WINDOWS7/8
1. UNIX: Hardware Requirements
Processor: Minimum of 1 GHz processor
Memory (RAM): Minimum of 1 GB RAM
Hard Disk Space: Minimum of 10 GB free disk space
Software Requirements
UNIX-compatible operating system, such as Sun Solaris, IBM AIX, HP-UX, etc.
Compiler and development tools (optional)
X Window System for graphical user interface (optional)
Networking tools for network communication (optional)
2. Linux: Hardware Requirements:
Processor: Minimum of 1 GHz processor
Memory (RAM): Minimum of 1 GB RAM (2 GB or more recommended for better
performance)
Hard Disk Space: Minimum of 10 GB free disk space (20 GB or more recommended for
better performance)
Software Requirements
Linux distribution, such as Ubuntu, Fedora, CentOS, Debian, etc.
Graphical user interface (optional)
Compiler and development tools (optional)
Networking tools for network communication (optional)
3. Windows XP: Hardware Requirements:
Processor: Minimum of Pentium 233 MHz processor (300 MHz or higher recommended)
Memory (RAM): Minimum of 64 MB RAM (128 MB or higher recommended)
Hard Disk Space: Minimum of 1.5 GB free disk space
Software Requirements:
Windows XP operating system
DirectX 9 graphics device with WDDM driver (optional for graphical user interface)
Networking tools for network communication (optional)
4. Windows 7/8: Hardware Requirements:
Processor: Minimum of 1 GHz processor (1 GHz or higher recommended)
Memory (RAM): Minimum of 1 GB RAM (2 GB or higher recommended)
Hard Disk Space: Minimum of 16 GB free disk space (20 GB or higher recommended)
Software Requirements:
Windows 7 or Windows 8 operating system
DirectX 9 graphics device with WDDM 1.0 or higher driver (optional for graphical user
interface)
Networking tools for network communication (optional)
Experiment No. – 2
Execute various UNIX system calls for
i. Process management
ii. File management
iii. Input/output Systems calls
i. Process Management
1. fork(): Used to create a new process by duplicating the current process.
2. exec(): Replaces the current process image with a new process image.
3. wait(): Makes a parent process wait until all its child processes have terminated.
4. exit(): Terminates a process and returns an exit status to the parent process.
5. kill(): Sends a signal (e.g., terminate, interrupt) to a process.
#include <stdio.h>
#include <unistd.h> ----------- for fork() and sleep() function
#include <sys/types.h>
int main() {
pid_t pid;
// Create a new process
pid = fork();
if (pid < 0) {
// Error occurred during fork
perror("Fork failed");
return 1;
} else if (pid == 0) {
// Child process
printf("Hello! I am the child process. My PID is %d\n", getpid());
} else {
// Parent process
printf("Hello! I am the parent process. My PID is %d, and my child's PID is %d\n",
getpid(), pid);
return 0;
ii. File Management
1. open(): Opens a file and returns a file descriptor.
2. read(): Reads data from a file associated with a given file descriptor.
3. write(): Writes data to a file using a file descriptor.
4. close(): Closes an open file descriptor.
5. unlink(): Deletes a file.
#include <stdio.h>
#include <stdlib.h>
// Function to write data to a file
void writeToFile(const char *filename)
FILE *file = fopen(filename, "w"); // Open the file in write mode
if (file == NULL) {
printf("Could not open file for writing\n");
return;}
fprintf(file, "Hello, this is a test file!\n");
fprintf(file, "We are testing file management in C.\n");
fclose(file); // Close the file
printf("Data written to file successfully.\n");
}
// Function to read data from a file
void readFromFile(const char *filename) {
FILE *file = fopen(filename, "r"); // Open the file in read mode
if (file == NULL) {
printf("Could not open file for reading\n");
return;
char ch;
printf("Contents of the file:\n");
while ((ch = fgetc(file)) != EOF) {
putchar(ch); // Print the file contents to the console
fclose(file); // Close the file}
// Function to append data to a file
void appendToFile(const char *filename) {
FILE *file = fopen(filename, "a"); // Open the file in append mode
if (file == NULL) {
printf("Could not open file for appending\n");
return;
fprintf(file, "Appending this new line to the file.\n");
fclose(file); // Close the file
printf("Data appended to file successfully.\n");
}
int main() {
const char *filename = "testfile.txt";
// Writing to a file
writeToFile(filename);
// Reading from the file
readFromFile(filename);
// Appending to the file
appendToFile(filename);
// Reading from the file after appending
readFromFile(filename);
return 0;}
iii. Input/Output System Calls
1. read(): Reads data from a file or input device into a buffer.
2. write(): Writes data from a buffer to a file or output device.
3. lseek(): Moves the file offset pointer to a specified location (useful for random
access).
4. ioctl(): Performs device-specific input/output operations.
5. dup(): Duplicates an existing file descriptor
6. #include <fcntl.h> // For open() flags
7. #include <unistd.h> // For read(), write(), close()
8. #include <stdio.h> // For perror()
9. #include <stdlib.h> // For exit()
10.
11. #define BUFFER_SIZE 1024
12.
13. // Function to read from a file and write to another file using system calls
14. void fileCopyUsingSysCalls(const char *source, const char *destination) {
15. int sourceFile, destFile, bytesRead, bytesWritten;
16. char buffer[BUFFER_SIZE];
17.
18. // Open the source file in read-only mode
19. sourceFile = open(source, O_RDONLY);
20. if (sourceFile == -1) {
21. perror("Error opening source file");
22. exit(1);
23. }
24.
25. // Open the destination file in write-only mode. Create the file if it doesn't exist.
26. destFile = open(destination, O_WRONLY | O_CREAT | O_TRUNC, 0644);
27. if (destFile == -1) {
28. perror("Error opening destination file");
29. close(sourceFile);
30. exit(1);
31. }
32.
33. // Read from the source file and write to the destination file
34. while ((bytesRead = read(sourceFile, buffer, BUFFER_SIZE)) > 0) {
35. bytesWritten = write(destFile, buffer, bytesRead);
36. if (bytesWritten != bytesRead) {
37. perror("Error writing to destination file");
38. close(sourceFile);
39. close(destFile);
40. exit(1);
41. }
42. }
43.
44. if (bytesRead == -1) {
45. perror("Error reading from source file");
46. }
47.
48. // Close both files
49. close(sourceFile);
50. close(destFile);
51.
52. printf("File copied successfully using system calls.\n");
53. }
54.
55. int main() {
56. const char *sourceFile = "source.txt";
57. const char *destinationFile = "destination.txt";
58.
59. // Copy content from source file to destination file
60. fileCopyUsingSysCalls(sourceFile, destinationFile);
61.
62. return 0;
Experiment No. – 3
Implement CPU Scheduling Policies:
i. SJF
ii. Priority
iii. FCFS
iv. Multi-level Queue
1. First-Come-First-Serve (FCFS):
In FCFS, the process that arrives first gets executed first.
FCFS Algorithm:
c
Copy
#include <stdio.h>
typedef struct {
int pid; // Process ID
int arrivalTime;
int burstTime;
int waitingTime;
int turnaroundTime;
} Process;
void findWaitingTime(Process proc[], int n) {
proc[0].waitingTime = 0;
for (int i = 1; i < n; i++) {
proc[i].waitingTime = proc[i - 1].waitingTime + proc[i - 1].burstTime;
}
}
void findTurnaroundTime(Process proc[], int n) {
for (int i = 0; i < n; i++) {
proc[i].turnaroundTime = proc[i].burstTime + proc[i].waitingTime;
}
}
void findAvgTimes(Process proc[], int n) {
int totalWaitingTime = 0, totalTurnaroundTime = 0;
for (int i = 0; i < n; i++) {
totalWaitingTime += proc[i].waitingTime;
totalTurnaroundTime += proc[i].turnaroundTime;
}
printf("Average waiting time: %.2f\n", (float)totalWaitingTime / n);
printf("Average turnaround time: %.2f\n", (float)totalTurnaroundTime / n);
}
void FCFS(Process proc[], int n) {
findWaitingTime(proc, n);
findTurnaroundTime(proc, n);
findAvgTimes(proc, n);
}
int main() {
Process proc[] = {
{1, 0, 5, 0, 0},
{2, 1, 3, 0, 0},
{3, 2, 8, 0, 0},
{4, 3, 6, 0, 0}
};
int n = sizeof(proc) / sizeof(proc[0]);
FCFS(proc, n);
return 0;
}
2. Shortest Job First (SJF):
In SJF, the process with the shortest burst time is executed first.
SJF Algorithm (Non-preemptive):
c
Copy
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int pid; // Process ID
int burstTime;
int waitingTime;
int turnaroundTime;
} Process;
int compare(const void *a, const void *b) {
return ((Process*)a)->burstTime - ((Process*)b)->burstTime;
}
void findWaitingTime(Process proc[], int n) {
proc[0].waitingTime = 0;
for (int i = 1; i < n; i++) {
proc[i].waitingTime = proc[i - 1].waitingTime + proc[i - 1].burstTime;
}
}
void findTurnaroundTime(Process proc[], int n) {
for (int i = 0; i < n; i++) {
proc[i].turnaroundTime = proc[i].burstTime + proc[i].waitingTime;
}
}
void findAvgTimes(Process proc[], int n) {
int totalWaitingTime = 0, totalTurnaroundTime = 0;
for (int i = 0; i < n; i++) {
totalWaitingTime += proc[i].waitingTime;
totalTurnaroundTime += proc[i].turnaroundTime;
}
printf("Average waiting time: %.2f\n", (float)totalWaitingTime / n);
printf("Average turnaround time: %.2f\n", (float)totalTurnaroundTime / n);
}
void SJF(Process proc[], int n) {
qsort(proc, n, sizeof(Process), compare); // Sort by burst time
findWaitingTime(proc, n);
findTurnaroundTime(proc, n);
findAvgTimes(proc, n);
}
int main() {
Process proc[] = {
{1, 6, 0, 0},
{2, 8, 0, 0},
{3, 7, 0, 0},
{4, 3, 0, 0}
};
int n = sizeof(proc) / sizeof(proc[0]);
SJF(proc, n);
return 0;
}
3. Priority Scheduling:
In Priority Scheduling, each process has a priority. The process with the highest priority
(lowest priority number) gets executed first.
Priority Scheduling Algorithm:
c
Copy
#include <stdio.h>
typedef struct {
int pid; // Process ID
int priority;
int burstTime;
int waitingTime;
int turnaroundTime;
} Process;
int compare(const void *a, const void *b) {
return ((Process*)a)->priority - ((Process*)b)->priority;
}
void findWaitingTime(Process proc[], int n) {
proc[0].waitingTime = 0;
for (int i = 1; i < n; i++) {
proc[i].waitingTime = proc[i - 1].waitingTime + proc[i - 1].burstTime;
}
}
void findTurnaroundTime(Process proc[], int n) {
for (int i = 0; i < n; i++) {
proc[i].turnaroundTime = proc[i].burstTime + proc[i].waitingTime;
}
}
void findAvgTimes(Process proc[], int n) {
int totalWaitingTime = 0, totalTurnaroundTime = 0;
for (int i = 0; i < n; i++) {
totalWaitingTime += proc[i].waitingTime;
totalTurnaroundTime += proc[i].turnaroundTime;
}
printf("Average waiting time: %.2f\n", (float)totalWaitingTime / n);
printf("Average turnaround time: %.2f\n", (float)totalTurnaroundTime / n);
}
void PriorityScheduling(Process proc[], int n) {
qsort(proc, n, sizeof(Process), compare); // Sort by priority
findWaitingTime(proc, n);
findTurnaroundTime(proc, n);
findAvgTimes(proc, n);
}
int main() {
Process proc[] = {
{1, 2, 6, 0, 0},
{2, 1, 8, 0, 0},
{3, 4, 7, 0, 0},
{4, 3, 3, 0, 0}
};
int n = sizeof(proc) / sizeof(proc[0]);
PriorityScheduling(proc, n);
return 0;
}
4. Multi-level Queue (MLQ) Scheduling:
In Multi-Level Queue Scheduling, there are multiple queues, each with a different priority.
Processes are assigned to different queues based on their priority.
MLQ Algorithm:
c
Copy
#include <stdio.h>
#define HIGH_QUEUE 0
#define LOW_QUEUE 1
typedef struct {
int pid;
int burstTime;
int priority;
} Process;
void scheduleQueue(Process proc[], int n, int queueType) {
printf("Processing Queue %d\n", queueType);
for (int i = 0; i < n; i++) {
if ((queueType == HIGH_QUEUE && proc[i].priority == 1) || (queueType ==
LOW_QUEUE && proc[i].priority == 2)) {
printf("Process %d (Priority: %d, Burst Time: %d)\n", proc[i].pid, proc[i].priority,
proc[i].burstTime);
}
}
}
void MLQ(Process proc[], int n) {
printf("High Priority Queue:\n");
scheduleQueue(proc, n, HIGH_QUEUE);
printf("\nLow Priority Queue:\n");
scheduleQueue(proc, n, LOW_QUEUE);
}
int main() {
Process proc[] = {
{1, 6, 1}, // High priority
{2, 8, 2}, // Low priority
{3, 5, 1}, // High priority
{4, 3, 2} // Low priority
};
int n = sizeof(proc) / sizeof(proc[0]);
MLQ(proc, n);
return 0;
}
Experiment No. – 4
Implement file storage allocation technique:
i. Contiguous(using array)
ii. Linked –list(using linked-list)
iii. Indirect allocation (indexing)
1. Contiguous Allocation (using an array)
In contiguous allocation, files are stored in contiguous blocks on the disk. We can represent this
using an array where each index represents a block on the disk.
#include <stdio.h>
#include <string.h>
#define MAX_BLOCKS 100 // Maximum number of blocks
typedef struct {
int blockNumber; // Block number on the disk
char data[50]; // Data stored in the block
} Block;
typedef struct {
int size; // Size of the file in blocks
int startBlock; // Starting block of the file
int blocks[MAX_BLOCKS]; // Array of block numbers allocated to the file
} File;
// Initialize the disk with free blocks
Block disk[MAX_BLOCKS];
// Function to allocate blocks contiguously
int allocateContiguously(File *file, int size) {
int freeBlocks = 0;
// Find contiguous free blocks
for (int i = 0; i < MAX_BLOCKS; i++) {
if (disk[i].blockNumber == 0) { // Block is free
freeBlocks++;
} else {
freeBlocks = 0;
}
if (freeBlocks == size) { // Found enough free blocks
file->startBlock = i - size + 1;
for (int j = 0; j < size; j++) {
disk[file->startBlock + j].blockNumber = 1; // Mark as allocated
file->blocks[j] = file->startBlock + j;
}
file->size = size;
return 1; // Allocation successful
}
}
return 0; // Allocation failed
}
void displayFileDetails(File file) {
printf("File Size: %d blocks\n", file.size);
printf("Start Block: %d\n", file.startBlock);
printf("Allocated Blocks: ");
for (int i = 0; i < file.size; i++) {
printf("%d ", file.blocks[i]);
}
printf("\n");
}
int main() {
File file1;
memset(disk, 0, sizeof(disk)); // Initialize all disk blocks as free
if (allocateContiguously(&file1, 5)) {
printf("Contiguous Allocation Successful!\n");
displayFileDetails(file1);
} else {
printf("Contiguous Allocation Failed!\n");
}
return 0;
}
2. Linked List Allocation (using linked list)
In linked list allocation, each block contains a pointer to the next block, and the file is stored in non-
contiguous blocks. This is implemented using a linked list, where each node represents a disk block.
#include <stdio.h>
#include <stdlib.h>
#define MAX_BLOCKS 100 // Maximum number of blocks
typedef struct Block {
int blockNumber; // Block number on the disk
char data[50]; // Data stored in the block
struct Block* next; // Pointer to the next block in the file
} Block;
typedef struct {
int size; // Size of the file (in blocks)
Block* head; // Head pointer to the first block
} File;
// Initialize the disk with free blocks
Block disk[MAX_BLOCKS];
// Function to allocate blocks using linked list
int allocateLinkedList(File* file, int size) {
Block* prevBlock = NULL;
Block* newBlock = NULL;
file->head = NULL;
file->size = size;
for (int i = 0; i < size; i++) {
newBlock = (Block*)malloc(sizeof(Block));
if (!newBlock) {
return 0; // Memory allocation failed
}
// Find a free block
for (int j = 0; j < MAX_BLOCKS; j++) {
if (disk[j].blockNumber == 0) {
disk[j].blockNumber = 1; // Mark as allocated
newBlock->blockNumber = j;
newBlock->next = NULL;
// Link the new block to the previous one
if (prevBlock == NULL) {
file->head = newBlock;
} else {
prevBlock->next = newBlock;
}
prevBlock = newBlock;
break;
}
}
}
return 1; // Allocation successful
}
void displayFileDetails(File file) {
printf("File Size: %d blocks\n", file.size);
printf("Allocated Blocks: ");
Block* current = file.head;
while (current != NULL) {
printf("%d ", current->blockNumber);
current = current->next;
}
printf("\n");
}
int main() {
File file1;
memset(disk, 0, sizeof(disk)); // Initialize all disk blocks as free
if (allocateLinkedList(&file1, 4)) {
printf("Linked List Allocation Successful!\n");
displayFileDetails(file1);
} else {
printf("Linked List Allocation Failed!\n");
}
return 0;
}
3. Indexed Allocation (using indexing)
In indexed allocation, each file has an index block that contains pointers to the data blocks. We
implement this using an array for the index block.
#include <stdio.h>
#define MAX_BLOCKS 100 // Maximum number of blocks
typedef struct {
int blockNumber; // Block number on the disk
char data[50]; // Data stored in the block
} Block;
typedef struct {
int size; // Size of the file in blocks
int index[MAX_BLOCKS]; // Index block that stores block numbers
} File;
// Initialize the disk with free blocks
Block disk[MAX_BLOCKS];
// Function to allocate blocks using indexed allocation
int allocateIndexed(File* file, int size) {
file->size = size;
for (int i = 0; i < size; i++) {
// Find a free block
for (int j = 0; j < MAX_BLOCKS; j++) {
if (disk[j].blockNumber == 0) {
disk[j].blockNumber = 1; // Mark as allocated
file->index[i] = j; // Store block number in index
break;
}
}
}
return 1; // Allocation successful
}
void displayFileDetails(File file) {
printf("File Size: %d blocks\n", file.size);
printf("Index Block Pointers: ");
for (int i = 0; i < file.size; i++) {
printf("%d ", file.index[i]);
}
printf("\n");
}
int main() {
File file1;
memset(disk, 0, sizeof(disk)); // Initialize all disk blocks as free
if (allocateIndexed(&file1, 6)) {
printf("Indexed Allocation Successful!\n");
displayFileDetails(file1);
} else {
printf("Indexed Allocation Failed!\n");
}
return 0;
}
Experiment No. – 5
Implementation of contiguous allocation techniques:
i. Worst-Fit
ii. Best- Fit
iii. First- Fit
(i) Best Fit Algorithm The best fit deals with allocating the smallest free partition
which meets the requirement of the requesting process. This algorithm first
searches the entire list of free partitions and considers the smallest hole that is
adequate. It then tries to find a hole which is close to actual process size needed.
Algorithm:
1. Input memory blocks and processes with sizes.
2. Initialize all memory blocks as free.
3. Start by picking each process and find the minimum block size that can be assigned to
current process i.e., find min(bockSize[1], blockSize[2],.....blockSize[n]) >
processSize[current], if found then assign it to the current process.
4. If not then leave that process and keep checking the further processes.
(ii) Worst Fit Algorithm Worst Fit allocates a process to the partition which is largest
sufficient among the freely available partitions available in the main memory. If a
large process comes at a later stage, then memory will not have space to
accommodate it.
Algorithm:
1. Input memory blocks and processes with sizes.
2. Initialize all memory blocks as free.
3. Start by picking each process and find the maximum block size that can be assigned to
current process i.e., find max(bockSize[1], blockSize[2],.....blockSize[n]) >
processSize[current], if found then assign it to the current process.
4. If not then leave that process and keep checking the further processes.
(iii) Next Fit algorithm Next fit is a modified version of first fit. It begins as first fit to
find a free partition. When called next time it starts searching from where it left
off, not from the beginning.
Algorithm:
1. Input the number of memory blocks and their sizes and initializes all the blocks as free.
2. Input the number of processes and their sizes.
3. Start by picking each process and check if it can be assigned to the current block, if yes,
allocate it the required memory and check for next process but from the block where we left
not from starting.
4. If the current block size is smaller then keep checking the further blocks. Assignment
Quest
Experiment No. – 6
Calculation of external and internal fragmentation
i. Free space list of blocks from system
ii. List process file from the system
External Fragmentation refers to the situation where free blocks of memory or disk space
are scattered throughout the system, making it difficult to allocate large contiguous blocks
even though the total free space might be sufficient.
Internal Fragmentation occurs when allocated memory or disk space is larger than the
required size, leading to unused space within the allocated blocks.
Below is a C program that calculates both internal and external fragmentation using a free
space list and a list of processes (files in this case). The program simulates a disk allocation
system, where free space blocks and allocated blocks are managed to calculate fragmentation.
1. Free Space List of Blocks
We will define a free space list that represents blocks on the disk, where each block can be
free or allocated.
2. List of Processes (Files)
Each process will represent a file, with the size (in blocks) and the blocks allocated to the file.
#include <stdio.h>
#include <stdlib.h>
#define MAX_BLOCKS 100 // Total number of blocks on the disk
// Structure to represent a block
typedef struct {
int blockNumber; // Block number on the disk
int allocated; // 1 if allocated, 0 if free
} Block;
// Structure to represent a file (process) allocated on the disk
typedef struct {
int pid; // Process ID (or File ID)
int size; // Size of the file in blocks
int *allocatedBlocks; // Array of block numbers allocated to this file
} File;
// Disk with blocks
Block disk[MAX_BLOCKS];
// Function to initialize the disk (set all blocks as free)
void initializeDisk() {
for (int i = 0; i < MAX_BLOCKS; i++) {
disk[i].blockNumber = i;
disk[i].allocated = 0; // Mark all blocks as free
}
}
// Function to calculate internal fragmentation for a file
int calculateInternalFragmentation(File *file) {
int internalFrag = 0;
// We assume each file occupies contiguous blocks
int lastBlock = file->allocatedBlocks[file->size - 1];
// If the file uses fewer blocks than required, internal fragmentation occurs
int unusedSpace = (lastBlock + 1) - file->size;
internalFrag = unusedSpace;
return internalFrag;
}
// Function to calculate external fragmentation
int calculateExternalFragmentation() {
int externalFrag = 0;
// External fragmentation is the number of free blocks scattered in the disk
for (int i = 0; i < MAX_BLOCKS; i++) {
if (disk[i].allocated == 0) {
externalFrag++; // Count free blocks
}
}
return externalFrag;
}
// Function to allocate blocks to a file (for simplicity, allocate contiguous blocks)
int allocateFile(File *file) {
int allocatedBlocksCount = 0;
// Try to allocate contiguous blocks on the disk
for (int i = 0; i < MAX_BLOCKS; i++) {
if (disk[i].allocated == 0) { // Block is free
disk[i].allocated = 1; // Mark as allocated
file->allocatedBlocks[allocatedBlocksCount] = i;
allocatedBlocksCount++;
// If all blocks are allocated, return success
if (allocatedBlocksCount == file->size) {
return 1;
}
}
}
return 0; // Failed to allocate enough contiguous blocks
}
// Function to display the free space list
void displayFreeSpaceList() {
printf("\nFree Space List (Block Number): ");
for (int i = 0; i < MAX_BLOCKS; i++) {
if (disk[i].allocated == 0) {
printf("%d ", disk[i].blockNumber);
}
}
printf("\n");
}
// Function to display file details
void displayFileDetails(File *file) {
printf("Process %d (File) Allocation Details:\n", file->pid);
printf("File Size: %d blocks\n", file->size);
printf("Allocated Blocks: ");
for (int i = 0; i < file->size; i++) {
printf("%d ", file->allocatedBlocks[i]);
}
printf("\nInternal Fragmentation: %d blocks\n", calculateInternalFragmentation(file));
}
int main() {
initializeDisk(); // Initialize the disk
// Creating sample files (processes) with sizes
File file1 = {1, 5, (int *)malloc(5 * sizeof(int))}; // File with 5 blocks
File file2 = {2, 3, (int *)malloc(3 * sizeof(int))}; // File with 3 blocks
File file3 = {3, 6, (int *)malloc(6 * sizeof(int))}; // File with 6 blocks
// Allocate space for the files
if (allocateFile(&file1)) {
displayFileDetails(&file1);
} else {
printf("File 1 Allocation Failed\n");
}
if (allocateFile(&file2)) {
displayFileDetails(&file2);
} else {
printf("File 2 Allocation Failed\n");
}
if (allocateFile(&file3)) {
displayFileDetails(&file3);
} else {
printf("File 3 Allocation Failed\n");
}
// Display the free space list
displayFreeSpaceList();
// Calculate and display external fragmentation
printf("\nExternal Fragmentation: %d blocks\n", calculateExternalFragmentation());
// Cleanup allocated memory
free(file1.allocatedBlocks);
free(file2.allocatedBlocks);
free(file3.allocatedBlocks);
return 0;
}
Experiment No. – 7
Implementation of compaction for the continually changing memory layout and
calculate total movement of data