news 2026/9/6 4:48:27

scanf与cout的误区:探究其内部的机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
scanf与cout的误区:探究其内部的机制

目录

引入

误区

Ⅰ:scanf内的\n没有换行的作用

Ⅱ:空格也算一个字符

Ⅲ:按下enter后,会添加‘\n’在末尾

Ⅳ:输入过后剩余的字符不会丢弃

Ⅴ:scanf内部的空白作用

Ⅵ:cin的输入也会跳过空白字符

Ⅶ:endl的作用

全程过程详解

总结

小测

答案

误区Ⅷ:缓冲区有可用的,不会再读取


引入

#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> using namespace std; int main() { char a, b; scanf("%c%c", &a, &b); printf("%c %c\n", a, b); scanf("%c %c", &a, &b); printf("%c %c\n", a, b); cin >> a >> b; cout << '\n' << endl; cout << a << ' '<< b << endl; return 0; }

如果每次输入,都输入“a c”,结果是怎么样的?

a c//输入 a c a c//输入 a c a c//输入 a c

a c//输入 a a c//输入 a c a c//输入 a c

a c//输入 a a c//输入 c a a c//输入 a c

a c//输入 a a c//输入 c a a c//输入 c a

误区

答案是④,这个情景本来是我今天学c++测试不同的输入输出方式的区别我一开始幻想的结果是②的类型,可以运行后发现差别有点大,而我又不懂其中的机制,干脆就了解一下。

Ⅰ:scanf内的\n没有换行的作用

这是我一开始犯的错误,我记录一下以免再犯错,这点本身没什么可讲的,了解就可以了。



Ⅱ:空格也算一个字符

在第一次输入“a c”时候,会依次读出‘a’,' ','c','\n'四个字符(至于为什么最后会有一个‘\n’,后续会讲),所以第一次的输出会是‘a’+‘ ’+‘\n’(这个'\n'是printf里带有的);

只有%c(还有%[ ]扫描集)会把\n、空格、Tab 这类空白字符当成普通数据读入变量。

格式符是否读取空白(空格 /\n)
%c✅会读取,空白就是普通字符
%d/%f❌自动跳过空白,不读取空白
%s❌自动跳过开头空白,遇到空白结束,空白不读入
%[ ]扫描集可以配置,能接收换行 / 空格

Ⅲ:按下enter后,会添加‘\n’在末尾

对于操作系统控制台(黑框)

按下回车产生\n是告诉操作系统:这一行输入完毕,可以把整行数据交给程序

你敲一堆字符,不按回车,scanf是拿不到任何字符的。 从控制台设备角度\n触发行输入提交。

但是❗\n本身并没有 “结束输入” 的语义,它只是一个普通字符留在缓冲区里面,不会自动消失。

举例子: 输入:ab回车 缓冲区:'a''b''\n'\n只是把这一行放行给程序,它自己也留在缓冲区队列里,作为一个实实在在的字符

对于 scanf 函数本身

\n不代表 scanf 读取结束!

  • %d%f:读到数字结束就完成读取,后面的\n仅仅留在缓冲区,不会终止函数。
  • %c:把\n当成普通字符,直接读入变量。

c

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

输入1然后回车: 缓冲区:'1','\n'

  • a 拿到'1'
  • b 拿到'\n'scanf 直接执行完毕,不需要你继续输入。 👉这里\n被当成第二个有效字符,不是结束标记,是被读取的数据

Ⅳ:输入过后剩余的字符不会丢弃

会进入缓冲区,用于后续的读取

第一次输入输出后,就还剩下‘c’+‘\n’(enter产生的)留在了缓冲区

⚠️缓冲区就相当于一个队列,字符排队,先进先出。


Ⅴ:scanf内部的空白作用

scanf("%c %c")【中间带空格】:空格会吞噬空白;读完第一个字符之后,会把后面所有空白吃掉,再等待下一个有效字符。

第二步:scanf("%c %c", &a, &b);

格式字符串:"%c %c"

两个%c中间写了一个空格。 scanf 格式串内的空格规则:消耗任意数量空白字符(空格、Tab、\n),一直读到不是空白才停止

