C语言scanf函数的匹配和缓冲机制
创始人
2025-05-31 12:44:09
0

在这里插入图片描述

文章目录

    • scanf函数的数据匹配规则
    • 缓冲区的三种类型
      • 举例
    • 实战:通过几个问题搞明白缓冲机制
      • 问题 1:两个整型数据之间没有空格?
      • 问题 2:读取字符型数据时会把空格读入吗?
      • 问题 3:字符型数据和整型数据需要空格吗?
      • 问题 4:字符型数据之间的换行?(1)
      • 问题 5:字符型数据之间的换行?(2)
      • 问题 6:两个整型数据之间多个空行?
    • 一切的罪魁祸首:原来是缓冲区还有多余的数据!
      • 方法一:用 getchar() 把换行符吸收掉
      • 方法二:使用 fflush(stdin) 把输入缓冲区刷新一遍
    • 实战:空一行表示输入完毕

scanf函数的数据匹配规则

数据类型匹配规则
整型%d两个数据间的分割符可以是空格符(ASCII=32)、换行符(ASCII=10)、制表符(ASCII=9)
浮点型%f两个数据间的分割符可以是空格符(ASCII=32)、换行符(ASCII=10)、制表符(ASCII=9)
字符串%s以非空白字符开始,以第一个空白字符(空格符、换行符、制表符)结束
字符型%c两个数据间没有分割符,所有字符(包括控制字符)都能匹配

缓冲区的三种类型

缓冲区的三种类型:

  • 全缓冲:在这种情况下,当填满标准 I/O 缓存后才进行实际 I/O 操作。全缓冲的典型代表是对磁盘文件的读写。
  • 行缓冲:在这种情况下,当在输入和输出中遇到换行符时,才执行真正的 I/O 操作。这时,输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的 I/O 操作。典型代表是键盘输入数据,标准输入(stdin)和标准输出(stdout)。
  • 不带缓冲:也就是不进行缓冲,标准出错情况 stderr 是典型代表,这使得出错信息可以直接尽快地显示出来。

以下情况将引发缓冲区的刷新:

  • 缓冲区满时;
  • 行缓冲区遇到换行符 \n;
  • 关闭文件;
  • 使用特定函数刷新缓冲区。

scanf 函数的原理就是行缓冲!大家应该都有经验吧,比如输入一行数据,这些数据并非刚输入完就能被程序读取,还需要你按下回车键才能读取到。不过需要注意,用户最后输入的回车也会储存在缓冲区中。

举例

例子来源C语言输入输出缓冲区:

#include#includeint main() {printf("hello");int i = 0;for (; i < 10; i++) {putchar('a');sleep(1000); // 延时 1 秒钟}return 0;}

运行该程序,等待 10s 后,输出 helloaaaaaaaaaa。

这是由于键盘输入是标准的行缓冲,只有遇到换行符或者程序结束后才会输出到屏幕上

