ExamplesC Programming

File Basics

File Handling / File Basics

Code Walkthrough
Intermediate
29 min

Learning Objective

Study worked examples for File Basics until you can trace the idea without guessing.

Why It Matters

Reading and running code turns the idea into behavior you can debug, modify, and reuse.

DemonstratesFundamentalOperationsOpeningClosing
Private notes
0/8000

Notes stay private to your browser until account sync is configured.

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

Skill Check

Test this lesson

Answer 4 quick questions to lock in the lesson and feed your adaptive practice queue.

--
Score
0/4
Answered
Not attempted
Status
1

Which module does this lesson belong to?

2

Which section is covered in this lesson content?

3

Which term is most central to this lesson?

4

What is the best way to use this lesson for real learning?

Your answers save locally first, then sync when account storage is available.
Practice queue