执行分步:

  1. 读到格式串第一个%c,准备读取字符。
  2. 遇见格式串里的空格:程序去缓冲区,跳过所有空白。 缓冲区队首现在是'c'——'c'不是空白!停止跳过。
  3. 第一个%c读取字符'c',赋值给a;现在a = 'c'
  4. 继续往后走,格式串又遇到一个空格,再次触发:吃掉所有空白。 现在缓冲区队列剩下:['\n'](就是你敲的回车)。'\n'属于空白,被空格规则消耗完毕,缓冲区空了。
  5. 来到第二个%c缓冲区已经空了!scanf 阻塞,等待你键盘输入新字符!

目前缓冲区域还有:[' ','c','\n'(enter产生)]


Ⅵ:cin的输入也会跳过空白字符

cin >>对于 char:自动跳过开头所有空白字符。 缓冲区队列现在:[' ', 'c', '\n']

  1. cin >> a:跳过开头空格,读取'c'存入a;队列剩余:['\n']
  2. cin >> b:缓冲区队首是'\n'属于空白,跳过;缓冲区空,阻塞等待键盘输入

Ⅶ:endl的作用

  1. '\n':输出 1 个换行
  2. endl输出 1 个换行,并且强制刷新缓冲区

👉cout << '\n' << endl;等于连续输出两次换行! 输出两个换行字符,中间就空出来一整行空白。

代码输出行为
cout << '\n';输出 1 次换行
cout << endl;输出 1 次换行 + 刷新 IO 缓冲区

所以:'\n' + endl=两个换行,这就是看见一大段空隙的根源。


全程过程详解

运行环境:VS Windows 控制台,文本模式,回车送入\n


第 1 段:第一次输入a c回车

键盘输入:

text

a c

缓冲区进入:

text

a 空格 c \n

第 2 段:执行第一个scanf("%c%c", &a, &b);

"%c%c"中间没有空格:

  • 第一个%ca
  • 第二个%c读后面的空格

所以:

cpp

a = 'a'; b = ' ';

缓冲区剩余:

text

c \n

执行:

cpp

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

输出:

text

a

注意:这里是a加一个空格再换行。


第 3 段:执行第二个scanf("%c %c", &a, &b);

格式串是:

c

"%c %c"

两个%c中间有一个空格。

这个空格的作用是:

在读取第二个%c之前,先吃掉缓冲区里所有连续空白。

当前缓冲区:

text

c \n

执行过程:

  1. 第一个%c直接读队首字符c
  2. 所以a = 'c'
  3. 缓冲区剩余:\n
  4. 格式串遇到中间的空格,开始清理空白
  5. \n属于空白,被清理掉
  6. 缓冲区变空
  7. 第二个%c需要新字符,程序等待输入

注意:

text

第二个 %c 不会读刚才剩下的那个 \n

因为格式串中间的空格已经先把\n吃掉了。


第 4 段:第二次输入a c回车

你输入:

text

a c

缓冲区进入新字符:

text

a 空格 c \n

第二个%c现在读取队首:

cpp

b = 'a';

所以当前变量是:

cpp

a = 'c'; b = 'a';

执行:

cpp

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

输出:

text

c a

第 5 段:缓冲区现在还剩什么?

刚才第二次输入是:

text

a 空格 c \n

其中a已经被第二个%c读走,所以缓冲区剩余:

text

空格 c \n

第 6 段:执行cin >> a >> b;

cin >>读取char时,会自动跳过开头空白。

当前缓冲区:

text

空格 c \n

执行过程:

  1. cin >> a先跳过空格
  2. 然后读取c
  3. 所以a = 'c'
  4. 缓冲区剩余:\n
  5. cin >> b看到队首是\n,也跳过
  6. 缓冲区空,程序等待输入

注意:

text

这里 a 被更新成了 'c'

第 7 段:第三次输入a c回车

你输入:

text

a c

缓冲区进入:

text

a 空格 c \n

cin >> b读取队首字符:

cpp

b = 'a';

所以现在变量变成:

cpp

a = 'c'; b = 'a';

不是a c

这里是之前文本最关键的错误。


第 8 段:执行输出

cpp

cout << '\n' << endl; cout << a << ' ' << b << endl;

先看第一句:

cpp

cout << '\n' << endl;

它会输出:

text

一个 \n 再加一个 endl

也就是连续两次换行。

所以控制台会先空出一行。

然后执行:

cpp

cout << a << ' ' << b << endl;

当前:

cpp

a = 'c'; b = 'a';

所以输出:

text

c a

不是a c


最终控制台完整结果

text

a c a a c c a a c c a

总结

