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]);
}

相关内容

热门资讯

浦银经济带崛起混合A:2025... AI基金浦银经济带崛起混合A(519175)披露2025年四季报,第四季度基金利润5.58万元,加权...
从“车主”到“同学”:仰望商业... 在高端汽车市场,传统的用户关系往往止步于销售与服务。但比亚迪旗下高端新能源汽车品牌仰望,却在其独特的...
艺恩数据:2025年明星营销市... 今天分享的是:艺恩数据:2025年明星营销市场与趋势观察报告 报告共计:34页 2025年明星营销市...
临港半导体产业版图持续扩容 重... 一批重点项目集中开工投用 临港新片区半导体产业版图持续扩容 昨天上午,临港新片区举办2026年1月份...
嘉实基金方晗:2026年权益市... 来源:新浪财经 1月23日,嘉实基金举办“投资好时节”嘉实基金2026投资策略峰会。嘉实基金股票策...
小贷新规“余震”:融资性信保走... 来源:21世纪经济报道 21世纪经济报道记者 杨梦雪 高息贷款产品及其关联行业在一系列新规后“余震”...
和讯投顾郭磊:四条铁律,告别股... 1月23日,和讯投顾郭磊表示,在股市里长期稳定赚钱,靠的不是秘籍绝招,而是几条简单原则。今天就把这4...
思勇明升任德华安顾人寿董事长,... 德华安顾人寿 视觉中国 资料图 德华安顾人寿董事长改由外资股东委派。 1月22日,德华安顾人寿保险有...
甲状腺结节随访期,记住“三个平... 太原龙城中医医院科普:查出甲状腺良性结节后,很多人会陷入持续的焦虑中,既担心结节变化,又对随访充满忐...
华夏基金鲁亚运:“核心+卫星”... 来源:滚动播报 (来源:财闻) 2026年险资有望提供万亿级别的入市资金。 1月23日,在同花顺(...
海光信息大宗交易成交1.50万... 海光信息1月22日大宗交易平台出现一笔成交,成交量1.50万股,成交金额432.75万元,大宗交易成...
晚间公告|1月23日这些公告有... 【品大事】 华立股份:延期回复上交所对公司收购事项问询函 华立股份(603038)公告,公司于202...
百川生物59岁董事长陈彪曾是公... 瑞财经 刘治颖 1月22日,百川生物科技股份有限公司(以下简称:百川生物)在浙江证监局完成IPO辅导...
包良清父子控制87.18%表决... 瑞财经 严明会近期,丹东东方测控技术股份有限公司(以下简称:东方测控)科创板IPO获受理,保荐机构为...
“大龄青年安置小区”火了,20... 近日,浙江宁波一镇建造的“大龄青年安置房小区”引发关注。 “不是20岁就算大龄,它只是一个购房...
构建无缝协同网络:企业多分支机... 随着企业规模扩大、分支机构增多,跨地区、跨部门的远程协作变得日益重要。为此,构建一个稳定、专业的远程...
中国建材(03323)完成发行... 来源:智通财经网 中国建材(03323)发布公告,根据《中国建材股份有限公司2026年面向专业投资者...
2025年新增8家,山东推动银... 齐鲁晚报·齐鲁壹点记者 黄寿赓 实习生 宋佳睿 1月23日,中国人民银行山东省分行召开2025年山东...
182天!富森美董事长刘兵回归 文/乐居财经 张丹 横跨2025年和2026年,将近半年的时间,刘兵重新回到他原本的位置。 1月23...
机构席位买入898.39万 北... 每经讯,2026年1月23日,北交所上市公司能之光(920056,收盘价:30.45元)登上龙虎榜,...