c

exercises

exercises.cπŸ”§
/**
 * =============================================================================
 *                       FILE BASICS - EXERCISES
 * =============================================================================
 * 
 * Practice exercises for file opening, closing, and basic operations.
 * Complete each exercise by implementing the required functionality.
 * 
 * Compile: gcc -o exercises exercises.c -Wall -Wextra
 * Run:     ./exercises
 * =============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/* Exercise function prototypes */
void exercise1_simple_file_creation(void);
void exercise2_check_file_existence(void);
void exercise3_safe_file_opener(void);
void exercise4_file_mode_explorer(void);
void exercise5_error_reporter(void);
void exercise6_copy_file_contents(void);
void exercise7_multiple_file_handler(void);
void exercise8_stream_redirector(void);
void exercise9_file_statistics(void);
void exercise10_binary_file_creator(void);

void print_exercise_header(int num, const char *title);
void run_all_exercises(void);

/* =============================================================================
 * MAIN FUNCTION
 * =============================================================================
 */
int main(void) {
    printf("╔══════════════════════════════════════════════════════════════════╗\n");
    printf("β•‘                 FILE BASICS - EXERCISES                          β•‘\n");
    printf("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n\n");
    
    run_all_exercises();
    
    return 0;
}

void print_exercise_header(int num, const char *title) {
    printf("\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\n");
    printf("β”‚  EXERCISE %d: %-52s β”‚\n", num, title);
    printf("β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n\n");
}

void run_all_exercises(void) {
    exercise1_simple_file_creation();
    exercise2_check_file_existence();
    exercise3_safe_file_opener();
    exercise4_file_mode_explorer();
    exercise5_error_reporter();
    exercise6_copy_file_contents();
    exercise7_multiple_file_handler();
    exercise8_stream_redirector();
    exercise9_file_statistics();
    exercise10_binary_file_creator();
    
    printf("\n╔══════════════════════════════════════════════════════════════════╗\n");
    printf("β•‘                 ALL EXERCISES COMPLETED!                          β•‘\n");
    printf("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n");
}

/* =============================================================================
 * EXERCISE 1: Simple File Creation
 * =============================================================================
 * 
 * Task:
 * Create a function that creates a text file with your personal information.
 * The file should contain:
 *   - Your name
 *   - Today's date
 *   - A greeting message
 * 
 * Requirements:
 * - Open file in write mode
 * - Check for errors
 * - Close file properly
 * - Print confirmation message
 */
void exercise1_simple_file_creation(void) {
    print_exercise_header(1, "Simple File Creation");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    const char *filename = "personal_info.txt";
    FILE *fp = NULL;
    
    printf("Creating personal information file...\n\n");
    
    /* Open file for writing */
    fp = fopen(filename, "w");
    
    if (fp == NULL) {
        perror("Error creating file");
        return;
    }
    
    /* Write personal information */
    fprintf(fp, "═══════════════════════════════════\n");
    fprintf(fp, "        PERSONAL INFORMATION\n");
    fprintf(fp, "═══════════════════════════════════\n\n");
    fprintf(fp, "Name:     C Programming Student\n");
    fprintf(fp, "Date:     2024-01-20\n");
    fprintf(fp, "Message:  Hello! I'm learning C file handling.\n");
    fprintf(fp, "\n═══════════════════════════════════\n");
    
    /* Close file */
    if (fclose(fp) != 0) {
        perror("Error closing file");
        return;
    }
    
    printf("File '%s' created successfully!\n\n", filename);
    
    /* Read and display contents */
    fp = fopen(filename, "r");
    if (fp != NULL) {
        printf("File contents:\n");
        char buffer[100];
        while (fgets(buffer, sizeof(buffer), fp) != NULL) {
            printf("  %s", buffer);
        }
        fclose(fp);
    }
    
    /* Clean up */
    remove(filename);
    printf("\n[Temporary file cleaned up]\n");
}

/* =============================================================================
 * EXERCISE 2: Check File Existence
 * =============================================================================
 * 
 * Task:
 * Create a function that checks if a file exists and prints detailed
 * information about it.
 * 
 * Requirements:
 * - Accept filename as parameter
 * - Return 1 if file exists, 0 if not
 * - If file doesn't exist, provide helpful message
 * - If file exists, try to determine if it's readable
 */

/* Your function prototype */
int check_file_exists(const char *filename);

