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;
 | 
						|
}
 |