#include
#include
int main() {printf("hello");fflush(stdout);  // 刷新缓冲区,使得hello被强制输出,现在缓冲区什么都没有了int i = 0;for (; i < 10; i++) {putchar('a');sleep(1000); // 延时 1 秒钟}return 0;}

运行该程序,首先输出 hello,等待 10s 后,继续输出 aaaaaaaaaa。这是由于 fflush 刷新了缓冲区,所以会首先输出 hello。

现在用几道题目来解释缓冲机制,顺便加深对匹配规则的理解!

实战:通过几个问题搞明白缓冲机制

问题 1:两个整型数据之间没有空格?

【语句】

scanf("%d%d", &a, &b);

【输入】

1 2

【匹配情况】

a = 1, b = 2

【输入缓冲区分析】请注意,这是当你输入完数据并按下回车键后输入缓冲区里的情况,不能将运行窗口的输入输出混为一谈。它们不是同一个东西!

匹配前:

1 2\n

匹配后:

\n

【结论】连续输入两个数值时,两个数值之间必须有空格,无论 %d 是否紧挨着。scanf 函数就是靠空格、换行等匹配不同的数值,但匹配完后不会将换行符吸收掉。该语句等同于以下语句:

scanf("%d %d", &a, &b);

问题 2:读取字符型数据时会把空格读入吗?

【语句】

scanf("%c%c", &a, &b);

【输入 1】

xy

【匹配情况 1】

a = 'x', b = 'y'

【输入缓冲区分析 1】

  • 匹配前:
xy\n
  • 匹配后:
\n

【输入 2】

x y

【匹配情况 2】

a = 'x', b = ' '

【输入缓冲区分析 2】

  • 匹配前:
x y\n
  • 匹配后:
y\n

如果此时再来一个scanf(“%c%c”, &c, &d),则c = ‘y’, d = ’ '

【结论】开始匹配字符型数据时,scanf 函数不会忽略空格。如果你确实需要空格间隔,需改成:

scanf("%c %c", &a, &b);

问题 3:字符型数据和整型数据需要空格吗?

【语句】

scanf("%d%c", &a, &b);

【输入 1】

11y

【匹配情况 1】

a = 11, b = 'y'

【输入缓冲区分析 1】

  • 匹配前:
11y\n
  • 匹配后:
\n

【输入 2】

11 y

【匹配情况 2】

a = 11, b = ' '

【输入缓冲区分析 2】

  • 匹配前:
11 y\n
  • 匹配后:
y\n

【结论】当匹配完前一个数值后,scanf 函数在给出的格式中发现下一个数据是字符型数据,于是开始匹配字符型数据,此时不会忽略空格。如果你确实需要空格间隔,需改成:

scanf("%d %c", &a, &b);

问题 4:字符型数据之间的换行?(1)

【语句】

scanf("%c%c", &a, &b);

【输入】

x
y

【匹配情况】

a = 'x', b = ' '

【输入缓冲区分析】

  • 匹配前:
x\n
y\n
  • 匹配后:
y\n

【结论】scanf 函数在匹配字符型数据时,不仅匹配空格,还匹配任何字符,包括控制字符。所以字符 b 读入了换行字符 \n。

问题 5:字符型数据之间的换行?(2)

【语句】

scanf("%c", &a);
printf("a=%c\n", a);scanf("%c", &b);
printf("b=%c", b);

【输入 1】

x

【输出 1】然而,当你输入完 a,按下回车,输出 a 的同时,也输出了 b。

a = x
b = 

【输入缓冲区分析 1】

  • 第一次匹配前:
x\n
  • 第一次匹配后,并输出 a 的值为“x”,第二次匹配前:
\n
  • 第二次匹配后,b 匹配到了换行符 \n:

【输入 2】

xy

【输出 2】

a = x
b = y

【输入缓冲区分析 2】

  • 第一次匹配前:
xy\n
  • 第一次匹配后,并输出 a 的值为“x”,第二次匹配前:
y\n
  • 第二次匹配后,b 匹配到了“y”:
\n

问题 6:两个整型数据之间多个空行?

【语句】

scanf("%d%d", &a, &b);

【输入】

1 
(换行)
(换行)
2

【匹配情况】

a = 1, b = 2

【输入缓冲区分析】

第一个匹配前:

1\n

当你按了三次回车、并输入 2 前,其实第一个已经得到了匹配:

\n
\n
\n

第二个匹配前:

\n
\n
\n
2\n

第二个得到匹配后:

\n
\n
\n
\n

【结论】scanf 函数就是靠空格、换行等匹配不同的数值,而且必须严格按照给出的格式进行匹配(比如%d%d必须要两个整数,少一个都不行)。在没有匹配完成之前,无论有多少个空格和换行,都要等待用户输入下一个数据。

一切的罪魁祸首:原来是缓冲区还有多余的数据!

为什么实际的运行情况跟设想的不一样?为什么这个字符变量读到的是换行符?原来一切的罪魁祸首是:缓冲区还有多余的数据!缓冲区并没有设想的那样干净,而是残留了一些不该有的东西!那么如何解决呢?

方法一:用 getchar() 把换行符吸收掉

【语句】

scanf("%c", &a);
printf("a=%c\n", a);
getchar();scanf("%c", &b);
printf("b=%c", b);

【输入和输出】

x
a = x
y
b = y

【输入缓冲区分析】

  • 输入 a,第一次匹配前:
x\n
  • 第一次匹配后,并输出 a 的值为“x”:
\n
  • 执行 getchar,读取了换行符 \n,此时缓冲区为空:

  • 输入 b,第二次匹配前:
y\n
  • 第二次匹配后,b 匹配到了“y”:
\n

方法二:使用 fflush(stdin) 把输入缓冲区刷新一遍

需要注意,fflush 在有些编译器是没有的,它不属于 C 标准。不推荐使用。

【语句】

scanf("%c", &a);
printf("a=%c\n", a);
fflush(stdin); // 清理输入缓冲区scanf("%c", &b);
printf("b=%c", b);

【输入和输出】

输入:x
输出:a = x
输入:y
输出:b = y

【输入缓冲区分析】

  • 输入 a,第一次匹配前:
x\n
  • 第一次匹配后,并输出 a 的值为“x”:
\n
  • 执行 fflush,此时缓冲区为空:

  • 输入 b,第二次匹配前:
y\n
  • 第二次匹配后,b 匹配到了“y”:
\n

实战:空一行表示输入完毕

【描述】每行输入两个字符串,当输入到空行时,表示输入完毕。请输出这些字符串。

【输入实例】

aaa bbb
ccc ddd
eee fff
(该行空行,表示输入完毕)

该输入等价于:

aaa bbb\nccc ddd\neee fff\n\n

当读到只有 \n 的一行时,表示输入完毕。

【输出实例】

aaa bbb
ccc ddd
eee fff

【分析】这题很考验你对输入缓冲区原理的理解。每次检测字符串 A 的第一个字符,若第一个字符是 \n 则停止输入;若不是 \n,则用另一个字符串变量 B 读取剩下的字符串,并将 B 拼接到 A 的后面。除此之外,每读入一行字符串,就要吸收掉最后的 \n。

【题解】

#include 
#include 
using namespace std;int main(){	char word[20][20] = {0};char mean[20][20] = {0};char tmp[20];int i, j;for (i = 0; ; i++){if ((word[i][0] = getchar()) == '\n') //检测第一个字符break;word[i][1] = '\0';scanf("%s", tmp); // 读入 word 的剩余字符 scanf("%s", mean[i]);strcat(word[i], tmp);  // word 的第一个字符与剩余字符拼接在一起 tmp[0] = '\0'; // 清空字符串 getchar();  // 吸收换行符 }for (j = 0; j < i; j++)printf("%s %s\n", word[j], mean[j]);
}

相关内容

热门资讯

走进小城看消费丨江西资溪:低碳...   夏日时节下午4点,江西省抚州市资溪县大觉山景区漂流终点依然热闹。来自南昌的游客余鑫漂流结束后没有...
【中原晨会0625】市场分析专... 来源:市场资讯 (来源:中原证券研究所) 本期重点研报目录 【中原策略】市场分析:电子半导体领涨 ...
南向资金连买4日!低费率+可月... 6月25日早盘,港股红利资产震荡整理。截至11时14分,港股红利低波ETF招商(520550)下跌0...
618成交破百万!紫荆花用一套... 一年一度的618年中大促,是消费市场的晴雨表,也是品牌间最激烈的角力场。当各大品牌在直播间里铆足了劲...
原创 黄... 2026年6月25日的国际金价已经从前期的5500美元高点跌到4200美元下方,累计跌幅超过22%,...
英伟达CEO:Vera Rub... 截至9:38,中证半导体材料设备主题指数(931743)涨2.36%创新高;权重股中,中微公司涨3....
再被催债16亿!“钢铁大王”戴... 澎湃新闻记者 贺梨萍 因“铁本事件”入狱五年的戴国芳重返钢铁行业,但他并没有完成从阶下囚再到“钢铁大...
周三原油价格下跌 随着美国和伊朗在和平谈判中取得进展,越来越多的油轮公开穿越霍尔木兹海峡,原油在战时的价格上涨已经蒸发...
这种蛋白是大脑衰老的开关 这种蛋白是大脑衰老的开关 清晨,假设一位五十岁左右的王女士发现自己常常把手机放在熟悉的抽屉里又找不到...
信通院牵头算力Token出海生... 盘面上,截至11:04,中证科创创业50指数(931643)涨1.68%,创历史新高;权重股中,芯原...
海外 774 亿营收背后:日本... 文 | 游戏价值论 6月23日,彭博社报道了腾讯正在围绕出售多家日本游戏工作室少数股权开展谈判,包...
餐饮“抢人”大战:把店开到公交... 作者 |餐饮老板内参 内参君 医院、公交站、演唱会…餐饮品牌,正在无孔不入 在北京儿童医院,肯德基...
快讯 | 外资扫货!陈翊庭:港... 港交所行政总裁陈翊庭在接受《中国证券报》专访时指出,国际资本对中国资产的看法已彻底扭转,布局中国市场...
2777.77元!A股“股王”... 25日早盘,昨天创下历史新高的A股“股王”联讯仪器,今天上午继续走强,盘中股价再度刷新历史新高。 截...
原创 今... 欧洲自己的媒体直接下结论,欧盟衰退躲不掉,内部分裂拦不住,现在就连欧洲顶尖工业巨头,都偷偷在用中国的...
黄仁勋股东大会放言:本轮AI基... 在当地时间6月24日的英伟达(NVDA.O)2026年度股东大会上,股东批准了该公司全部10名董事会...
国际油价大跌 新华社消息, 纽约原油期货主力合约价格24日盘中跌破每桶70美元,为伊朗战事爆发以来首次。 市场分析...
马云带队插秧,什么信号? 一场别开生面的“务农”,让外界看到了一个不一样的阿里巴巴。 近日,阿里巴巴合伙人、高德董事长刘振飞在...
全球最大产能,最高丰度达99.... 本文转自【科技日报】; 6月23日,高丰度硼-10同位素技术暨产业化成果发布会在山东省东营市举办,全...
黄金大跳水!金饰克价年内暴跌近... 25日,现货黄金盘中震荡,截至发稿,报3985.070美元/盎司,跌0.17%。 当地时间24日,...