void exercise2_check_file_existence(void) {
    print_exercise_header(2, "Check File Existence");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    /* Implementation of check_file_exists */
    
    /* Test files */
    const char *existing = "test_exists.txt";
    const char *nonexisting = "this_does_not_exist.txt";
    
    /* Create a test file */
    FILE *fp = fopen(existing, "w");
    if (fp != NULL) {
        fprintf(fp, "Test content\n");
        fclose(fp);
    }
    
    printf("Testing file existence checker:\n\n");
    
    /* Check existing file */
    printf("Checking '%s':\n", existing);
    fp = fopen(existing, "r");
    if (fp != NULL) {
        printf("  βœ“ File EXISTS\n");
        printf("  βœ“ File is READABLE\n");
        
        /* Try to get file size */
        fseek(fp, 0, SEEK_END);
        long size = ftell(fp);
        printf("  βœ“ File size: %ld bytes\n", size);
        
        fclose(fp);
    } else {
        printf("  βœ— File DOES NOT EXIST or is not accessible\n");
        printf("    Error: %s\n", strerror(errno));
    }
    
    /* Check non-existing file */
    printf("\nChecking '%s':\n", nonexisting);
    fp = fopen(nonexisting, "r");
    if (fp != NULL) {
        printf("  βœ“ File EXISTS\n");
        fclose(fp);
    } else {
        printf("  βœ— File DOES NOT EXIST\n");
        printf("    Error code: %d\n", errno);
        printf("    Error message: %s\n", strerror(errno));
        printf("    Suggestion: Check the filename and path.\n");
    }
    
    /* Clean up */
    remove(existing);
}

/* =============================================================================
 * EXERCISE 3: Safe File Opener
 * =============================================================================
 * 
 * Task:
 * Create a robust file opening function with the following features:
 * - Validates input parameters
 * - Provides detailed error messages
 * - Supports verbose and quiet modes
 * - Returns NULL on failure with appropriate errno
 */

/* Your function prototype */
FILE *open_file_safely(const char *filename, const char *mode, int verbose);

void exercise3_safe_file_opener(void) {
    print_exercise_header(3, "Safe File Opener");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    /* Define the safe opener inline */
    FILE *open_safe(const char *filename, const char *mode, int verbose) {
        /* Validate parameters */
        if (filename == NULL) {
            if (verbose) {
                fprintf(stderr, "ERROR: Filename is NULL\n");
            }
            errno = EINVAL;
            return NULL;
        }
        
        if (mode == NULL) {
            if (verbose) {
                fprintf(stderr, "ERROR: Mode is NULL\n");
            }
            errno = EINVAL;
            return NULL;
        }
        
        if (strlen(filename) == 0) {
            if (verbose) {
                fprintf(stderr, "ERROR: Filename is empty\n");
            }
            errno = EINVAL;
            return NULL;
        }
        
        /* Validate mode */
        const char *valid_modes[] = {"r", "w", "a", "r+", "w+", "a+",
                                      "rb", "wb", "ab", "r+b", "w+b", "a+b",
                                      "rb+", "wb+", "ab+"};
        int valid = 0;
        for (size_t i = 0; i < sizeof(valid_modes)/sizeof(valid_modes[0]); i++) {
            if (strcmp(mode, valid_modes[i]) == 0) {
                valid = 1;
                break;
            }
        }
        
        if (!valid) {
            if (verbose) {
                fprintf(stderr, "ERROR: Invalid mode '%s'\n", mode);
            }
            errno = EINVAL;
            return NULL;
        }
        
        /* Try to open file */
        FILE *fp = fopen(filename, mode);
        
        if (fp == NULL && verbose) {
            fprintf(stderr, "ERROR: Cannot open '%s' with mode '%s'\n", 
                    filename, mode);
            fprintf(stderr, "  Reason: %s\n", strerror(errno));
        }
        
        if (fp != NULL && verbose) {
            printf("SUCCESS: Opened '%s' in mode '%s'\n", filename, mode);
        }
        
        return fp;
    }
    
    printf("Testing safe file opener:\n\n");
    
    /* Test 1: Normal operation */
    printf("Test 1: Opening file for writing (verbose)\n");
    FILE *fp = open_safe("safe_test.txt", "w", 1);
    if (fp != NULL) fclose(fp);
    remove("safe_test.txt");
    
    /* Test 2: NULL filename */
    printf("\nTest 2: NULL filename\n");
    fp = open_safe(NULL, "r", 1);
    
    /* Test 3: Invalid mode */
    printf("\nTest 3: Invalid mode\n");
    fp = open_safe("test.txt", "xyz", 1);
    
    /* Test 4: Non-existent file in read mode */
    printf("\nTest 4: Non-existent file in read mode\n");
    fp = open_safe("does_not_exist.txt", "r", 1);
    
    /* Test 5: Quiet mode */
    printf("\nTest 5: Same error in quiet mode (no output expected)\n");
    fp = open_safe(NULL, "r", 0);
    printf("  (No error message printed - quiet mode)\n");
    printf("  errno is set to: %d (%s)\n", errno, strerror(errno));
}

