c
examples
examples.cš§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");
}