字符串处理

在 C 语言中,字符串的处理一直是一大核心难点。针对字符串的输入和输出,标准库提供了各式各样的函数。很多初学者常被 getcharputcharscanfsscanffscanf 这几个函数绕晕。

虽然它们长得很像,但由于设计初衷不同,它们对字符串的操作方式、吞取空格的态度、以及适用的“水管(流)”有着千差万别。

今天我们就来专题对比一下这 5 个函数在字符串操作上的表现与核心差异。

一、 函数全景透视表

在深入细节前,我们先通过一张全局图表,看一下它们在操作字符串时的基本属性:

函数名核心功能每次操作的基本单位遇到空格/换行符适用流(水管)
getchar单字符输入1 个字符照单全收,当普通字符读取仅限标准输入(键盘)
putchar单字符输出1 个字符原样输出仅限标准输出(屏幕)
scanf格式化输入字符串/单词/各类数据视为分隔符(遇到即停止)仅限标准输入(键盘)
sscanf内存格式化解析从字符串中抠取数据视为分隔符(遇到即停止)内存缓冲区(字符串)
fscanf流格式化读取从流中解析数据视为分隔符(遇到即停止)所有输入流(文件/键盘等)

二、 逐个击破:它们是如何蹂躏或组装字符串的?

1. getcharputchar —— 搬砖式逐字拼装

这两个函数本是为“单字符”设计的,但它们却是构建任意超长字符串的最底层基石。

  • 对字符串的操作:它们自己不懂什么是“字符串”,只能靠死板的循环。通过 getchar 一个一个字符读入并塞进字符数组,或者通过 putchar 一个一个输出。

  • 对待空格/换行的态度极度宽容。无论是空格、制表符(\t)还是换行符(\n),在它们眼里一视同仁,全是合法的字符。因此,如果你想读取带有一整大段空格和换行的英文文章,它是最不会漏掉细节的。

  • 代码示例

    C

    char str[100];
    int i = 0, ch;
    // 只有遇到换行,才停止读取字符串
    while ((ch = getchar()) != '\n' && ch != EOF && i < 99) {
        str[i++] = ch;
    }
    str[i] = '\0'; // 必须手动补上字符串结束符
    

2. scanf —— 粗暴的“单词”切割机

这是大家最熟悉的函数,但在处理字符串时,它有一个著名的致命特性

  • 对字符串的操作:使用 %s 占位符来读取一串字符,并自动在末尾补 \0

  • 对待空格/换行的态度极度敏感(视为终结者)scanf 在读取字符串时,一看到空格、\t\n,就会认为这个单词结束了,立刻停下来。

  • 致命痛点:如果你输入 "Hangzhou Dianzi University"scanf("%s", str) 只会悄悄吞下 "Hangzhou",后面的文本全被遗弃在输入缓冲区里。所以它不适合读取带空格的完整句子

  • 代码示例

    C

    char str[50];
    scanf("%s", str); // 输入 "Hello World",str 里面只有 "Hello"
    

3. sscanf —— 字符串高级“解剖刀”

这个函数非常特殊,它的输入源不是键盘,也不是文件,而是一块已经存在于内存中的字符串

  • 对字符串的操作:你可以把它看作是“字符串解剖工具”。它专门用来从一个大字符串中,按照特定格式把里面的数字、子字符串给“抠”出来。

  • 对待空格/换行的态度:与 scanf 一致,靠空格和格式文本来隔离、识别不同的信息。

  • 应用场景:常用于解析固定格式的文本日志、前后端交互的特定字符串。

  • 代码示例

    C

    char source[] = "ID:202601 Score:95.5 Name:Jack";
    int id; float score; char name[20];
    // 从 source 字符串里提取数据
    sscanf(source, "ID:%d Score:%f Name:%s", &id, &score, name);
    // 此时成功将字符串解构:id=202601, score=95.5, name="Jack"
    

4. fscanf —— 广阔无垠的“通用流吸尘器”

它是 scanf 的大哥。scanf 只能盯着键盘,而 fscanf 的眼里是整个星辰大海——只要是输入流(文件、网络流、键盘),它都能吸取数据。

  • 对字符串的操作:从指定的文件指针或其他输入流中,按照格式读取字符串。

  • 对待空格/换行的态度:与 scanf 完全一样,遇到空白字符就停止对当前 %s 的读取。

  • 应用场景:最常用于读取配置文件、数据库导出的文本报表。一行行地解析文件中的结构化数据。

  • 代码示例

    C

    FILE* pf = fopen("student.txt", "r");
    char name[30];
    if (pf != NULL) {
        // 从文件中读取一个单词/字符串
        fscanf(pf, "%s", name); 
        fclose(pf);
    }
    

三、 核心维度横向大比拼

为了在写代码时能精准选型,我们从两个最高频的开发维度来对比:

1. 边界安全维度(防缓冲区溢出)

  • getchar:安全可控。因为是程序员自己写循环控制次数(如 i < 99),所以绝不会溢出。

  • scanf / sscanf / fscanf默认极度危险。如果使用不带长度限制的 %s,用户输入一个 1000 字节的字符串,而你的数组只有 10 字节,程序会直接崩溃(或被黑客攻击)。

    • 防御方案:必须限制最大读取长度,写成 %99s(最多读 99 字节)。

2. 空间吞噬维度(如何读取带空格的字符串?)

  • 如果字符串包含空格(如 "C Language Paper"):

    • ❌ 判死刑scanffscanfsscanf 配合 %s 无法直接读取,它们会断章取义。

    • ✅ 选用:使用 getchar 循环读取;或者使用本文未列出但极其擅长此道的 fgets 函数。

    • 💡 进阶高级黑客写法scanf 家族可以使用谓词字符集 %[^\n](意思是:除了换行符,什么都抓),这样也能强行让它们吞下空格。

四、 总结:什么时候该用谁?

理清了它们的脾气后,我们在写 C 语言代码时可以遵循以下金标准:

  1. 如果需要从键盘输入、或者从文件里读取结构化的账目/表格数据(如 书名 价格 数量),毫不犹豫选择 scanffscanf

  2. 如果你的程序收到了别人传给你的一长串复杂字符串,你需要从中提取出有用的数字和标签,立刻使用 sscanf 进行格式化解剖。

  3. 如果需要做最底层的文本过滤、字符计数、或者完全保留空格换行地读取整篇文章,请祭出最原生态的 getcharputchar

理解了它们对“流”的控制和对“空格”的判定,你对 C 语言字符串的掌控便能再上一个台阶。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值