/* =============================================================================
 * EXERCISE 4: File Mode Explorer
 * =============================================================================
 * 
 * Task:
 * Create a demonstration that shows the behavior of different file modes.
 * For each mode, show:
 * - What happens when file exists
 * - What happens when file doesn't exist
 * - Whether content is preserved or lost
 */
void exercise4_file_mode_explorer(void) {
    print_exercise_header(4, "File Mode Explorer");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    const char *filename = "mode_test.txt";
    FILE *fp;
    
    printf("Exploring file modes:\n\n");
    
    /* Create initial file */
    fp = fopen(filename, "w");
    if (fp != NULL) {
        fprintf(fp, "Original content\n");
        fclose(fp);
    }
    
    /* Mode "r" */
    printf("═══ Mode 'r' (Read) ═══\n");
    printf("File exists with content: 'Original content'\n");
    fp = fopen(filename, "r");
    if (fp != NULL) {
        printf("Result: File opened successfully\n");
        char buf[50];
        fgets(buf, sizeof(buf), fp);
        printf("Content: %s", buf);
        fclose(fp);
    }
    
    printf("\nTrying non-existent file:\n");
    fp = fopen("nonexistent.txt", "r");
    printf("Result: %s\n\n", fp == NULL ? "NULL returned (correct)" : "Unexpected");
    if (fp) fclose(fp);
    
    /* Mode "w" */
    printf("═══ Mode 'w' (Write) ═══\n");
    printf("Opening existing file in 'w' mode:\n");
    fp = fopen(filename, "w");
    if (fp != NULL) {
        printf("Result: File opened (truncated!)\n");
        fclose(fp);
    }
    
    fp = fopen(filename, "r");
    if (fp != NULL) {
        char buf[50];
        if (fgets(buf, sizeof(buf), fp) == NULL) {
            printf("Content: <empty - file was truncated>\n");
        }
        fclose(fp);
    }
    
    /* Mode "a" */
    printf("\n═══ Mode 'a' (Append) ═══\n");
    printf("Creating file and appending:\n");
    fp = fopen(filename, "w");
    if (fp) {
        fprintf(fp, "Line 1\n");
        fclose(fp);
    }
    
    fp = fopen(filename, "a");
    if (fp) {
        fprintf(fp, "Line 2 (appended)\n");
        fclose(fp);
    }
    
    fp = fopen(filename, "r");
    if (fp) {
        printf("Content after append:\n");
        char buf[50];
        while (fgets(buf, sizeof(buf), fp)) {
            printf("  %s", buf);
        }
        fclose(fp);
    }
    
    /* Summary table */
    printf("\n═══ Summary Table ═══\n");
    printf("β”Œβ”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\n");
    printf("β”‚ Mode β”‚ File Exists  β”‚ File Missing  β”‚ Truncate? β”‚\n");
    printf("β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€\n");
    printf("β”‚  r   β”‚ Open read    β”‚ NULL          β”‚ No        β”‚\n");
    printf("β”‚  w   β”‚ Truncate     β”‚ Create        β”‚ YES       β”‚\n");
    printf("β”‚  a   β”‚ Append       β”‚ Create        β”‚ No        β”‚\n");
    printf("β”‚  r+  β”‚ Read/Write   β”‚ NULL          β”‚ No        β”‚\n");
    printf("β”‚  w+  β”‚ Read/Write   β”‚ Create        β”‚ YES       β”‚\n");
    printf("β”‚  a+  β”‚ Read/Append  β”‚ Create        β”‚ No        β”‚\n");
    printf("β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n");
    
    remove(filename);
}

/* =============================================================================
 * EXERCISE 5: Comprehensive Error Reporter
 * =============================================================================
 * 
 * Task:
 * Create a function that attempts various file operations and reports
 * detailed error information including errno values and suggestions.
 */
