ProgramGuru

C File Input, Output and Resource Cleanup

C File Input, Output and Resource Cleanup

A school report must be written and then read back. Opening a file can fail, writes can fail and the stream must be closed after use.

A FILE stream represents an input/output resource. Check whether opening succeeded, check the operations you require, and close each opened stream when its ownership ends.

  1. Explain

    Follow successful file creation, writing, repositioning, reading and closing.

  2. Trace

    Write Ravi: 83 to the same temporary-stream workflow.

  3. Apply

    Check a file operation and close the resource on the error path.

Files: follow the data

  1. Start

    A school report must be written and then read back. Opening a file can fail, writes can fail and the stream must be closed after use.

  2. Operation

    A FILE stream represents an input/output resource. Check whether opening succeeded, check the operations you require, and close each opened stream when its ownership ends.

  3. Result

    Read: Asha: 75

A guided model of this example. The illustration explains the process; run the complete C program to check its output.

Understand the operation

This complete example uses tmpfile to create a temporary binary update stream rather than overwrite an existing school file. A real named text file uses fopen with a documented path and mode, such as "r" for reading or "w" for writing with truncation.

An update stream has direction-change requirements. fflush finishes buffered output; a positioning operation such as rewind prepares the subsequent read. fclose can report a delayed write failure, so a successful earlier fprintf is not the entire success contract.

Read the complete C program

This complete C17 program uses a small school example. Read declarations before the statements that use their values. Each printf format describes how the corresponding value is written to standard output.

C17 · complete program

#include <stdio.h>
int main(void) {
  FILE *report = tmpfile();
  if (report == NULL) return 1;
  if (fprintf(report, "Asha: 75\n") < 0) { fclose(report); return 1; }
  if (fflush(report) == EOF) { fclose(report); return 1; }
  rewind(report);
  char line[32];
  if (fgets(line, sizeof line, report) == NULL) { fclose(report); return 1; }
  printf("Read: %s", line);
  if (fclose(report) == EOF) return 1;
  return 0;
}

Expected output

Read: Asha: 75
Run in C compiler →

Follow the values through the code

C17 · code used in this explanation

#include <stdio.h>
int main(void) {
  FILE *report = tmpfile();
  if (report == NULL) return 1;
  if (fprintf(report, "Asha: 75\n") < 0) { fclose(report); return 1; }
  if (fflush(report) == EOF) { fclose(report); return 1; }
  rewind(report);
  char line[32];
  if (fgets(line, sizeof line, report) == NULL) { fclose(report); return 1; }
  printf("Read: %s", line);
  if (fclose(report) == EOF) return 1;
  return 0;
}

The stream is checked before any write.

After the write is flushed and position reset, fgets reads the terminated report line. The program prints it and closes the stream.

Follow the worked calculation

  1. Read the starting values

    The stream is checked before any write.

  2. Perform the operation

    After the write is flushed and position reset, fgets reads the terminated report line. The program prints it and closes the stream.

  3. Check the observable result

    Read: Asha: 75

    Read: Asha: 75
A guided model of this example. The illustration explains the process; run the complete C program to check its output.

Try a small variation

C17 · code used in this explanation

#include <stdio.h>
int main(void) {
  FILE *report = tmpfile();
  if (report == NULL) return 1;
  if (fprintf(report, "Asha: 75\n") < 0) { fclose(report); return 1; }
  if (fflush(report) == EOF) { fclose(report); return 1; }
  rewind(report);
  char line[32];
  if (fgets(line, sizeof line, report) == NULL) { fclose(report); return 1; }
  printf("Read: %s", line);
  if (fclose(report) == EOF) return 1;
  return 0;
}

Write Ravi: 83 to the same temporary-stream workflow.

Worked answer

The record text changes, but the resource checks and release path stay in place. This temporary-stream exercise does not guarantee that a deployment permits creation of an arbitrary named file.

C17 · complete program

#include <stdio.h>
int main(void) {
  FILE *report = tmpfile();
  if (report == NULL) return 1;
  if (fputs("Ravi: 83\n", report) == EOF || fflush(report) == EOF) { fclose(report); return 1; }
  rewind(report);
  char line[32];
  if (fgets(line, sizeof line, report) == NULL) { fclose(report); return 1; }
  printf("Read: %s", line);
  if (fclose(report) == EOF) return 1;
  return 0;
}

Expected output

Read: Ravi: 83
Run in C compiler →

Recognize the important boundaries

EOF is an int sentinel distinct from an ordinary unsigned-char value. Store fgetc results in int until after checking for EOF.

Text and binary file behavior can differ across platforms. Do not serialize structure padding or pointer addresses as a portable student-record format.

Check your understanding

Choose the answer, then compare the reasoning for every option.

Why check fclose for an output stream?
Choose one answer. You can try again.

Answer and explanation

A buffered write failure may be reported when closing.

Correct. Earlier operations alone do not establish successful delivery of all output.

Use the idea independently

A FILE stream represents an input/output resource. Check whether opening succeeded, check the operations you require, and close each opened stream when its ownership ends.

Continue with failure paths and tests.

Language reference: WG14 C11 committee draft. These examples use the C17-compatible subset of the explained language features.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: C Headers, Prototypes and Separate Modules →