详解scanf、gets、getchar和getch 使用及其原理。

2023-05-16

scanf、gets、getchar和getch 使用及其原理。

一、说在最前:回车及换行。

概念

在计算机还没有出现之前,有一种叫做电传打字机。在电传打字机打字时,在每行后面加两个表示结束的字符,分别叫做回车和换行。

回车:是告诉打字机把打印头定位在左边界,不卷动滚筒;符号 \r;十六进制 0x0d

换行:是告诉打字机把纸张向下方移动一行,不改变左右位置;符号 \n;十六进制 0x0a

区别

Unix系统里,每行结尾只有"<换行>",即按下Enter后会产生 ‘\n’ ( linux与 unix系统基本一致)

Win系统里,每行结尾是"<回车><换行>",即按下Enter后会产生 ‘\r’ 和 ‘\n’

Mac系统里,每行结尾是"<回车>",即按下Enter后会产生 ‘\r’
上述系统按下 Enter 后都会进行回车和换行操作,而产生的 ‘\r’ ‘\n’ 则会保留在 输入缓冲区

二、缓冲区

一般情况下,由键盘输入的字符并没有直接送入程序,而是被存储在一个缓冲区当中+。缓冲又分为两种,行缓冲和完全缓冲。对于完全缓冲来说,缓冲区满时被清空(内容被发送到指定的目的地)。这种缓冲通常出现在文件输入中。对于行缓冲来说,遇到一个换行符,则清空缓冲区,键盘输入是标准的行缓冲,因此,按下换行键(回车键)的时候才会清空(键盘缓冲区)。
键盘缓冲区的数据接下来会被传送到 输入缓冲区(stdin), 输入函数scanf、gets、getchar都是从输入缓冲区中获取数据的。如果输入数据过多或者输入缓冲区还有很多数据,那么下次调用输入函数时,不会要求你输入,而是直接从输入缓冲区中读取数据。
在这里插入图片描述

三、scanf、gets、getchar和getch 区别及一些原理。

1. scanf

scanf 指定了输入的格式,并按照格式说明符解析输入对应位置的信息并存储于可变参数列表中对应的指针所指位置。

从 scanf() 角度看输入

假设scanf() 根据一个%d转换说明读取一个整数:scanf 函数每次从输入缓冲区中读取一个字符,跳过所有空白字符,直到遇到第一个非空白字符才开始读取。因为要读取整数,所以 scanf 希望发现一个数字字符或者是 ’ + ’ 或 ’ - ’ 。如果找到一个数字或者 ’ + ’ 或 ’ - ’ ,它便保存该字符,并读取下一个字符。scanf 不断地读取和保存,直到遇到非数字字符。如果遇到一个非数字字符,它便认为读到了整数的末尾。然后 scanf 把非数字字符放回到输入缓冲区中。( 这就意味着程序在下次读取时,首先读到的是上一次读取时丢弃的非数字字符 ) 最后 scanf 计算已读数字相应的数值,并将计算后的值放入指定的变量中。

如果使用%s转换说明:scanf 会读取除空白字符以外的所有字符。scanf 跳过空白开始读取第1个非空白字符,并保存直到再次遇到空白字符。这就意味着 scanf 根据%s 转换说明读取一个不包括空白字符的字符串。当scanf 把字符串放进指定数组中时,它会在字符序列末尾加上’\0’,让数组内容成为一个C字符串。
空白符(空白符:指空格符、制表符、回车符)

例子解析
	现在假设你的缓冲区里有:abcd\n1234\n  (其中\n是回车符)  执行:scanf("%s",name);的时候
由于scanf是读数据直到看见空白符(空白符:指空格符、制表符、回车符)就停止的输入函数所以执行后,把abcd存到了name中。
缓冲区于是变成了 :\n1234

	接下来的执行就有问题了,如果遇到了:scanf("%d",&number);怎么办?因为遇到了回车符,它并不是一个数字。
所以scanf还有一个特性,就是忽略先导的空白符。不管是有几百个回车也好,几万个空格也罢,
只要它们连续地出现在缓冲区的开头,就统统忽略他们。然后再读有意义的字符。于是1234被读入number。

	回到刚刚,当缓冲区还是:\n1234\n的时候,如果遇到了:scanf("%c",&sex);应该怎么办呢?
你说,那好办呀,不是说了忽略前导空白符吗。
跳过回车读'1'呀!想法是好的,可这只针对你的程序这一种情况。如果我编写的程序就是统计用户输入了多少个回车呢
所以对scanf来讲跳过前导空白符有个例外,当参数是%c的时候,就把缓冲区的第一个字符返回回去,不管是什么。

	这样的设计就有个问题,scanf对不同的参数表现出来的特性不一样。得承认,这是个缺陷,但不是说这样不好。
