272 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			272 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <limits.h> // For INT_MAX
 | |
| 
 | |
| // Structure for a memory block
 | |
| typedef struct Block {
 | |
|     int id;          // Block ID (optional, can use address for uniqueness)
 | |
|     int size;        // Size of the block
 | |
|     int allocated;   // 0 if free, 1 if allocated
 | |
|     int process_id;  // ID of process allocated to this block (-1 if free)
 | |
|     struct Block *next; // Pointer to the next block in the list
 | |
|     struct Block *prev; // Pointer to the previous block in the list (for potential merging)
 | |
| } Block;
 | |
| 
 | |
| // Global head of the memory block linked list
 | |
| Block *memory_head = NULL;
 | |
| 
 | |
| // Function to create a new block node
 | |
| Block* create_block(int id, int size, int allocated, int process_id) {
 | |
|     Block *new_block = (Block*)malloc(sizeof(Block));
 | |
|     if (!new_block) {
 | |
|         perror("Failed to allocate memory for block");
 | |
|         exit(EXIT_FAILURE);
 | |
|     }
 | |
|     new_block->id = id;
 | |
|     new_block->size = size;
 | |
|     new_block->allocated = allocated;
 | |
|     new_block->process_id = process_id;
 | |
|     new_block->next = NULL;
 | |
|     new_block->prev = NULL;
 | |
|     return new_block;
 | |
| }
 | |
| 
 | |
| // Function to initialize the memory list with one large free block
 | |
| void initialize_memory(int total_size) {
 | |
|     if (memory_head != NULL) {
 | |
|          // Simple cleanup for re-initialization (more robust needed for general use)
 | |
|          Block *current = memory_head;
 | |
|          Block *next_node;
 | |
|          while(current != NULL) {
 | |
|              next_node = current->next;
 | |
|              free(current);
 | |
|              current = next_node;
 | |
|          }
 | |
|          memory_head = NULL; // Reset head
 | |
|     }
 | |
|     memory_head = create_block(0, total_size, 0, -1); // ID 0, size, free, no process
 | |
| }
 | |
| 
 | |
| // Function to display the current state of memory blocks
 | |
| void display_memory() {
 | |
|     Block *current = memory_head;
 | |
|     printf("Memory Blocks:\n");
 | |
|     printf("----------------------------------------------------\n");
 | |
|     printf("| ID | Size      | Status    | Process ID |\n");
 | |
|     printf("----------------------------------------------------\n");
 | |
|     while (current != NULL) {
 | |
|         printf("| %-2d | %-9d | %-9s | %-10d |\n",
 | |
|                current->id,
 | |
|                current->size,
 | |
|                current->allocated ? "Allocated" : "Free",
 | |
|                current->allocated ? current->process_id : -1);
 | |
|         current = current->next;
 | |
|     }
 | |
|     printf("----------------------------------------------------\n\n");
 | |
| }
 | |
| 
 | |
| // Function to allocate memory using First Fit strategy
 | |
