c

examples

examples.cšŸ”§
/**
 * =============================================================================
 *                         FILE BASICS - EXAMPLES
 * =============================================================================
 * 
 * This file demonstrates fundamental file operations in C:
 * - Opening and closing files
 * - File opening modes
 * - Error handling with file operations
 * - Standard streams (stdin, stdout, stderr)
 * - File buffering concepts
 * 
 * Compile: gcc -o examples examples.c -Wall -Wextra
 * Run:     ./examples
 * =============================================================================
 */

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

/* Function prototypes */
void example1_basic_file_open_close(void);
void example2_file_opening_modes(void);
void example3_error_handling_with_perror(void);
void example4_error_handling_with_errno(void);
void example5_checking_file_existence(void);
void example6_standard_streams(void);
void example7_stderr_usage(void);
void example8_fflush_demonstration(void);
void example9_file_pointer_validation(void);
void example10_safe_file_open_function(void);
void example11_multiple_files(void);
void example12_binary_vs_text_mode(void);
void example13_freopen_demonstration(void);
void example14_file_operations_workflow(void);
void example15_cleanup_pattern(void);

void print_separator(const char *title);

/* =============================================================================
 * MAIN FUNCTION
 * =============================================================================
 */
int main(void) {
    printf("╔══════════════════════════════════════════════════════════════════╗\n");
    printf("ā•‘              FILE BASICS - COMPREHENSIVE EXAMPLES                ā•‘\n");
    printf("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n\n");
    
    example1_basic_file_open_close();
    example2_file_opening_modes();
    example3_error_handling_with_perror();
    example4_error_handling_with_errno();
    example5_checking_file_existence();
    example6_standard_streams();
    example7_stderr_usage();
    example8_fflush_demonstration();
    example9_file_pointer_validation();
    example10_safe_file_open_function();
    example11_multiple_files();
    example12_binary_vs_text_mode();
    example13_freopen_demonstration();
    example14_file_operations_workflow();
    example15_cleanup_pattern();
    
    printf("\n╔══════════════════════════════════════════════════════════════════╗\n");
    printf("ā•‘                    ALL EXAMPLES COMPLETED                         ā•‘\n");
    printf("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•\n");
    
    return 0;
}

/* =============================================================================
 * HELPER FUNCTION
 * =============================================================================
 */