这样的设计至少把发现所有字符的机会交给了用户,设计者这样想:如果程序员使用了scanf("%c",..)
那他就有必要知道这函数能把回车符读出来,至于程序员对回车符感不感兴趣,那就看他了
不感兴趣的话,程序员也一定知道该怎么处理。回到你的程序里。

	当执行scanf("%s",name)的时候,要求你从键盘输入,于是你输入了"abc",然后“回车”
缓冲区里自然而然地是:abc\n ,scanf把abc拿走了,留下了\n
缓冲区里现在就剩下\n于是,下一个scanf ("%c",&sex); 想当然地读取了\n

scanf ()

scanf 按格式从输入缓冲区内读取数据 (即从输入缓冲区中取出),读取并丢弃先导的空白符,直到非空字符才开始保存,当读取 到空白符,也就是 空格符、制表符、回车符时,停止读取并将空白符 放回 输入缓冲区 ( 注意:%c例外,不会放弃先导空白符,而是直接读取第一个字符 )。切记:键盘输入最后按下的回车键 会以 ‘\n’ 的形式存放进输入缓冲区,当scanf 以%c读取时会读入上一次键盘输入末尾的 \n 导致读取数据错误,所以用%c时要清空输入缓冲区,以免读取到垃圾数据。

注意:scanf("%d\n",&num); \n在scanf格式串中不表示等待换行符,而是读取并放弃 (丢掉,不放回输入缓冲区) 连续的空白字符。(事实上,scanf格式串中的任何空白字符都表示读取并放弃空白字符。而且,诸如%d这样的格式也会扔掉前边的空白,因此你通常根本不需要在scanf格式串中加入显式的空白。)

因此,"%d\n"中的\n会让scanf读到非空白字符为止,而它可能需要读到下一行才能找到这个非空白字符。这种情况下,去掉\n仅仅使用"%d"即可。

2. gets

gets从标准输入设备读字符串函数,可以无限读取,不会判断上限,以回车结束读取。所以如果输入的字符串超过100个,它也不会做检测,此时就会发生溢出。若输入未超过100个,则gets从输入缓冲区中读取数据 当读取到 \n
时,将 ‘\n’ 转换成 ‘\0’ 作为字符串结束标志。(\n并没有被放回去,所以不会产生像 scanf 读取完后留下 \n, 而导致下次读取单个字符的错误。)

3. getchar

从输入缓冲区中读取一个字符,若缓冲区中无数据就会等待用户输入,直到输入回车键,将数据输入到输入缓冲区。getchar可以用来清空缓冲区(防止读入垃圾数据)。
可以写成如下函数:

void clear_in(void)
{
	int c;
	while( (c=getchar() ) != '\n' && c != EOF);
}

getchar会一直读取字符直到输入缓冲区内没有数据(返回一个EOF = End Of File 文件结束),这样输入缓冲区就清空干净了。

4. getch

getch直接从键盘获取键值,不等待用户按回车,只要用户按一个键,getch就立刻返回。
getch是非缓冲输入函数,即不能用getch来接收缓冲区已存在的字符。
getch是无回显的读取 (不显示读取键值)。

注意:getch();并非标准C中的函数,不存在C语言中。所以在使用的时候要注意程序的可移植性。
1.所在头文件是conio.h。而不是stdio.h。
2.在使用之前要调用 initscr(),结束时要调用 endwin()。否则会出现不输入字符这个函数
也会返回的情况。
3.若使头文件 getch.h ,也会出现不输入字符这个函数直接返回的情况,可以使用多个getchar()来清空缓冲区。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

详解scanf、gets、getchar和getch 使用及其原理。 的相关文章

