C语言提供了多种函数来处理字符的输入和输出,最常用的是 scanf/printf 和 getchar/putchar。
使用 scanf 和 printf
scanf 用于格式化输入,printf 用于格式化输出。对于单个字符,我们使用 %c 格式说明符。
#include <stdio.h>
int main() {
char ch;
// 提示用户输入
printf("请输入一个字符: ");
// 读取一个字符
scanf("%c", &ch);
// 输出读取的字符
printf("您输入的字符是: %c\n", ch);
return 0;
}
使用 getchar 和 putchar
getchar() 从标准输入读取下一个字符,putchar(c) 将一个字符 c 写入标准输出。它们通常用于处理单个字符的流式操作。
#include <stdio.h>
int main() {
int c; // 使用int类型以正确处理EOF
printf("请输入字符(按Ctrl+D或Ctrl+Z结束):\n");
// 循环读取并输出字符
while ((c = getchar()) != EOF) {
putchar(c);
}
return 0;
}
输入验证的关键问题与技巧
直接读取用户输入往往不够安全,可能会遇到各种意外情况。输入验证是确保程序稳定性和安全性的关键步骤。
1. 输入缓冲区中的"残留"字符
这是一个非常常见且容易被忽视的问题。当你使用 scanf 读取一个数字或字符串后,用户按下的回车键(换行符 '\n')会留在输入缓冲区中。如果紧接着读取一个字符,scanf 会直接读取这个残留的换行符,而不是等待用户的新输入。
解决方案:
-
在
%c前加空格 :在scanf的格式字符串中,%c前面加一个空格(" %c"),可以告诉scanf跳过所有的空白字符(包括空格、制表符和换行符),直到遇到第一个非空白字符。 -
清空缓冲区:使用一个循环来读取并丢弃缓冲区中直到换行符的所有字符。
int c;
while ((c = getchar()) != '\n' && c != EOF);
2. 验证输入的有效性
scanf 函数会返回成功读取并赋值的变量数量。我们可以利用这个返回值来判断用户的输入是否符合预期的格式。
例如,当期望用户输入一个整数时,如果用户输入了字母,scanf("%d", &num) 的返回值将不是1。
3. 安全的字符串输入
使用 scanf 读取字符串(%s)时,如果不限制长度,当用户输入的字符串超过数组容量时,就会发生缓冲区溢出,这是一个严重的安全漏洞。
解决方案:
-
限制读取宽度 :在
%s中指定最大读取字符数,该数值应比数组大小小1,为字符串末尾的空字符'\0'留出空间。char name[20]; // 最多读取19个字符 scanf("%19s", name);
-
使用
fgets:fgets是更安全的替代方案,它会读取一整行,并且不会超出指定的缓冲区大小。char line[100]; printf("请输入一行文本: "); fgets(line, sizeof(line), stdin); // fgets会把换行符也读进来,通常需要手动移除 line[strcspn(line, "\n")] = '\0';
重定向和文件
在 C 语言中,"文件"不仅仅指存储在磁盘上的文档,它更是一种通用的数据输入/输出模型。而"重定向"则是改变程序默认输入输出目标的强大技术。
📁 文件操作基础
C 语言将所有输入输出都抽象为"流"(stream)。程序启动时,默认会打开三个标准流:
- stdin: 标准输入流,默认指向键盘。
- stdout: 标准输出流,默认指向屏幕。
- stderr: 标准错误流,也默认指向屏幕,但通常无缓冲,用于立即显示错误信息。
操作文件通常遵循"打开 → 读写 → 关闭"的三步流程。
1. 打开与关闭文件
使用 fopen 函数打开文件,它会返回一个 FILE* 类型的文件指针,后续所有操作都通过这个指针进行。使用完毕后,必须用 fclose 关闭文件以释放系统资源。
#include <stdio.h>
int main() {
// 以写入模式("w")打开文件
FILE *pf = fopen("myfile.txt", "w");
if (pf != NULL) {
// ... 执行读写操作 ...
fclose(pf); // 使用完毕后关闭文件
}
return 0;
}
2. 文件打开模式
fopen 的第二个参数指定了文件的访问模式。
| 模式 | 含义 | 文件不存在时 |
|---|---|---|
"r" |
只读 | 打开失败 |
"w" |
只写 | 创建新文件 |
"a" |
追加写入 | 创建新文件 |
"r+" |
读写 | 打开失败 |
"w+" |
读写 | 创建新文件 |
"rb", "wb" |
二进制只读/只写 | 同上 |
3. 文件读写函数
C 语言提供了一系列函数来读写文件,可以分为两类:
| 操作 | 函数 | 功能 | 示例 |
|---|---|---|---|
| 格式化读写 | fprintf / fscanf |
类似 printf/scanf,但作用于文件 |
fprintf(pf, "Age: %d", 25); |
| 字符/字符串读写 | fputs / fgets |
写入/读取字符串 | fgets(buffer, 100, pf); |
| 单字符读写 | fputc / fgetc |
写入/读取单个字符 | fputc('A', pf); |
| 二进制块读写 | fwrite / fread |
高效读写数据块(如数组、结构体) | fwrite(&data, sizeof(data), 1, pf); |
🔄 输入/输出重定向
重定向允许你改变标准流(stdin, stdout, stderr)的默认来源或目标。这在处理大量数据或需要自动化测试时非常有用,可以让你在不修改 scanf/printf 等核心代码的情况下,从文件读取输入或将输出保存到文件。
1. 在程序内部使用 freopen
freopen 函数可以将一个标准流重新关联到一个指定的文件。
#include <stdio.h>
int main() {
// 将标准输入(stdin)重定向到 input.txt
// 此后,scanf 将从 input.txt 读取数据
freopen("input.txt", "r", stdin);
// 将标准输出(stdout)重定向到 output.txt
// 此后,printf 将把内容写入 output.txt
freopen("output.txt", "w", stdout);
int a, b;
scanf("%d %d", &a, &b); // 从 input.txt 读取
printf("Sum: %d\n", a + b); // 写入 output.txt
// 关闭流
fclose(stdin);
fclose(stdout);
return 0;
}
2. 通过命令行进行重定向
这是一种更灵活的方式,无需修改和重新编译程序即可改变其输入输出行为。
| 命令 | 功能 | 示例 |
|---|---|---|
> |
将 stdout 重定向到文件(覆盖) |
./program > output.txt |
>> |
将 stdout 重定向到文件(追加) |
./program >> output.txt |
< |
将 stdin 重定向自文件 |
./program < input.txt |
2> |
将 stderr 重定向到文件 |
./program 2> error.log |
2>&1 |
将 stderr 合并到 stdout |
./program > all.log 2>&1 |