无格式/有格式输入输出
本节把 <stdio.h> 的 I/O 分成两类:
- 无格式 I/O:按字符或按字节块读写,不进行解析与格式化;
- 有格式 I/O:按格式字符串解析/生成文本(例如
printf/scanf家族)。
1. 无格式 I/O
1.1 字符 I/O:fgetc / fputc
c
#include <stdio.h>
int fgetc(FILE* stream);
int fputc(int ch, FILE* stream);1
2
3
4
2
3
4
它们以 int 形式返回读到的字符(或写入结果),并使用 EOF 表示失败或文件结束(对读操作)。
标准输入输出的便捷版本是:
c
int getchar(void); /* 等价于 fgetc(stdin) */
int putchar(int ch);/* 等价于 fputc(ch, stdout) */1
2
2
1.2 行 I/O:fgets / fputs
c
#include <stdio.h>
char* fgets(char* s, int n, FILE* stream);
int fputs(const char* s, FILE* stream);1
2
3
4
2
3
4
fgets 最多读入 n - 1 个字符,并保证以空字符终止;若读取失败返回空指针。
1.3 块 I/O:fread / fwrite
c
#include <stdio.h>
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream);
size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream);1
2
3
4
2
3
4
它们以“元素个数”为单位返回成功读写的元素数量。若返回值小于 nmemb,需要结合 feof / ferror 判断是文件结束还是错误(见 14.5)。
2. 有格式 I/O
2.1 printf 家族(输出)
c
#include <stdio.h>
int printf(const char* format, ...);
int fprintf(FILE* stream, const char* format, ...);
int snprintf(char* s, size_t n, const char* format, ...);1
2
3
4
5
2
3
4
5
它们返回输出的字符数(失败时返回负值)。
snprintf 的位置
snprintf 是把格式化结果写入字符数组的接口。为了避免写越界,应优先使用 snprintf,并检查返回值。
2.2 scanf 家族(输入)
c
#include <stdio.h>
int scanf(const char* format, ...);
int fscanf(FILE* stream, const char* format, ...);
int sscanf(const char* s, const char* format, ...);1
2
3
4
5
2
3
4
5
它们返回成功匹配并赋值的项数;若在任何赋值发生之前就到达文件结束,返回 EOF。
2.3 最常见的风险点
%s默认读入到空白符为止,且不会自动检查目标数组大小,容易写越界。scanf的返回值必须检查,否则输入失败时对象会保留旧值,导致后续逻辑错误。
示例:为 %s 指定最大宽度:
c
char name[16];
if (scanf("%15s", name) != 1) {
return 1;
}1
2
3
4
2
3
4
3. 习题
#11431
⚡4⏳3
写一个程序:逐行读取标准输入,并在每行前输出行号(从 1 开始)。
要求:
- 使用
fgets; - 正确处理超长行(即一次
fgets读不完一行的情况)。
#11432
⚡5⏳3
写一个程序:从标准输入读入若干个 int,计算它们的和并输出。
要求:
- 使用
scanf; - 正确处理“输入到达 EOF”与“输入格式错误”两种结束条件。