随机推荐

  • Zipwire

    文章目录 Chapter 55 Zipwire55 1 Chip specific Zipwire information52 2 Overview55 3 Introduction55 4 Zipwire Block Diagram55
  • arm启动过程详解

    ARM芯片的启动程序的分析和总结 2009 02 04 14 35 26 标签 xff1a 杂谈 分类 xff1a ARM 1 综述 xff1a 目前大多基于ARM芯片的系统都是一个比较复杂的片上系统 xff0c 多数硬件模块都是可配置的
  • 数据读写的乒乓操作

    数据读写的乒乓操作 文中一部分从其他博客中学习到 xff0c 加入了自己实际应用的过程 在重要数据的解帧与处理过程中 xff0c 为了确保数据的实时性与可靠性 xff0c 我们一般对收到的数据存储到芯片的RAM或Flash xff08 掉电
  • 生命在于学习——Linux提权

    本篇文章仅用于学习记录 xff0c 不得用于其他违规用途 一 内核漏洞提权 1 常规查找 查看内核版本信息 uname span class token operator span a uname span class token oper
  • 前入式JUC常用类源码分析

    CountDownLatch span class token keyword public span span class token keyword class span span class token class name Coun
  • dockerfile中的命令:run, cmd, entrypoint, copy和add

    总结一下 xff0c run 可以有多个 xff0c cmd 和entrypoint 只能有一个 xff08 常用来跑app xff09 cmd 可以被docker 指令overwrite xff0c entrypoint不可以 此命令会在
  • Qt类关系一览表

    Qt类关系一览表
  • ros之pid

    PID口诀 参数整定找最佳 xff0c 从小到 大顺序查 先是比例后积分 xff0c 最后再把微分加 曲线振荡很频繁 xff0c 比例度盘要放大 曲线漂浮绕大湾 xff0c 比例度盘往小扳 曲线偏离回复慢 xff0c 积分时间往下降 曲线波
  • 导 Kinect2库,opencv库,pcl库

    导 Kinect2库 opencv库 pcl库 Kinect2驱动安装 https blog csdn net qq 15204179 article details 107706758 ndfreenect2 cmake Kinect2
  • ros中订阅/map话题,获取地图尺寸,获取机器人原点origin,获取地图分辨率resolution (c++,python,waitForMessage,wait_for_message)

    ros中订阅 map话题 获取地图尺寸 获取机器人原点position 获取地图分辨率resolution 1 nbsp include lt ros ros h gt include lt nav msgs OccupancyGrid h
  • geometry_msgs::TransformStamped与geometry_msgs::PoseStamped消息互转

    geometry msgs TransformStamped与geometry msgs PoseStamped消息互转 下面是一个将geometry msgs TransformStamped转换为geometry msgs PoseSt
  • ros中获取小车当前位置

    ros中获取小车当前位置 一 tf2获取小车当前位置 xff1a include 34 tf2 ros transform listener h 34 include 34 tf2 ros buffer h 34 include 34 tf
  • 记一次被正点原子坑了的经历

    被正点原子坑 xff0c 不是买了他们的板子 xff0c 而是用了他们的一个Lwip的配置文件lwipopt h文件 xff0c 事情是这样的 xff0c 我现在开发的这个项目用lwip的库 xff0c 版本是1 4 1 xff0c 上手的
  • SecureCRT连接超时设置-The semaphore timeout period has expired

    设置 设置后就不会出现短时间没有操作连接超时的局面 xff0c 要求需要再次重连的问题 FR 徐海涛 xff08 hunk Xu xff09 QQ技术交流群 xff1a 386476712
  • CANoe-Trace-CAN Error

    CANoe软件CAN Error排查经验案例 系统模拟充电桩 xff0c 和实车车辆通过枪线连接 xff0c 启动充电流程 xff0c 在Trace界面看到CAN1有故障 xff0c CAN Error xff0c 并且是TxError 原
  • Makefile的使用

    Makefile规则 规则解析 一个简单的 Makefile 文件包含一系列的 规则 xff0c 样式如下 xff1a 目标 target 依赖 prerequiries lt tab gt 命令 command 目标 xff08 targ
  • STM32用一个定时器输出多路不同频率及占空比的PWM(输出比较模式)

    我们使用STM32输出PWM时会使用定时器的PWM输出模式来进行生成 xff0c 但是这样子生成PWM是有局限的 xff0c 它只能生成四路频率相同的PWM xff0c 当你设定了TIMx PSC xff08 预分频寄存器 xff09 和T
  • 虚拟机的安装与开发环境的配置

    前言 最近开始接触嵌入式 xff0c 之前也就学过C语言 xff0c 但是都是是非常基础的一些知识 知识最高峰的时期就是为了过国家计算机二级C 而一通猛学 下面就放入我最近学习笔记的内容 一 Linux开发环境的搭建 下载VirtualBo
  • C语言:基础知识

    基础C语言 基本知识 如何在虚拟机上写代码 1 打开终端 xff08 Ctrl xff0b Alt xff0b t xff09 xff0c mkdir day01 创建目录 cd 目录名 2 vim file c xff0c 进入vim文本
  • 详解scanf、gets、getchar和getch 使用及其原理。

    scanf gets getchar和getch 使用及其原理 一 说在最前 xff1a 回车及换行 概念 在计算机还没有出现之前 xff0c 有一种叫做电传打字机 在电传打字机打字时 xff0c 在每行后面加两个表示结束的字符 xff0c