核心概念:流
在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
中,或读到换行符为止。它会自动在末尾添加