C 基础(7) - 字符输入/输出和输入验证

C语言提供了多种函数来处理字符的输入和输出,最常用的是 scanf/printfgetchar/putchar

使用 scanfprintf

scanf 用于格式化输入,printf 用于格式化输出。对于单个字符,我们使用 %c 格式说明符。

复制代码
#include <stdio.h>

int main() {
    char ch;
    // 提示用户输入
    printf("请输入一个字符: ");
    // 读取一个字符
    scanf("%c", &ch);
    // 输出读取的字符
    printf("您输入的字符是: %c\n", ch);
    return 0;
}
使用 getcharputchar

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);
  • 使用 fgetsfgets 是更安全的替代方案,它会读取一整行,并且不会超出指定的缓冲区大小。

    复制代码
    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
相关推荐
小肝一下2 小时前
c++从入门到跑路——string类
开发语言·c++·职场和发展·string类
老花眼猫2 小时前
数学艺术图案画-曼陀罗(一)
c语言·经验分享·青少年编程·课程设计
无巧不成书02182 小时前
Unicode编码机制全解析:从核心原理到Java 实战
java·开发语言·java字符编码·unicode 15.1码点
楼田莉子2 小时前
设计模式:构造器模式
开发语言·c++·后端·学习·设计模式
lly2024062 小时前
Swift 析构过程
开发语言
mu_guang_2 小时前
计算机体系结构3-cache一致性和内存一致性的区别
java·开发语言·计算机体系结构
戏舟的嵌入式开源笔记2 小时前
上手RP2040(基于C SDK)
c语言·pico·嵌入式软件·rp2040
jolimark2 小时前
Windows下如何用GCC编译C语言?轻便方法分享
c语言·windows·git·mingw·gcc编译器
lingggggaaaa2 小时前
PHP模型开发篇&MVC层&动态调试未授权&脆弱鉴权&未引用&错误逻辑
开发语言·安全·web安全·网络安全·php·mvc·代码审计