| int allocate_first_fit(int process_id, int required_size) {
 | |
|     Block *current = memory_head;
 | |
|     Block *best_block = NULL;
 | |
| 
 | |
|     // Find the first free block that is large enough
 | |
|     while (current != NULL) {
 | |
|         if (!current->allocated && current->size >= required_size) {
 | |
|             best_block = current;
 | |
|             break; // First fit found
 | |
|         }
 | |
|         current = current->next;
 | |
|     }
 | |
| 
 | |
|     // If a suitable block is found
 | |
|     if (best_block != NULL) {
 | |
|         // Check if splitting is necessary (and worthwhile, e.g., remaining > 0)
 | |
|         if (best_block->size > required_size) {
 | |
|             // Create a new block for the remaining free space
 | |
|             int remaining_size = best_block->size - required_size;
 | |
|             // For simplicity, assigning next available ID - needs better management in real system
 | |
|             int new_block_id = best_block->id + 1; // simplistic ID assignment
 | |
|             Block *new_free_block = create_block(new_block_id, remaining_size, 0, -1);
 | |
| 
 | |
|             // Update the allocated block
 | |
|             best_block->size = required_size;
 | |
|             best_block->allocated = 1;
 | |
|             best_block->process_id = process_id;
 | |
| 
 | |
|             // Insert the new free block into the list
 | |
|             new_free_block->next = best_block->next;
 | |
|             new_free_block->prev = best_block;
 | |
|             if (best_block->next != NULL) {
 | |
|                 best_block->next->prev = new_free_block;
 | |
|             }
 | |
|             best_block->next = new_free_block;
 | |
| 
 | |
|             // Renumber subsequent block IDs (basic approach)
 | |
|             Block* temp = new_free_block->next;
 | |
|             int current_id = new_block_id + 1;
 | |
|             while (temp != NULL) {
 | |
|                 temp->id = current_id++;
 | |
|                 temp = temp->next;
 | |
|             }
 | |
| 
 | |
|         } else { // Exact fit or minimal leftover space (allocate the whole block)
 | |
|             best_block->allocated = 1;
 | |
|             best_block->process_id = process_id;
 | |
|         }
 | |
|         printf("Process %d allocated %d units using First Fit in Block %d.\n", process_id, required_size, best_block->id);
 | |
|         return 1; // Allocation successful
 | |
|     } else {
 | |
|         printf("Process %d (size %d) could not be allocated using First Fit.\n", process_id, required_size);
 | |
|         return 0; // Allocation failed
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| // Function to allocate memory using Best Fit strategy
 | |
| int allocate_best_fit(int process_id, int required_size) {
 | |
|     Block *current = memory_head;
 | |
|     Block *best_block = NULL;
 | |
|     int min_waste = INT_MAX;
 | |
| 
 | |
|     // Find the smallest free block that is large enough
 | |
|     while (current != NULL) {
 | |
|         if (!current->allocated && current->size >= required_size) {
 | |
|             int waste = current->size - required_size;
 | |
|             if (waste < min_waste) {
 | |
|                 min_waste = waste;
 | |
|                 best_block = current;
 | |
|             }
 | |
|         }
 | |
|         current = current->next;
 | |
|     }
 | |
| 
 | |
|     // If a suitable block is found
 | |
|     if (best_block != NULL) {
 | |
|          // Check if splitting is necessary (and worthwhile, e.g., remaining > 0)
 | |
|         if (best_block->size > required_size) {
 | |
|             // Create a new block for the remaining free space
 | |
|             int remaining_size = best_block->size - required_size;
 | |
|             int new_block_id = best_block->id + 1; // simplistic ID assignment
 | |
|             Block *new_free_block = create_block(new_block_id, remaining_size, 0, -1);
 | |
| 
 | |
|             // Update the allocated block
 | |
|             best_block->size = required_size;
 | |
|             best_block->allocated = 1;
 | |
|             best_block->process_id = process_id;
 | |
| 
 | |
|             // Insert the new free block into the list
 | |
|             new_free_block->next = best_block->next;
 | |
|             new_free_block->prev = best_block;
 | |
|             if (best_block->next != NULL) {
 | |
|                 best_block->next->prev = new_free_block;
 | |
|             }
 | |
|             best_block->next = new_free_block;
 | |
| 
 | |
|             // Renumber subsequent block IDs (basic approach)
 | |
|              Block* temp = new_free_block->next;
 | |
|             int current_id = new_block_id + 1;
 | |
|             while (temp != NULL) {
 | |
|                 temp->id = current_id++;
 | |
|                 temp = temp->next;
 | |
|             }
 | |
| 
 | |
|         } else { // Exact fit (allocate the whole block)
 | |
|             best_block->allocated = 1;
 | |
|             best_block->process_id = process_id;
 | |
|         }
 | |
|         printf("Process %d allocated %d units using Best Fit in Block %d.\n", process_id, required_size, best_block->id);
 | |
|         return 1; // Allocation successful
 | |
|     } else {
 | |
|         printf("Process %d (size %d) could not be allocated using Best Fit.\n", process_id, required_size);
 | |
|         return 0; // Allocation failed
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Function to free all allocated memory for the linked list
 | |
| void cleanup_memory() {
 | |
|     Block *current = memory_head;
 | |
|     Block *next_node;
 | |
|     while (current != NULL) {
 | |
|         next_node = current->next;
 | |
|         free(current);
 | |
|         current = next_node;
 | |
|     }
 | |
|     memory_head = NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| int main() {
 | |
|     int total_memory;
 | |
|     int num_processes;
 | |
|     int *process_sizes = NULL; // Dynamically allocated array for process sizes
 | |
|     int i;
 | |
| 
 | |
|     // --- Input ---
 | |
|     printf("Enter the total size of memory: ");
 | |
|     scanf("%d", &total_memory);
 | |
|     if (total_memory <= 0) {
 | |
|         printf("Invalid memory size.\n");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     printf("Enter the number of processes: ");
 | |
|     scanf("%d", &num_processes);
 | |
|     if (num_processes <= 0) {
 | |
|         printf("Invalid number of processes.\n");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     // Dynamically allocate array for process sizes
 | |
|     process_sizes = (int*)malloc(num_processes * sizeof(int));
 | |
|     if (!process_sizes) {
 | |
|         perror("Failed to allocate memory for process sizes");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     printf("Enter the size required for each process:\n");
 | |
|     for (i = 0; i < num_processes; i++) {
 | |
|         printf("Process %d size: ", i + 1);
 | |
|         scanf("%d", &process_sizes[i]);
 | |
|         if (process_sizes[i] <= 0) {
 | |
|             printf("Invalid process size. Please enter a positive value.\n");
 | |
|             free(process_sizes);
 | |
|             return 1;
 | |
|         }
 | |
|     }
 | |
|     printf("\n");
 | |
| 
 | |
| 
 | |
|     // --- First Fit Simulation ---
 | |
|     printf("--- First Fit Allocation ---\n");
 | |
|     initialize_memory(total_memory);
 | |
|     printf("Initial Memory State:\n");
 | |
|     display_memory();
 | |
| 
 | |
|     for (i = 0; i < num_processes; i++) {
 | |
|         allocate_first_fit(i + 1, process_sizes[i]); // Process IDs starting from 1
 | |
|         display_memory(); // Show state after each allocation attempt
 | |
|     }
 | |
|     printf("Final Memory State after First Fit:\n");
 | |
|     display_memory();
 | |
| 
 | |
| 
 | |
|     // --- Best Fit Simulation ---
 | |
|     printf("\n--- Best Fit Allocation ---\n");
 | |
|     initialize_memory(total_memory); // Re-initialize memory for a fresh start
 | |
|     printf("Initial Memory State:\n");
 | |
|     display_memory();
 | |
| 
 | |
|     for (i = 0; i < num_processes; i++) {
 | |
|         allocate_best_fit(i + 1, process_sizes[i]); // Process IDs starting from 1
 | |
|         display_memory(); // Show state after each allocation attempt
 | |
|     }
 | |
|     printf("Final Memory State after Best Fit:\n");
 | |
|     display_memory();
 | |
| 
 | |
|     // --- Cleanup ---
 | |
|     free(process_sizes); // Free the dynamically allocated process sizes array
 | |
|     cleanup_memory(); // Free the memory blocks linked list
 | |
| 
 | |
|     return 0;
 | |
| }
 |