核心概念:流
在C语言中,所有的I/O操作都是通过“流”来完成的。流是一个字符序列,它可以是文件、物理设备(如键盘、屏幕)等。stdio.h 库预定义了三个标准流:
stdin: 标准输入流,默认连接到键盘。stdout: 标准输出流,默认连接到屏幕。stderr: 标准错误流,默认连接到屏幕。
格式化I/O函数
printf / fprintf / sprintf / snprintf (常用)
- 函数原型:
int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); int sprintf(char *str, const char *format, ...); int snprintf(char *str, size_t size, const char *format, ...); - 用途:
printf: 将格式化的数据输出到stdout(屏幕)。fprintf: 将格式化的数据输出到指定的stream(文件)。sprintf: 将格式化的数据输出到一个字符串str中。snprintf:sprintf的安全版本,最多向str写入size个字符,防止缓冲区溢出。
- 示例代码:
#include <stdio.h> int main() { char buffer[50]; int year = 2024; // 输出到屏幕 printf("Hello, World! Year: %dn", year); // 输出到文件 FILE *fp = fopen("log.txt", "w"); if (fp != NULL) { fprintf(fp, "Log entry for year %d.n", year); fclose(fp); } // 输出到字符串 (安全版本) snprintf(buffer, 50, "The year is %d.", year); puts(buffer); return 0; } - 注意事项:
- 类型匹配: 必须确保格式说明符(如
%d,%f,%s)与后面的参数类型和数量完全匹配。 - 缓冲区溢出: 绝对不要使用
sprintf!它不检查边界,极易造成缓冲区溢出。始终使用snprintf。
- 类型匹配: 必须确保格式说明符(如
scanf / fscanf / sscanf (常用)
- 函数原型:
int scanf(const char *format, ...); int fscanf(FILE *stream, const char *format, ...); int sscanf(const char *str, const char *format, ...); - 用途:
scanf: 从stdin(键盘) 读取格式化的输入。fscanf: 从指定的stream(文件) 读取格式化的输入。sscanf: 从一个字符串str中解析格式化的输入。
- 示例代码:
#include <stdio.h> int main() { int age; char name[50]; const char *data = "Charlie 30"; // 从字符串解析 sscanf(data, "%49s %d", name, &age); printf("从字符串读取 -> 姓名: %s, 年龄: %dn", name, age); return 0; } - 注意事项:
- 取地址符
&: 必须为非指针变量传递地址。 - 缓冲区溢出: 使用
%s时必须指定最大宽度,如%49s。 - 检查返回值: 必须检查函数返回的成功赋值的项数。
- 输入缓冲区残留:
scanf和fscanf会将换行符n留在输入缓冲区中,可能干扰后续的字符/行读取。
- 取地址符
字符I/O函数
fgetc / getc / getchar (常用)
- 函数原型:
int fgetc(FILE *stream); int getc(FILE *stream); // 通常实现为宏,更快但有副作用风险 int getchar(void); // 等价于 getc(stdin) - 用途: 从指定流或
stdin读取一个字符。 -
注意事项: 返回类型是
int而不是char,以容纳文件结束符EOF。必须用int变量接收返回值。
fputc / putc / putchar (常用)
-
函数原型:
int fputc(int character, FILE *stream); int putc(int character, FILE *stream); // 通常实现为宏 int putchar(int character); // 等价于 putc(character, stdout) - 用途: 将一个字符写入到指定流或
stdout。
ungetc (不常用)
- 函数原型:
int ungetc(int character, FILE *stream); - 用途: 将一个字符
character推回到输入流stream中,以便下一次读取时能再次读到它。每个流只保证能成功推回一个字符。
行/字符串I/O函数
fgets (常用)
- 函数原型:
char *fgets(char *str, int num, FILE *stream); - 用途: 强烈推荐的安全函数。从
stream读取最多num-1个字符到str中,或读到换行符为止。它会自动在末尾添加