void exercise5_error_reporter(void) {
    print_exercise_header(5, "Comprehensive Error Reporter");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    void report_file_error(const char *operation, const char *filename) {
        printf("\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\n");
        printf("β”‚ FILE OPERATION ERROR REPORT            β”‚\n");
        printf("β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€\n");
        printf("β”‚ Operation: %-27s β”‚\n", operation);
        printf("β”‚ Filename:  %-27s β”‚\n", filename);
        printf("β”‚ Error #:   %-27d β”‚\n", errno);
        printf("β”‚ Message:   %-27s β”‚\n", strerror(errno));
        printf("β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n");
        
        /* Provide suggestions based on errno */
        printf("\nSuggestion: ");
        switch (errno) {
            case ENOENT:
                printf("File or directory doesn't exist.\n");
                printf("  - Check the file path\n");
                printf("  - Ensure all parent directories exist\n");
                break;
            case EACCES:
                printf("Permission denied.\n");
                printf("  - Check file permissions\n");
                printf("  - Try running with elevated privileges\n");
                break;
            case EEXIST:
                printf("File already exists.\n");
                printf("  - Use a different filename\n");
                printf("  - Delete existing file first\n");
                break;
            case EISDIR:
                printf("Path is a directory, not a file.\n");
                printf("  - Append a filename to the path\n");
                break;
            case EMFILE:
                printf("Too many open files.\n");
                printf("  - Close some files\n");
                printf("  - Increase file descriptor limit\n");
                break;
            case ENOSPC:
                printf("No space left on device.\n");
                printf("  - Free up disk space\n");
                printf("  - Use a different location\n");
                break;
            default:
                printf("Unknown error - check documentation.\n");
        }
    }
    
    printf("Testing various error conditions:\n");
    
    /* Test 1: Non-existent file */
    printf("\n═══ Test 1: Reading non-existent file ═══");
    FILE *fp = fopen("/nonexistent/path/file.txt", "r");
    if (fp == NULL) {
        report_file_error("fopen (read)", "/nonexistent/path/file.txt");
    }
    
    /* Test 2: Permission denied (might not work everywhere) */
    printf("\n═══ Test 2: Writing to protected location ═══");
    fp = fopen("/etc/protected_test.txt", "w");
    if (fp == NULL) {
        report_file_error("fopen (write)", "/etc/protected_test.txt");
    } else {
        fclose(fp);
        remove("/etc/protected_test.txt");
    }
    
    /* Test 3: Invalid path */
    printf("\n═══ Test 3: Directory as file ═══");
    fp = fopen("/tmp", "r");
    if (fp == NULL) {
        report_file_error("fopen (read)", "/tmp");
    } else {
        fclose(fp);
    }
}

/* =============================================================================
 * EXERCISE 6: File Copy Utility
 * =============================================================================
 * 
 * Task:
 * Create a function that copies the contents of one file to another.
 * Handle all error conditions properly.
 */
int copy_file(const char *source, const char *destination);

void exercise6_copy_file_contents(void) {
    print_exercise_header(6, "File Copy Utility");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    /* Create source file */
    FILE *fp = fopen("source.txt", "w");
    if (fp != NULL) {
        fprintf(fp, "This is line 1 of the source file.\n");
        fprintf(fp, "This is line 2 of the source file.\n");
        fprintf(fp, "This is line 3 of the source file.\n");
        fclose(fp);
    }
    
    printf("Copying 'source.txt' to 'destination.txt'\n\n");
    
    /* Open source for reading */
    FILE *src = fopen("source.txt", "r");
    if (src == NULL) {
        perror("Error opening source file");
        return;
    }
    
    /* Open destination for writing */
    FILE *dst = fopen("destination.txt", "w");
    if (dst == NULL) {
        perror("Error opening destination file");
        fclose(src);
        return;
    }
    
    /* Copy contents */
    char buffer[256];
    int lines_copied = 0;
    
    while (fgets(buffer, sizeof(buffer), src) != NULL) {
        if (fputs(buffer, dst) == EOF) {
            perror("Error writing to destination");
            break;
        }
        lines_copied++;
    }
    
    /* Check for read errors */
    if (ferror(src)) {
        perror("Error reading from source");
    }
    
    /* Close files */
    fclose(src);
    fclose(dst);
    
    printf("Copy complete! %d lines copied.\n\n", lines_copied);
    
    /* Verify by reading destination */
    printf("Contents of destination.txt:\n");
    printf("───────────────────────────\n");
    dst = fopen("destination.txt", "r");
    if (dst != NULL) {
        while (fgets(buffer, sizeof(buffer), dst) != NULL) {
            printf("  %s", buffer);
        }
        fclose(dst);
    }
    
    /* Clean up */
    remove("source.txt");
    remove("destination.txt");
}