void print_separator(const char *title) {
    printf("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
    printf("  %s\n", title);
    printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n");
}

/* =============================================================================
 * EXAMPLE 1: Basic File Open and Close
 * =============================================================================
 * Demonstrates the fundamental pattern of opening and closing a file.
 */
void example1_basic_file_open_close(void) {
    print_separator("EXAMPLE 1: Basic File Open and Close");
    
    /*
     * FILE is a structure defined in stdio.h
     * FILE * is a pointer to this structure
     * Always initialize to NULL for safety
     */
    FILE *fp = NULL;
    const char *filename = "test_file.txt";
    
    printf("Step 1: Attempting to open file '%s' for writing...\n", filename);
    
    /*
     * fopen() syntax:
     *   FILE *fopen(const char *filename, const char *mode);
     * 
     * Returns: FILE pointer on success, NULL on failure
     */
    fp = fopen(filename, "w");
    
    /* Step 2: Always check if file was opened successfully */
    if (fp == NULL) {
        printf("ERROR: Could not open file '%s'\n", filename);
        return;
    }
    
    printf("SUCCESS: File '%s' opened successfully!\n", filename);
    printf("Step 2: File pointer address: %p\n", (void *)fp);
    
    /* Step 3: Write something to the file */
    fprintf(fp, "Hello, World!\n");
    fprintf(fp, "This is a test file created by example1.\n");
    printf("Step 3: Data written to file.\n");
    
    /*
     * Step 4: Close the file
     * fclose() syntax:
     *   int fclose(FILE *stream);
     * 
     * Returns: 0 on success, EOF on failure
     */
    printf("Step 4: Closing the file...\n");
    
    if (fclose(fp) == 0) {
        printf("SUCCESS: File closed successfully!\n");
    } else {
        printf("ERROR: Failed to close file\n");
    }
    
    /* Step 5: Set pointer to NULL after closing (good practice) */
    fp = NULL;
    printf("Step 5: File pointer set to NULL.\n");
    
    printf("\n[File '%s' created. You can verify its contents.]\n", filename);
}

/* =============================================================================
 * EXAMPLE 2: File Opening Modes
 * =============================================================================
 * Demonstrates different file opening modes and their behaviors.
 */
void example2_file_opening_modes(void) {
    print_separator("EXAMPLE 2: File Opening Modes");
    
    FILE *fp;
    const char *filename = "modes_test.txt";
    
    /* Mode "w" - Write mode (creates/truncates) */
    printf("═══ Mode 'w' (Write) ═══\n");
    printf("- Creates file if it doesn't exist\n");
    printf("- TRUNCATES (empties) file if it exists\n");
    printf("- Allows writing only\n\n");
    
    fp = fopen(filename, "w");
    if (fp != NULL) {
        fprintf(fp, "Line 1: Written in 'w' mode\n");
        fprintf(fp, "Line 2: This is the second line\n");
        fclose(fp);
        printf("File created with 2 lines.\n\n");
    }
    
    /* Mode "a" - Append mode */
    printf("═══ Mode 'a' (Append) ═══\n");
    printf("- Creates file if it doesn't exist\n");
    printf("- Preserves existing content\n");
    printf("- New content added at end\n\n");
    
    fp = fopen(filename, "a");
    if (fp != NULL) {
        fprintf(fp, "Line 3: Appended in 'a' mode\n");
        fclose(fp);
        printf("Line 3 appended to existing content.\n\n");
    }
    
    /* Mode "r" - Read mode */
    printf("═══ Mode 'r' (Read) ═══\n");
    printf("- Opens existing file for reading\n");
    printf("- Returns NULL if file doesn't exist\n");
    printf("- Cannot write to file\n\n");
    
    fp = fopen(filename, "r");
    if (fp != NULL) {
        char buffer[100];
        printf("Reading file contents:\n");
        printf("---\n");
        while (fgets(buffer, sizeof(buffer), fp) != NULL) {
            printf("%s", buffer);
        }
        printf("---\n");
        fclose(fp);
    }
    
    /* Mode "r+" - Read and Write */
    printf("\n═══ Mode 'r+' (Read/Write) ═══\n");
    printf("- Opens existing file for reading AND writing\n");
    printf("- Returns NULL if file doesn't exist\n");
    printf("- Does NOT truncate the file\n\n");
    
    fp = fopen(filename, "r+");
    if (fp != NULL) {
        /* Can read */
        char ch = fgetc(fp);
        printf("First character: '%c'\n", ch);
        
        /* Can also write (overwrites at current position) */
        /* We won't demonstrate here to preserve the file */
        
        fclose(fp);
    }
    
    /* Mode "w+" - Read and Write with truncate */
    printf("\n═══ Mode 'w+' (Read/Write, Truncate) ═══\n");
    printf("- Creates or truncates file\n");
    printf("- Allows both reading and writing\n");
    printf("- WARNING: Destroys existing content!\n\n");
    
    /* We'll create a new file to demonstrate */
    fp = fopen("w_plus_test.txt", "w+");
    if (fp != NULL) {
        fprintf(fp, "Written in w+ mode\n");
        
        /* Rewind to read what we wrote */
        rewind(fp);
        
        char buffer[100];
        if (fgets(buffer, sizeof(buffer), fp) != NULL) {
            printf("Read back: %s", buffer);
        }
        fclose(fp);
        remove("w_plus_test.txt");  /* Clean up */
    }
    
    /* Binary mode "b" */
    printf("\n═══ Binary Mode 'b' ═══\n");
    printf("- Add 'b' for binary files: 'rb', 'wb', 'ab', etc.\n");
    printf("- Important on Windows (newline translation)\n");
    printf("- No difference on Unix/Linux (but good practice)\n");
    
    fp = fopen("binary_test.bin", "wb");
    if (fp != NULL) {
        int data[] = {1, 2, 3, 4, 5};
        fwrite(data, sizeof(int), 5, fp);
        fclose(fp);
        printf("- Binary file created with 5 integers\n");
        remove("binary_test.bin");  /* Clean up */
    }
    
    /* Clean up test file */
    remove(filename);
}

/* =============================================================================
 * EXAMPLE 3: Error Handling with perror()
 * =============================================================================
 * Demonstrates using perror() for error messages.
 */
void example3_error_handling_with_perror(void) {
    print_separator("EXAMPLE 3: Error Handling with perror()");
    
    /*
     * perror() prints a descriptive error message to stderr.
     * It uses the global errno variable to determine the error.
     * 
     * Syntax: void perror(const char *s);
     * Output: s: error_description
     */
    
    printf("Attempting to open a non-existent file...\n\n");
    
    FILE *fp = fopen("this_file_does_not_exist.txt", "r");
    
    if (fp == NULL) {
        /* perror adds system error message */
        perror("fopen failed");
        
        printf("\nExplanation:\n");
        printf("- perror() prefixes your message\n");
        printf("- Then adds ': ' and the system error\n");
        printf("- Common error: 'No such file or directory'\n");
    } else {
        fclose(fp);
    }
    
    printf("\n--- Testing other common errors ---\n\n");
    
    /* Permission denied (trying to write to a read-only location) */
    printf("Attempting to write to /root (usually protected)...\n");
    fp = fopen("/root/test.txt", "w");
    if (fp == NULL) {
        perror("Cannot write to /root");
    } else {
        fclose(fp);
        remove("/root/test.txt");
    }
    
    /* Invalid path */
    printf("\nAttempting to open file in non-existent directory...\n");
    fp = fopen("/nonexistent_dir/file.txt", "w");
    if (fp == NULL) {
        perror("Cannot create file");
    } else {
        fclose(fp);
    }
}

/* =============================================================================
 * EXAMPLE 4: Error Handling with errno
 * =============================================================================
 * Demonstrates using errno for detailed error information.
 */
void example4_error_handling_with_errno(void) {
    print_separator("EXAMPLE 4: Error Handling with errno");
    
    /*
     * errno is a global variable set by system calls on error.
     * Defined in <errno.h>
     * 
     * strerror(errno) returns a string describing the error.
     */
    
    printf("Common errno values for file operations:\n");
    printf("ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”\n");
    printf("│ Macro     │ Value  │ Description                     │\n");
    printf("ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤\n");
    printf("│ ENOENT    │   2    │ No such file or directory       │\n");
    printf("│ EACCES    │  13    │ Permission denied               │\n");
    printf("│ EEXIST    │  17    │ File exists                     │\n");
    printf("│ EISDIR    │  21    │ Is a directory                  │\n");
    printf("│ EMFILE    │  24    │ Too many open files             │\n");
    printf("│ ENOSPC    │  28    │ No space left on device         │\n");
    printf("│ EROFS     │  30    │ Read-only file system           │\n");
    printf("ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n\n");
    
    /* Demonstrate errno usage */
    FILE *fp = fopen("nonexistent_file.txt", "r");
    
    if (fp == NULL) {
        printf("File open failed!\n");
        printf("errno value: %d\n", errno);
        printf("Error message: %s\n\n", strerror(errno));
        
        /* Check specific error types */
        switch (errno) {
            case ENOENT:
                printf("Analysis: File does not exist.\n");
                printf("Solution: Create the file first or check the path.\n");
                break;
            case EACCES:
                printf("Analysis: Permission denied.\n");
                printf("Solution: Check file permissions.\n");
                break;
            default:
                printf("Analysis: Error code %d occurred.\n", errno);
                break;
        }
    } else {
        fclose(fp);
    }
    
    /* Reset errno after handling */
    errno = 0;
    printf("\n[errno reset to 0 after handling]\n");
}

/* =============================================================================
 * EXAMPLE 5: Checking File Existence
 * =============================================================================
 * Different methods to check if a file exists.
 */
void example5_checking_file_existence(void) {
    print_separator("EXAMPLE 5: Checking File Existence");
    
    const char *existing_file = "existing_test.txt";
    const char *nonexistent_file = "this_file_does_not_exist.txt";
    
    /* Create a test file */
    FILE *fp = fopen(existing_file, "w");
    if (fp != NULL) {
        fprintf(fp, "Test content\n");
        fclose(fp);
    }
    
    printf("Method 1: Using fopen() with mode 'r'\n");
    printf("─────────────────────────────────────\n");
    
    /* Check existing file */
    fp = fopen(existing_file, "r");
    if (fp != NULL) {
        printf("  '%s': EXISTS\n", existing_file);
        fclose(fp);
    } else {
        printf("  '%s': DOES NOT EXIST\n", existing_file);
    }
    
    /* Check non-existing file */
    fp = fopen(nonexistent_file, "r");
    if (fp != NULL) {
        printf("  '%s': EXISTS\n", nonexistent_file);
        fclose(fp);
    } else {
        printf("  '%s': DOES NOT EXIST\n", nonexistent_file);
    }
    
    printf("\nMethod 2: Creating a reusable function\n");
    printf("──────────────────────────────────────\n");
    
    /* Inline function to check file existence */
    int file_exists(const char *filename) {
        FILE *f = fopen(filename, "r");
        if (f != NULL) {
            fclose(f);
            return 1;  /* File exists */
        }
        return 0;  /* File does not exist */
    }
    
    printf("  file_exists(\"%s\"): %s\n", 
           existing_file, 
           file_exists(existing_file) ? "true" : "false");
    printf("  file_exists(\"%s\"): %s\n", 
           nonexistent_file, 
           file_exists(nonexistent_file) ? "true" : "false");
    
    printf("\nNote: This method briefly opens the file.\n");
    printf("For better methods, use access() from <unistd.h> (POSIX)\n");
    
    /* Clean up */
    remove(existing_file);
}

/* =============================================================================
 * EXAMPLE 6: Standard Streams
 * =============================================================================
 * Demonstrates stdin, stdout, and stderr usage.
 */
void example6_standard_streams(void) {
    print_separator("EXAMPLE 6: Standard Streams");
    
    printf("C provides three predefined FILE pointers:\n\n");
    
    printf("ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”\n");
    printf("│ Stream     │ Pointer       │ Default Connection             │\n");
    printf("ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤\n");
    printf("│ stdin      │ FILE *stdin   │ Keyboard (input)               │\n");
    printf("│ stdout     │ FILE *stdout  │ Screen (normal output)         │\n");
    printf("│ stderr     │ FILE *stderr  │ Screen (error output)          │\n");
    printf("ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n\n");
    
    /* Using fprintf with standard streams */
    printf("Demonstrating fprintf with streams:\n\n");
    
    /* stdout - equivalent to printf */
    fprintf(stdout, "  fprintf(stdout, ...): This appears on standard output\n");
    
    /* stderr - for error messages */
    fprintf(stderr, "  fprintf(stderr, ...): This appears on standard error\n");
    
    printf("\nKey differences:\n");
    printf("  - stdout is line-buffered (output after newline)\n");
    printf("  - stderr is unbuffered (output immediately)\n");
    printf("  - stderr is separate from stdout for redirection\n\n");
    
    printf("Shell redirection examples:\n");
    printf("  ./program > output.txt    # Redirects stdout only\n");
    printf("  ./program 2> errors.txt   # Redirects stderr only\n");
    printf("  ./program > out.txt 2>&1  # Redirects both to same file\n");
}

/* =============================================================================
 * EXAMPLE 7: stderr Usage for Errors
 * =============================================================================
 * Shows proper use of stderr for error reporting.
 */
void example7_stderr_usage(void) {
    print_separator("EXAMPLE 7: stderr Usage for Errors");
    
    printf("Why use stderr for errors?\n");
    printf("──────────────────────────\n");
    printf("1. Error messages stay visible even when stdout is redirected\n");
    printf("2. stderr is unbuffered - messages appear immediately\n");
    printf("3. Separates normal output from error messages\n\n");
    
    /* Simulate an error condition */
    printf("Simulating a function that might fail:\n\n");
    
    int divide(int a, int b, int *result) {
        if (b == 0) {
            fprintf(stderr, "ERROR: Division by zero!\n");
            return -1;
        }
        *result = a / b;
        return 0;
    }
    
    int result;
    
    /* Successful case */
    if (divide(10, 2, &result) == 0) {
        printf("  10 / 2 = %d (output to stdout)\n", result);
    }
    
    /* Error case */
    printf("  Trying 10 / 0:\n  ");
    if (divide(10, 0, &result) != 0) {
        printf("  (above error went to stderr)\n");
    }
    
    printf("\nBest practice example:\n");
    printf("─────────────────────\n");
    
    FILE *fp = fopen("nonexistent.txt", "r");
    if (fp == NULL) {
        /* Error to stderr with context */
        fprintf(stderr, "FATAL: Cannot open configuration file 'nonexistent.txt'\n");
        fprintf(stderr, "       Please ensure the file exists.\n");
        fprintf(stderr, "       System error: %s\n", strerror(errno));
        /* In real code, might exit(1) here */
    }
    
    printf("  (The error messages above were sent to stderr)\n");
}

/* =============================================================================
 * EXAMPLE 8: fflush() Demonstration
 * =============================================================================
 * Shows how to force buffer flush to disk.
 */
void example8_fflush_demonstration(void) {
    print_separator("EXAMPLE 8: fflush() Demonstration");
    
    printf("What is buffering?\n");
    printf("─────────────────\n");
    printf("When you write to a file, data goes to a buffer first.\n");
    printf("The buffer is written to disk when:\n");
    printf("  1. The buffer is full\n");
    printf("  2. fflush() is called\n");
    printf("  3. fclose() is called\n");
    printf("  4. A newline is written (for line-buffered streams)\n\n");
    
    const char *filename = "flush_test.txt";
    FILE *fp = fopen(filename, "w");
    
    if (fp != NULL) {
        printf("Writing to file with fflush():\n");
        
        fprintf(fp, "Line 1 - written\n");
        printf("  Written Line 1 (in buffer)\n");
        
        fflush(fp);  /* Force write to disk */
        printf("  Called fflush() - data now on disk!\n");
        
        fprintf(fp, "Line 2 - written\n");
        printf("  Written Line 2 (in buffer)\n");
        
        printf("  Closing file (also flushes)...\n");
        fclose(fp);
        printf("  File closed.\n\n");
        
        /* Read back to verify */
        fp = fopen(filename, "r");
        if (fp != NULL) {
            printf("Contents of file:\n");
            char buffer[100];
            while (fgets(buffer, sizeof(buffer), fp) != NULL) {
                printf("  %s", buffer);
            }
            fclose(fp);
        }
        
        remove(filename);
    }
    
    printf("\nWhen to use fflush():\n");
    printf("─────────────────────\n");
    printf("  - Before a potential crash point\n");
    printf("  - For log files (ensure entries are saved)\n");
    printf("  - Before prompting for input (flush stdout)\n");
    printf("  - When data integrity is critical\n");
    
    printf("\nExample with stdout:\n");
    printf("  Without fflush: printf(\"Enter name: \");\n");
    printf("                  // May not appear before scanf!\n");
    printf("  With fflush:    printf(\"Enter name: \");\n");
    printf("                  fflush(stdout);\n");
    printf("                  // Guaranteed to appear first\n");
}

/* =============================================================================
 * EXAMPLE 9: File Pointer Validation
 * =============================================================================
 * Shows importance of validating file pointers.
 */
void example9_file_pointer_validation(void) {
    print_separator("EXAMPLE 9: File Pointer Validation");
    
    printf("Common mistakes with file pointers:\n\n");
    
    printf("1. Using a file after closing it:\n");
    printf("─────────────────────────────────\n");
    printf("   FILE *fp = fopen(\"file.txt\", \"r\");\n");
    printf("   fclose(fp);\n");
    printf("   fgetc(fp);  // UNDEFINED BEHAVIOR!\n\n");
    
    printf("2. Not checking for NULL before use:\n");
    printf("────────────────────────────────────\n");
    printf("   FILE *fp = fopen(\"nonexistent.txt\", \"r\");\n");
    printf("   fgetc(fp);  // CRASH - fp is NULL!\n\n");
    
    printf("3. Closing NULL pointer:\n");
    printf("────────────────────────\n");
    printf("   FILE *fp = NULL;\n");
    printf("   fclose(fp);  // UNDEFINED BEHAVIOR!\n\n");
    
    printf("4. Closing same file twice:\n");
    printf("───────────────────────────\n");
    printf("   FILE *fp = fopen(\"file.txt\", \"r\");\n");
    printf("   fclose(fp);\n");
    printf("   fclose(fp);  // UNDEFINED BEHAVIOR!\n\n");
    
    printf("SOLUTION: Defensive programming pattern\n");
    printf("───────────────────────────────────────\n");
    printf("   FILE *fp = NULL;  // Initialize to NULL\n");
    printf("\n");
    printf("   fp = fopen(\"file.txt\", \"r\");\n");
    printf("   if (fp == NULL) {  // Check before use\n");
    printf("       perror(\"Error\");\n");
    printf("       return;\n");
    printf("   }\n");
    printf("\n");
    printf("   // ... use file ...\n");
    printf("\n");
    printf("   if (fp != NULL) {  // Check before closing\n");
    printf("       fclose(fp);\n");
    printf("       fp = NULL;  // Prevent double-close\n");
    printf("   }\n");
}

/* =============================================================================
 * EXAMPLE 10: Safe File Open Function
 * =============================================================================
 * Creates a reusable safe file opening function.
 */

/* Reusable safe file open function */
FILE *safe_fopen(const char *filename, const char *mode, int verbose) {
    if (filename == NULL || mode == NULL) {
        if (verbose) {
            fprintf(stderr, "Error: NULL filename or mode provided\n");
        }
        return NULL;
    }
    
    FILE *fp = fopen(filename, mode);
    
    if (fp == NULL && verbose) {
        fprintf(stderr, "Error opening '%s' with mode '%s': %s\n",
                filename, mode, strerror(errno));
    }
    
    return fp;
}

void example10_safe_file_open_function(void) {
    print_separator("EXAMPLE 10: Safe File Open Function");
    
    printf("A reusable safe file open function:\n\n");
    
    printf("FILE *safe_fopen(const char *filename, const char *mode, int verbose) {\n");
    printf("    if (filename == NULL || mode == NULL) {\n");
    printf("        if (verbose) {\n");
    printf("            fprintf(stderr, \"Error: NULL filename or mode\\n\");\n");
    printf("        }\n");
    printf("        return NULL;\n");
    printf("    }\n");
    printf("\n");
    printf("    FILE *fp = fopen(filename, mode);\n");
    printf("\n");
    printf("    if (fp == NULL && verbose) {\n");
    printf("        fprintf(stderr, \"Error opening '%%s' with mode '%%s': %%s\\n\",\n");
    printf("                filename, mode, strerror(errno));\n");
    printf("    }\n");
    printf("\n");
    printf("    return fp;\n");
    printf("}\n\n");
    
    /* Demonstrate usage */
    printf("Testing the safe_fopen function:\n\n");
    
    /* Test 1: Successful open */
    FILE *fp = safe_fopen("safe_test.txt", "w", 1);
    if (fp != NULL) {
        printf("Test 1: Created 'safe_test.txt' successfully\n");
        fclose(fp);
        remove("safe_test.txt");
    }
    
    /* Test 2: Failed open (verbose) */
    printf("\nTest 2: Opening nonexistent file for reading:\n");
    fp = safe_fopen("does_not_exist.txt", "r", 1);
    if (fp == NULL) {
        printf("(Function returned NULL as expected)\n");
    }
    
    /* Test 3: NULL parameters */
    printf("\nTest 3: Passing NULL filename:\n");
    fp = safe_fopen(NULL, "r", 1);
    if (fp == NULL) {
        printf("(Function handled NULL gracefully)\n");
    }
}

/* =============================================================================
 * EXAMPLE 11: Working with Multiple Files
 * =============================================================================
 * Demonstrates opening and managing multiple files.
 */
void example11_multiple_files(void) {
    print_separator("EXAMPLE 11: Working with Multiple Files");
    
    printf("Opening and managing multiple files simultaneously:\n\n");
    
    FILE *input_file = NULL;
    FILE *output_file = NULL;
    FILE *log_file = NULL;
    
    /* Create input file with test data */
    input_file = fopen("input.txt", "w");
    if (input_file != NULL) {
        fprintf(input_file, "10\n20\n30\n40\n50\n");
        fclose(input_file);
    }
    
    /* Now open all files we need */
    input_file = fopen("input.txt", "r");
    output_file = fopen("output.txt", "w");
    log_file = fopen("process.log", "w");
    
    /* Check all files opened successfully */
    if (input_file == NULL || output_file == NULL || log_file == NULL) {
        fprintf(stderr, "Error: Could not open all required files\n");
        
        /* Clean up any that did open */
        if (input_file != NULL) fclose(input_file);
        if (output_file != NULL) fclose(output_file);
        if (log_file != NULL) fclose(log_file);
        
        return;
    }
    
    printf("All three files opened successfully:\n");
    printf("  - input.txt  (reading)\n");
    printf("  - output.txt (writing)\n");
    printf("  - process.log (logging)\n\n");
    
    /* Process: read numbers, double them, write output, log operations */
    fprintf(log_file, "Processing started\n");
    
    int number;
    int count = 0;
    
    while (fscanf(input_file, "%d", &number) == 1) {
        int result = number * 2;
        fprintf(output_file, "%d\n", result);
        fprintf(log_file, "Line %d: %d * 2 = %d\n", ++count, number, result);
    }
    
    fprintf(log_file, "Processing completed: %d lines\n", count);
    
    /* Close all files */
    fclose(input_file);
    fclose(output_file);
    fclose(log_file);
    
    printf("Processing complete!\n");
    printf("Read %d numbers, doubled each, wrote to output.\n\n", count);
    
    /* Display results */
    printf("Contents of output.txt:\n");
    output_file = fopen("output.txt", "r");
    if (output_file != NULL) {
        while (fscanf(output_file, "%d", &number) == 1) {
            printf("  %d\n", number);
        }
        fclose(output_file);
    }
    
    printf("\nContents of process.log:\n");
    log_file = fopen("process.log", "r");
    if (log_file != NULL) {
        char buffer[100];
        while (fgets(buffer, sizeof(buffer), log_file) != NULL) {
            printf("  %s", buffer);
        }
        fclose(log_file);
    }
    
    /* Clean up */
    remove("input.txt");
    remove("output.txt");
    remove("process.log");
}

/* =============================================================================
 * EXAMPLE 12: Binary vs Text Mode
 * =============================================================================
 * Shows the difference between binary and text modes.
 */
void example12_binary_vs_text_mode(void) {
    print_separator("EXAMPLE 12: Binary vs Text Mode");
    
    printf("Key Differences:\n");
    printf("────────────────\n\n");
    
    printf("Text Mode ('r', 'w', 'a', etc.):\n");
    printf("  - Newline translation (platform-dependent)\n");
    printf("  - On Windows: \\n <-> \\r\\n\n");
    printf("  - On Unix/Linux: No translation\n");
    printf("  - EOF character may be interpreted (Ctrl+Z on Windows)\n\n");
    
    printf("Binary Mode ('rb', 'wb', 'ab', etc.):\n");
    printf("  - No translation whatsoever\n");
    printf("  - Data is read/written exactly as-is\n");
    printf("  - Essential for non-text data\n\n");
    
    /* Demonstrate with a structure */
    printf("Demonstration: Saving a struct to file\n");
    printf("──────────────────────────────────────\n\n");
    
    struct Record {
        int id;
        float value;
        char name[20];
    };
    
    struct Record data = {42, 3.14159f, "TestRecord"};
    
    printf("Original data:\n");
    printf("  id: %d\n", data.id);
    printf("  value: %.5f\n", data.value);
    printf("  name: %s\n\n", data.name);
    
    /* Write in binary mode */
    FILE *fp = fopen("record.bin", "wb");
    if (fp != NULL) {
        fwrite(&data, sizeof(struct Record), 1, fp);
        fclose(fp);
        printf("Data written in binary mode.\n");
    }
    
    /* Read back in binary mode */
    struct Record loaded = {0, 0.0f, ""};
    fp = fopen("record.bin", "rb");
    if (fp != NULL) {
        fread(&loaded, sizeof(struct Record), 1, fp);
        fclose(fp);
        
        printf("\nLoaded data:\n");
        printf("  id: %d\n", loaded.id);
        printf("  value: %.5f\n", loaded.value);
        printf("  name: %s\n", loaded.name);
        
        printf("\nData integrity: %s\n",
               (data.id == loaded.id && 
                data.value == loaded.value &&
                strcmp(data.name, loaded.name) == 0) ? "VERIFIED" : "FAILED");
    }
    
    remove("record.bin");
    
    printf("\nWhen to use each:\n");
    printf("  Text mode:   .txt, .csv, .c, .h, .json, .xml\n");
    printf("  Binary mode: .bin, .dat, images, audio, executables\n");
}

/* =============================================================================
 * EXAMPLE 13: freopen() Demonstration
 * =============================================================================
 * Shows how to redirect standard streams using freopen().
 */
void example13_freopen_demonstration(void) {
    print_separator("EXAMPLE 13: freopen() Demonstration");
    
    printf("freopen() can redirect standard streams to files.\n\n");
    
    printf("Syntax:\n");
    printf("  FILE *freopen(const char *filename, const char *mode, FILE *stream);\n\n");
    
    printf("Common uses:\n");
    printf("  - Redirect stdout to a file\n");
    printf("  - Redirect stdin from a file\n");
    printf("  - Redirect stderr to a log file\n\n");
    
    /* Save stdout so we can restore it */
    printf("Demonstrating stdout redirection:\n");
    printf("(The next printf will go to 'redirected.txt')\n\n");
    
    /* Redirect stdout to file */
    FILE *original_stdout = stdout;
    FILE *fp = freopen("redirected.txt", "w", stdout);
    
    if (fp != NULL) {
        /* This goes to the file, not the screen */
        printf("This line is written to redirected.txt\n");
        printf("So is this line!\n");
        
        /* Close the redirected stream */
        fclose(stdout);
        
        /* Restore stdout (platform-specific) */
        #ifdef _WIN32
            freopen("CON", "w", stdout);
        #else
            stdout = fdopen(1, "w");  /* Unix/Linux */
        #endif
    }
    
    /* Now read and display the redirected content */
    printf("Contents of redirected.txt:\n");
    fp = fopen("redirected.txt", "r");
    if (fp != NULL) {
        char buffer[100];
        while (fgets(buffer, sizeof(buffer), fp) != NULL) {
            printf("  %s", buffer);
        }
        fclose(fp);
    }
    
    remove("redirected.txt");
    
    printf("\nNote: freopen() is often used for logging all program output.\n");
}

/* =============================================================================
 * EXAMPLE 14: Complete File Operations Workflow
 * =============================================================================
 * Shows a complete, production-quality file handling pattern.
 */
void example14_file_operations_workflow(void) {
    print_separator("EXAMPLE 14: Complete File Operations Workflow");
    
    printf("Best practice workflow for file operations:\n\n");
    
    const char *filename = "workflow_test.txt";
    FILE *fp = NULL;
    int exit_status = EXIT_SUCCESS;
    
    printf("Step 1: Open file with error handling\n");
    fp = fopen(filename, "w");
    if (fp == NULL) {
        fprintf(stderr, "  Error: Cannot open '%s': %s\n", 
                filename, strerror(errno));
        return;
    }
    printf("  File opened successfully.\n");
    
    printf("\nStep 2: Perform file operations\n");
    int result = fprintf(fp, "Line 1: Hello\n");
    if (result < 0) {
        fprintf(stderr, "  Error: Write failed\n");
        exit_status = EXIT_FAILURE;
        goto cleanup;
    }
    printf("  Wrote %d characters.\n", result);
    
    result = fprintf(fp, "Line 2: World\n");
    if (result < 0) {
        fprintf(stderr, "  Error: Write failed\n");
        exit_status = EXIT_FAILURE;
        goto cleanup;
    }
    printf("  Wrote %d more characters.\n", result);
    
    printf("\nStep 3: Check for stream errors\n");
    if (ferror(fp)) {
        fprintf(stderr, "  Error: Stream error occurred\n");
        exit_status = EXIT_FAILURE;
        goto cleanup;
    }
    printf("  No stream errors.\n");
    
    printf("\nStep 4: Flush buffer to ensure data is written\n");
    if (fflush(fp) != 0) {
        fprintf(stderr, "  Error: Flush failed\n");
        exit_status = EXIT_FAILURE;
        goto cleanup;
    }
    printf("  Buffer flushed successfully.\n");

cleanup:
    printf("\nStep 5: Close file\n");
    if (fp != NULL) {
        if (fclose(fp) != 0) {
            fprintf(stderr, "  Warning: Error closing file\n");
            exit_status = EXIT_FAILURE;
        } else {
            printf("  File closed successfully.\n");
        }
        fp = NULL;
    }
    
    printf("\nStep 6: Final status\n");
    printf("  Exit status: %s\n", 
           exit_status == EXIT_SUCCESS ? "SUCCESS" : "FAILURE");
    
    /* Display file contents */
    if (exit_status == EXIT_SUCCESS) {
        printf("\nVerification - File contents:\n");
        fp = fopen(filename, "r");
        if (fp != NULL) {
            char buffer[100];
            while (fgets(buffer, sizeof(buffer), fp) != NULL) {
                printf("  %s", buffer);
            }
            fclose(fp);
        }
    }
    
    remove(filename);
}

/* =============================================================================
 * EXAMPLE 15: Cleanup Pattern with Multiple Resources
 * =============================================================================
 * Shows proper cleanup when dealing with multiple resources.
 */
void example15_cleanup_pattern(void) {
    print_separator("EXAMPLE 15: Cleanup Pattern with Multiple Resources");
    
    printf("When working with multiple files and allocated memory,\n");
    printf("proper cleanup is essential to avoid resource leaks.\n\n");
    
    /* Resources we'll need */
    FILE *input = NULL;
    FILE *output = NULL;
    char *buffer = NULL;
    int result = EXIT_SUCCESS;
    
    printf("Resource acquisition:\n");
    
    /* Create test input file */
    FILE *temp = fopen("cleanup_input.txt", "w");
    if (temp != NULL) {
        fprintf(temp, "Test data line 1\nTest data line 2\n");
        fclose(temp);
    }
    
    /* Step 1: Open input file */
    input = fopen("cleanup_input.txt", "r");
    if (input == NULL) {
        fprintf(stderr, "  Failed to open input file\n");
        result = EXIT_FAILURE;
        goto cleanup;
    }
    printf("  Input file opened.\n");
    
    /* Step 2: Open output file */
    output = fopen("cleanup_output.txt", "w");
    if (output == NULL) {
        fprintf(stderr, "  Failed to open output file\n");
        result = EXIT_FAILURE;
        goto cleanup;
    }
    printf("  Output file opened.\n");
    
    /* Step 3: Allocate memory */
    buffer = (char *)malloc(1024);
    if (buffer == NULL) {
        fprintf(stderr, "  Failed to allocate memory\n");
        result = EXIT_FAILURE;
        goto cleanup;
    }
    printf("  Memory allocated.\n");
    
    /* Step 4: Process data */
    printf("\nProcessing:\n");
    while (fgets(buffer, 1024, input) != NULL) {
        /* Convert to uppercase */
        for (int i = 0; buffer[i] != '\0'; i++) {
            if (buffer[i] >= 'a' && buffer[i] <= 'z') {
                buffer[i] = buffer[i] - 'a' + 'A';
            }
        }
        fputs(buffer, output);
        printf("  Processed line: %s", buffer);
    }
    
    printf("\nAll operations completed successfully.\n");

cleanup:
    printf("\nCleanup:\n");
    
    /* Clean up in reverse order of acquisition */
    if (buffer != NULL) {
        free(buffer);
        buffer = NULL;
        printf("  Memory freed.\n");
    }
    
    if (output != NULL) {
        fclose(output);
        output = NULL;
        printf("  Output file closed.\n");
    }
    
    if (input != NULL) {
        fclose(input);
        input = NULL;
        printf("  Input file closed.\n");
    }
    
    printf("\nFinal status: %s\n", 
           result == EXIT_SUCCESS ? "SUCCESS" : "FAILURE");
    
    /* Remove test files */
    remove("cleanup_input.txt");
    remove("cleanup_output.txt");
    
    printf("\nKey points:\n");
    printf("  1. Initialize all pointers to NULL\n");
    printf("  2. Check each allocation/open\n");
    printf("  3. Use goto for consistent cleanup\n");
    printf("  4. Clean up in reverse order\n");
    printf("  5. Check for NULL before closing/freeing\n");
    printf("  6. Set pointers to NULL after cleanup\n");
}
Examples - C Programming Tutorial | DeepML