图标关键点说明
🔑scanf("%c%c")无空格:原样读取,空格、\n全部当作普通字符存入变量
🔑scanf("%c %c")中间带空格:读完第一个字符,在读下一个 % c 之前吞噬全部空白\n不会被读到变量
📦输入缓冲区先进先出队列,键盘输入回车,往队列存入'\n'%d%f不会拿走\n,会遗留
⚠️经典坑%d之后直接跟%c%c会直接读取遗留的'\n',程序不等输入
修复方案%c格式里前面加空格:scanf(" %c", &ch);,读取前自动吃掉空白
🚫cout << '\n' << endl;\n换行,endl也换行 + 刷新;两个一起写 =两次换行,产生多余空白行
cin >> ch自动跳过所有空白(空格、\n、tab),不需要手动加空格

小测

阅读下面代码,假设运行在 Windows 环境,按下 Enter 会向输入缓冲区存入'\n',缓冲区先进先出。

c

#include <stdio.h> int main(void) { char x, y; scanf("%c%c", &x, &y); printf("%c %c\n", x, y); scanf("%c %c", &x, &y); printf("%c %c\n", x, y); return 0; }

用户键盘操作: 第一行输入:m n(m 和 n 之间 3 个空格),回车 第二行输入:s t,回车

请你作答:

  1. 第一次 printf 输出什么?变量 x、y 分别是什么?执行完第一个 scanf 之后,输入缓冲区剩余哪些字符?
  2. 第二个 scanf 内部每一步缓冲区如何变化?
  3. 第二次 printf 输出什么?

1.m+空格 m 空格 空格+空格+n+\n

2.先读走一个空格 再删去一个空格 再读走n 在最后面追加s+空格+t+\n

3.空+n

答案

输入:第一行m n(m 后面 3 个空格)+ 回车 缓冲区初始:['m',' ',' ',' ','n','\n']

问题 1

  1. 第一次printf输出:m
  2. 变量:x='m'y=' '
  3. 第一个 scanf 执行完,缓冲区剩余:[' ',' ','n','\n']

误区Ⅷ:缓冲区有可用的,不会再读取

问题 2,第二个scanf("%c %c", &x, &y);完整过程

起始缓冲区:[' ',' ','n','\n']

  1. 第一个%c读取队首空格,x=' ';缓冲区变为:[' ','n','\n']
  2. 遇到格式串中间的空格:吞噬所有连续空白,吃掉剩下的空格;缓冲区变为:['n','\n']
  3. 第二个%c读取'n'y='n';缓冲区变为:['\n']

缓冲区里有n可用,程序不会阻塞等待输入,第二行输入s t完全不会被读取

//实测的时候不会让你再输入了


问题 3

第二次printf("%c %c\n",x,y);x=' 'y='n'输出:n

解释:打印 x (空格),printf 自带的分隔空格,再打印 n。肉眼看:先一个空格,再一个空格,再字母 n。

感谢观看

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 4:44:44

Git 入门:从零开始的版本控制之旅

1. 什么是 Git&#xff1f;为什么你需要它&#xff1f; 想象一下&#xff0c;你正在写一篇超长的论文&#xff0c;改来改去&#xff0c;最后电脑里存了十几个文件&#xff1a; 论文_最终版.docx论文_最终版2.docx论文_最终版3_真的不改了.docx论文_最终版3_打死也不改了.docx…

作者头像 李华
网站建设 2026/9/6 4:39:54

deepseek:高缓存命中省token教程

先附上reasonix,pi的安装文件&#xff08;具体教程在zip文件中&#xff0c;后面都是环境配置和论述省token的原因&#xff09; https://pan.baidu.com/s/1cBvcOXxTAP3KIc_a0Ff8vQ?pwddfac 提取码:dfac https://pan.baidu.com/s/1fhOefpiXp6NF3mcdGCD_cg?pwd4z6a 提取码:4z…

作者头像 李华
网站建设 2026/9/6 4:39:47

如果你所在的行业,已经开始被 AI 渗透,先不必恐慌

如果你所在的行业&#xff0c;已经开始被 AI 渗透&#xff0c;先不必恐慌。最近不少老板都有这样的感受&#xff1a;同行借助 AI 批量产出文案、自动接待客户、快速生成设计初稿。市场报价被不断压低&#xff0c;订单越来越难承接&#xff0c;内心不由得开始焦虑&#xff1a;我…

作者头像 李华
网站建设 2026/9/6 4:37:11

AIAgent智能体开发实战:从零搭建到项目封装全指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 4:35:38

台风“白海豚”实测:海上工业视频监控部署与防抖防水全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华