/* =============================================================================
 * EXERCISE 7: Multiple File Handler
 * =============================================================================
 * 
 * Task:
 * Create a program that opens multiple files, processes them, and properly
 * cleans up all resources even if an error occurs.
 */
void exercise7_multiple_file_handler(void) {
    print_exercise_header(7, "Multiple File Handler");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    FILE *files[5] = {NULL, NULL, NULL, NULL, NULL};
    const char *names[] = {"file1.txt", "file2.txt", "file3.txt", 
                           "file4.txt", "file5.txt"};
    int num_files = 5;
    int files_opened = 0;
    int success = 1;
    
    printf("Opening %d files:\n", num_files);
    
    /* Open all files */
    for (int i = 0; i < num_files; i++) {
        files[i] = fopen(names[i], "w");
        if (files[i] == NULL) {
            fprintf(stderr, "  βœ— Failed to open '%s': %s\n", 
                    names[i], strerror(errno));
            success = 0;
            break;
        }
        printf("  βœ“ Opened '%s'\n", names[i]);
        files_opened++;
    }
    
    if (success) {
        printf("\nWriting to all files:\n");
        
        /* Write to all files */
        for (int i = 0; i < num_files; i++) {
            fprintf(files[i], "This is file #%d\n", i + 1);
            fprintf(files[i], "Created by multiple file handler exercise.\n");
            printf("  βœ“ Wrote to '%s'\n", names[i]);
        }
    }
    
    /* Close all opened files (even on error) */
    printf("\nClosing files:\n");
    for (int i = 0; i < files_opened; i++) {
        if (files[i] != NULL) {
            if (fclose(files[i]) == 0) {
                printf("  βœ“ Closed '%s'\n", names[i]);
            } else {
                printf("  βœ— Error closing '%s'\n", names[i]);
            }
            files[i] = NULL;
        }
    }
    
    /* Verify one file */
    if (success) {
        printf("\nVerifying 'file1.txt':\n");
        FILE *fp = fopen("file1.txt", "r");
        if (fp != NULL) {
            char buffer[100];
            while (fgets(buffer, sizeof(buffer), fp)) {
                printf("  %s", buffer);
            }
            fclose(fp);
        }
    }
    
    /* Clean up all files */
    printf("\nCleaning up:\n");
    for (int i = 0; i < num_files; i++) {
        if (remove(names[i]) == 0) {
            printf("  βœ“ Removed '%s'\n", names[i]);
        }
    }
}

/* =============================================================================
 * EXERCISE 8: Stream Redirector
 * =============================================================================
 * 
 * Task:
 * Create a logging utility that redirects stdout to a file temporarily,
 * then restores it.
 */
void exercise8_stream_redirector(void) {
    print_exercise_header(8, "Stream Redirector");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    printf("This message goes to normal stdout.\n\n");
    
    printf("Implementing a simple logging system:\n");
    printf("─────────────────────────────────────\n\n");
    
    /* Save original stdout using file descriptor */
    int stdout_fd = dup(fileno(stdout));
    
    /* Open log file */
    FILE *log = fopen("output.log", "w");
    if (log == NULL) {
        perror("Cannot open log file");
        return;
    }
    
    printf("Redirecting next 3 printf calls to 'output.log'...\n\n");
    
    /* Redirect stdout to log file */
    fflush(stdout);
    dup2(fileno(log), fileno(stdout));
    
    /* These go to the log file */
    printf("Log entry 1: Program started\n");
    printf("Log entry 2: Processing data\n");
    printf("Log entry 3: Processing complete\n");
    
    /* Restore stdout */
    fflush(stdout);
    dup2(stdout_fd, fileno(stdout));
    close(stdout_fd);
    fclose(log);
    
    printf("stdout restored. Messages went to log file.\n\n");
    
    /* Read and display log contents */
    printf("Contents of output.log:\n");
    printf("───────────────────────\n");
    log = fopen("output.log", "r");
    if (log != NULL) {
        char buffer[100];
        while (fgets(buffer, sizeof(buffer), log)) {
            printf("  %s", buffer);
        }
        fclose(log);
    }
    
    remove("output.log");
}

