Now that you can organize code with headers and source files, it is time to connect your program to the outside world. In C, stdio.h provides the core facilities for standard input/output and file handling. In this lesson we will practice console input (scanf, fgets) and file reading/writing (fopen, fgets, fprintf, fclose) together.
New Terms in This Post
- Standard input: The default input stream a program reads from, usually the keyboard
- Standard output: The default output stream a program writes to, usually the terminal
- File pointer: A
FILE *that stores the position and state of an open file - Buffer: A temporary block of memory that holds data before it is processed
Key Ideas
Study Notes
- Time required: 70–80 minutes
- Prerequisites: functions, arrays, pointers, experience splitting headers
- Goal: read values from standard input, open/close files, safely handle text files
We will focus on four flows:
- Understand when to choose
scanfversusfgets. - Use
fopento obtain aFILE *and always close it withfcloseafterward. - Read a file line by line to accumulate results.
- Check error cases and print meaningful messages.
Code Walkthrough
Reading Values from Standard Input
#include <stdio.h>
int main(void) {
int age;
double height;
printf("Enter age and height: ");
if (scanf("%d %lf", &age, &height) != 2) {
printf("Invalid input format.\n");
return 1;
}
printf("age = %d, height = %.1f\n", age, height);
return 0;
}
scanf splits input based on whitespace. It returns the number of items it successfully read, which is why the condition checks != 2 in this example. Always compare that result to catch errors.
Also remember that scanf stops at whitespace and can leave the newline character in the input buffer. If you call fgets immediately afterward, it may read that leftover newline as an empty line.
Reading Whole Lines with fgets
#include <stdio.h>
int main(void) {
char buffer[32];
printf("Enter your name: ");
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
printf("Input error\n");
return 1;
}
printf("Name: %s", buffer);
return 0;
}
fgets reads an entire line, including spaces. Always pass both the array and its size to avoid buffer overflows. The trailing newline may be included, so be aware of it. Unlike scanf, fgets does not return a count. It returns the buffer pointer on success and NULL on failure or end-of-file.
If you want to call fgets after scanf, flush the leftover newline first:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
}
stdin stands for “standard input.” For now you can treat it as “the keyboard input channel.”
Opening and Writing to a File
#include <stdio.h>
int main(void) {
FILE *fp = fopen("report.txt", "w");
if (fp == NULL) {
printf("Unable to open file.\n");
return 1;
}
fprintf(fp, "C study report\n");
fprintf(fp, "score = %d\n", 92);
fclose(fp);
printf("Created report.txt\n");
return 0;
}
Mode "w" creates the file or overwrites existing contents. Always check whether the file pointer is NULL, and always call fclose so buffered data is actually written. In real projects you might combine this with perror("fopen") to display the operating system’s error cause.
Reading a File and Computing Totals
#include <stdio.h>
int main(void) {
FILE *fp = fopen("scores.txt", "r");
int value;
int total = 0;
int count = 0;
if (fp == NULL) {
printf("Cannot open scores.txt.\n");
return 1;
}
while (fscanf(fp, "%d", &value) == 1) {
total += value;
count++;
}
fclose(fp);
if (count > 0) {
printf("Average = %.1f\n", (double)total / count);
} else {
printf("No data.\n");
}
return 0;
}
fscanf uses the same format specifiers as scanf but reads from a file. Check the return value every time. After the loop, guard against dividing by zero. This pattern works well when the file truly contains only integers—if a non-numeric token appears, the loop stops at that point.
Processing Files Line by Line
#include <stdio.h>
int main(void) {
FILE *fp = fopen("names.txt", "r");
char line[64];
int line_number = 1;
if (fp == NULL) {
printf("Cannot open names.txt.\n");
return 1;
}
while (fgets(line, sizeof(line), fp) != NULL) {
printf("%d: %s", line_number, line);
line_number++;
}
fclose(fp);
return 0;
}
This example prints each line exactly as read, newline included. When fgets returns NULL, you’ve hit EOF or an error, so exit the loop.
Why It Matters
I/O is the bridge between your program and its users or other systems. Standard input/output lets you exchange test data quickly, and file I/O enables basic logging, configuration, and reporting. Managing FILE * properly builds the habit of “release every resource you acquire,” which later applies to dynamic memory, sockets, and more.
Practice in CodeSandbox
The sandbox below uses CodeSandbox's Universal starter. For C, the key learning loop is still compile and run in the terminal, so recreate the lesson code as a source file and repeat that cycle directly.
💬 댓글
이 글에 대한 의견을 남겨주세요