/* =============================================================================
 * EXERCISE 9: File Statistics
 * =============================================================================
 * 
 * Task:
 * Create a function that analyzes a text file and reports:
 * - Number of characters
 * - Number of words
 * - Number of lines
 * - File size in bytes
 */
void exercise9_file_statistics(void) {
    print_exercise_header(9, "File Statistics");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    /* Create a sample file */
    const char *filename = "sample.txt";
    FILE *fp = fopen(filename, "w");
    if (fp != NULL) {
        fprintf(fp, "Hello World!\n");
        fprintf(fp, "This is a sample text file.\n");
        fprintf(fp, "It contains multiple lines.\n");
        fprintf(fp, "We will count characters, words, and lines.\n");
        fclose(fp);
    }
    
    /* Analyze the file */
    fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("Cannot open file");
        return;
    }
    
    long characters = 0;
    long words = 0;
    long lines = 0;
    int in_word = 0;
    int ch;
    
    while ((ch = fgetc(fp)) != EOF) {
        characters++;
        
        if (ch == '\n') {
            lines++;
        }
        
        /* Count words (space/newline/tab separated) */
        if (ch == ' ' || ch == '\n' || ch == '\t') {
            if (in_word) {
                words++;
                in_word = 0;
            }
        } else {
            in_word = 1;
        }
    }
    
    /* Count last word if file doesn't end with whitespace */
    if (in_word) {
        words++;
    }
    
    /* Get file size */
    fseek(fp, 0, SEEK_END);
    long file_size = ftell(fp);
    
    fclose(fp);
    
    /* Display statistics */
    printf("File: %s\n\n", filename);
    printf("β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\n");
    printf("β”‚         FILE STATISTICS               β”‚\n");
    printf("β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€\n");
    printf("β”‚ Characters:     %-20ld β”‚\n", characters);
    printf("β”‚ Words:          %-20ld β”‚\n", words);
    printf("β”‚ Lines:          %-20ld β”‚\n", lines);
    printf("β”‚ File size:      %-17ld bytesβ”‚\n", file_size);
    printf("β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n");
    
    /* Display file contents for reference */
    printf("\nFile contents:\n");
    printf("─────────────────────────────────────────\n");
    fp = fopen(filename, "r");
    if (fp != NULL) {
        char buffer[100];
        while (fgets(buffer, sizeof(buffer), fp)) {
            printf("  %s", buffer);
        }
        fclose(fp);
    }
    
    remove(filename);
}

/* =============================================================================
 * EXERCISE 10: Binary File Creator
 * =============================================================================
 * 
 * Task:
 * Create a program that:
 * 1. Creates a binary file with structured data
 * 2. Reads it back
 * 3. Verifies data integrity
 */
void exercise10_binary_file_creator(void) {
    print_exercise_header(10, "Binary File Creator");
    
    /* TODO: Implement your solution here */
    
    /* SOLUTION */
    struct Student {
        int id;
        char name[50];
        float gpa;
    };
    
    const char *filename = "students.bin";
    
    /* Create sample data */
    struct Student students[] = {
        {1001, "Alice Johnson", 3.85},
        {1002, "Bob Smith", 3.42},
        {1003, "Carol Williams", 3.91},
        {1004, "David Brown", 3.15},
        {1005, "Eve Davis", 3.78}
    };
    int num_students = sizeof(students) / sizeof(students[0]);
    
    printf("Creating binary file with student records:\n\n");
    
    /* Write to binary file */
    FILE *fp = fopen(filename, "wb");
    if (fp == NULL) {
        perror("Cannot create binary file");
        return;
    }
    
    /* Write number of records first */
    fwrite(&num_students, sizeof(int), 1, fp);
    
    /* Write all student records */
    size_t written = fwrite(students, sizeof(struct Student), num_students, fp);
    printf("Wrote %zu student records.\n\n", written);
    
    fclose(fp);
    
    /* Read back from binary file */
    printf("Reading back from binary file:\n");
    printf("──────────────────────────────\n\n");
    
    fp = fopen(filename, "rb");
    if (fp == NULL) {
        perror("Cannot open binary file");
        return;
    }
    
    /* Read number of records */
    int count;
    fread(&count, sizeof(int), 1, fp);
    printf("Number of records: %d\n\n", count);
    
    /* Read and display each record */
    printf("β”Œβ”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”\n");
    printf("β”‚  ID  β”‚ Name               β”‚  GPA  β”‚\n");
    printf("β”œβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€\n");
    
    struct Student loaded;
    int verified = 1;
    
    for (int i = 0; i < count; i++) {
        fread(&loaded, sizeof(struct Student), 1, fp);
        printf("β”‚ %4d β”‚ %-18s β”‚ %5.2f β”‚\n", 
               loaded.id, loaded.name, loaded.gpa);
        
        /* Verify data integrity */
        if (loaded.id != students[i].id ||
            strcmp(loaded.name, students[i].name) != 0 ||
            loaded.gpa != students[i].gpa) {
            verified = 0;
        }
    }
    
    printf("β””β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”˜\n\n");
    
    printf("Data integrity check: %s\n", 
           verified ? "βœ“ PASSED" : "βœ— FAILED");
    
    fclose(fp);
    remove(filename);
}

/* =============================================================================
 * ANSWER KEY AND EXPLANATIONS
 * =============================================================================
 *
 * EXERCISE 1: Simple File Creation
 * --------------------------------
 * Key concepts:
 * - fopen() with "w" mode creates a new file or truncates existing
 * - Always check fopen() return value for NULL
 * - Use fprintf() to write formatted text
 * - Always fclose() after you're done
 * - Use fgets() in a loop to read file line by line
 *
 * EXERCISE 2: Check File Existence
 * --------------------------------
 * Key concepts:
 * - Opening in "r" mode fails if file doesn't exist
 * - fseek(fp, 0, SEEK_END) + ftell(fp) gives file size
 * - Always close file even when just checking existence
 * - strerror(errno) gives human-readable error message
 *
 * EXERCISE 3: Safe File Opener
 * ----------------------------
 * Key concepts:
 * - Validate all input parameters before use
 * - Check for NULL and empty strings
 * - Validate mode strings against known valid modes
 * - errno should be set on error
 * - Verbose mode allows caller to control error output
 *
 * EXERCISE 4: File Mode Explorer
 * ------------------------------
 * Key concepts:
 * - "r" fails if file doesn't exist
 * - "w" ALWAYS truncates/creates - USE WITH CAUTION
 * - "a" preserves content, writes at end
 * - "+" modes add both read and write capability
 * - Binary modes ("rb", "wb") important for non-text data
 *
 * EXERCISE 5: Comprehensive Error Reporter
 * ----------------------------------------
 * Key concepts:
 * - errno is set by failed system calls
 * - Different errno values indicate different problems
 * - Providing suggestions based on error helps users
 * - perror() and strerror() format error messages
 *
 * EXERCISE 6: File Copy Utility
 * -----------------------------
 * Key concepts:
 * - Open source for reading, destination for writing
 * - Use a buffer with fgets()/fputs() for text files
 * - Check for both read and write errors
 * - Close both files even if copying fails
 * - ferror() checks if stream encountered an error
 *
 * EXERCISE 7: Multiple File Handler
 * ---------------------------------
 * Key concepts:
 * - Initialize all file pointers to NULL
 * - Track how many files were successfully opened
 * - Close ALL opened files in cleanup, even on error
 * - Loop cleanup handles partial success scenarios
 *
 * EXERCISE 8: Stream Redirector
 * -----------------------------
 * Key concepts:
 * - dup() duplicates a file descriptor
 * - dup2() redirects one descriptor to another
 * - fileno() gets file descriptor from FILE*
 * - fflush() before redirecting ensures buffered data written
 * - Restore original descriptor when done
 *
 * EXERCISE 9: File Statistics
 * ---------------------------
 * Key concepts:
 * - fgetc() reads one character at a time
 * - Track state (in_word) to count words correctly
 * - Count lines by counting newline characters
 * - fseek() + ftell() for file size
 * - EOF marks end of file
 *
 * EXERCISE 10: Binary File Creator
 * --------------------------------
 * Key concepts:
 * - Use "wb" and "rb" for binary mode
 * - fwrite() writes raw binary data
 * - fread() reads raw binary data
 * - Structure padding may affect binary file portability
 * - Write metadata (count) before actual data for reading
 *
 * =============================================================================
 */
Exercises - C Programming Tutorial | DeepML