scanf函数读取数据 清空缓冲区

news2024/11/14 11:11:03

scanf函数读取数据&清空缓冲区

  • scanf 从输入缓冲区读取数据
    • 数据的接收
    • 数据存入缓冲区
    • scanf 中%d读取数据
    • scanf中%c读取数据
  • 清空输入缓冲区
    • 例子
    • 用getchar()吸收回车
    • 练习

scanf 从输入缓冲区读取数据

首先,要清楚的是,scanf在读取数据的时候,不是从键盘上读取,而是从输入缓冲区读取数据

数据的接收

我们从键盘上输入的全部数据,不管是数字还是字母还是空格回车Tab键等,操作系统在接收时,都是将它们当成字符来接收的。
比如,我们从键盘输入123,它表示的并不是数字123,而是字符'1'字符'2'字符'3'

数据存入缓冲区

在scanf中,从键盘中输入的一切数据,,不管是数字、字母、还是空格回车、Tab键等这些字符都会被当作数据存入缓冲区
当按下回车键时,scanf开始进入缓冲区读取数据,从前往后,依次取。

scanf 中%d读取数据

scanf中%d读取数据时,%d只识别“十进制整数”。
对于%d而言,空格、回车、Tab键都是区分数据与数据的分隔符
当scanf进入缓冲区读取数据的时候,如果%d遇到空格、回车、Tab键,那么它并不会采用,而是跳过取后面的数据,直到取到“十进制整数”为止。


%d以十进制整数形式读取整数,scanf函数依然是每次读取一个字符,而不是读取一整个数字,不会马上结束读取进行存储。
首先scanf函数从第一个输入开始检查,它会跳过所有空白字符,直到它发现一个数字或者符号(+或-),它便会保存该字符然后往下读取,如果接下来读取依然是数字,他就会不断地保存然后读取下一个字符直到遇见一个非数字字符,scanf函数认为这里是数字的结尾。
大家可以参考一个博主的这篇文章scanf函数到底怎么读取数字?
对于被跳过和取出的数据,系统会将它从缓冲区中释放掉
未被跳过或取出的数据,系统会将它一直放在缓冲区,直到下一个scanf来获取。

%d读取时中遇到字母,那么它不会跳过也不会取用,而是直接从缓冲区跳出
下面举个例子:

#include <stdio.h> 
int main() 
{ 	
    int a,b; 	
    scanf("%d", &a ); 	
    printf("a=%d ", a); 	
    scanf("%d",&b);
    printf("a=%d",b);
    return 0; 
} 

当输入1(空格)2(回车)时,输出结果为
——————————————
a=1 b=2
——————————————
当输入1(Tab)2(回车)时,输出结果为
——————————————
a=1 b=2
——————————————
当输入(空格)(空格)1(空格)2(回车)时,输出结果为
——————————————
a=1 b=2
——————————————
当输入1(回车)2(回车)时,输出结果为
——————————————
1
a=1
2
a=2
——————————————
从输出结果可以看出来,不管是多种形式123的次性全部输入完,还是一个一个输入4,输出结果都是一样的。
原因在于从键盘上输入的数据都会被依次存入缓冲区,不管是数字还是字符都会被当作数据存进去。
我们可以全部将数据全部存入缓冲区后再一个一个用scanf取出,也可以到缓冲区存入一个数据scanf读取一个数据再到缓冲区存入一个数据再用scanf读取一个数据。


%d读取时中遇到字母,那么它不会跳过也不会取用,而是直接从缓冲区跳出

#include <stdio.h> 
int main() 
{ 	
    int a,b; 	
    scanf("%d", &a ); 	
    printf("a=%d ", a); 	
    scanf("%d",&b);
    printf("a=%d",b);
    return 0; 
} 

当我们输入
a(空格)1(回车)时,输出为
——————————————
a=-858993460 b=-858993460
——————————————
为什么会是这样的结果呢?
scanf中%d从缓冲区读取数据,从前往后依次取,先读到的字符是字母a,那么它不会跳过也不会取用,而是直接从缓冲区跳出,那么变量a没有值,即未被初始化,变量b也没有值,所以输出a=-858993460 b=-858993460

scanf中%c读取数据

对于%d,在缓冲区,空格,回车,Tab键都只是分隔符,不会被scanf当成数据取用,%d遇到它们就跳过,取下一个数据.但是如果是%c,那么空格,回车,Tab键都会被当成数据输出给scanf取用.

#include <stdio.h> 
int main() 
{ 	
    char a,b; 	
    scanf("%c", &a ); 	
    printf("a=%c ", a); 	
    scanf("%c",&b);
    printf("a=%c",b);
    return 0; 
} 

当我们输入1(空格)2()回车时,输出结果为
——————————————
a=1 b=
——————————————
这是因为,当我们输入结束时,输入缓冲区的数据为1(空格)2(回车)
第一个scanf语句scanf从缓冲区读取一个字符,即字符1,将a=1 打印到屏幕上.
第二句scanf依然要从缓冲区读取数据,这时缓冲区还有数据,为(空格)2(回车),所以不需要我们再次从键盘上进行输入.scanf从缓冲区读取(空格),将此赋给变量b,b= 打印到屏幕上.

此时缓冲区剩下了2(回车).
但我们希望的是,将字符2赋值给变量b,所以我们希望将(空格)清理掉,让scanf读取字符2.

清空输入缓冲区

例子

下面,先看一个例子
我们要实现用户输入密码,输入完之后,需要用户进行确认(Y/N)

#include <stdio.h> 
int main() 
{ 	
    char password[20]; 	
    printf("请输入密码:>"); 	
    scanf("%s", password); 	
    printf("请确认(Y/N):"); 	
    char ch=0;
    scanf("%c",&ch);
    if (ch == 'Y') 		
        printf("确认成功\n"); 	
    else
		printf("确认失败\n"); 	
    return 0; 
}

当我们运行程序,运行结果为
在这里插入图片描述
我们还没有输入Y或者N,为什么会直接弹出来确认失败呢?
这是因为当我们输入密码> 123456(回车)时,scanf开始从输入缓冲区读取数据,第一个scanf语句,它只是读走了"123456",缓冲区剩下了(回车),对于第二个scanf语句,scanf依然从缓冲区读取数据,将留下缓冲区的(回车)读走.

所以我们希望我们可以清理先清理掉(回车),然后让用户自己输入Y/N.

用getchar()吸收回车

当我们要从输入流中取一个字符,但在之前使用过scanf,那么此时就必须要先用getchar()吸收回车。否则取到的将不是你想要的字符,而是scanf遗留在输入流中的回车。
我们对上面的程序进行修改:

#include <stdio.h> 
int main() 
{ 	
    char password[20]; 	
    printf("请输入密码:>"); 	
    scanf("%s", password); 	
    getchar(); //(1)
 
    printf("请确认(Y/N):"); 	
    char ch=getchar();  //(2)
   
   
    if (ch == 'Y') 		
        printf("确认成功\n"); 	
    else
		printf("确认失败\n"); 	
    return 0; 
}

对于语句(1),我们用getchar()吸收scanf在缓冲区留下的回车,简单,方便,都不需要将从缓冲区读到的回车赋值给一个字符变量.
对于语句(2),用getchar()缓冲区读取一个字符,将此赋值给字符变量ch.

修改后的结果为:
在这里插入图片描述

练习

题目一
在这里插入图片描述
题目描述
描述
KiKi想完成字母大小写转换,有一个字符,判断它是否为大写字母,如果是,将它转换成小写字母;反之则转换为大写字母。
输入描述:
多组输入,每一行输入一个字母。
输出描述:
针对每组输入,输出单独占一行,输出字母的对应形式。
代码实现(方法一)-----用scanf获取字符

#include <stdio.h> 
int main()  
{
    char ch;
    while(scanf("%c",&ch) != EOF)
    {
         getchar();//吸收回车
        if (ch>='a' && ch<='z')
            ch=ch-32;
        else if(ch>='A' && ch<='Z')
            ch =ch+32;      
        printf("%c\n",ch);
        
    }
    return 0; 
 }

代码实现(方法二)----用getchar()获取字符

#include <stdio.h> 
int main()  
{
    char ch;
    while((ch=getchar())!=EOF)
    {
         getchar();//吸收回车
        if (ch>='a' && ch<='z')
            ch=ch-32;
        else if(ch>='A' && ch<='Z')
            ch =ch+32;      
        printf("%c\n",ch);
        
    }
    return 0; 
}

代码实现(方法三)—使用库函数

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<ctype.h> 
//有库函数可以判断大写字母 -isupper 
//有库函数可以判断小写字母 -islower 
//大写转小写 -tolower 
//小写转大写 -toupper 
int main() 
{ 	
    char ch = 0; 	
    while(scanf("%c", &ch) == 1) 	
    { 		
        if (islower(ch)) 			
            printf("%c\n",toupper(ch)); 		
        else if (isupper(ch)) 			
            printf("%c\n", tolower(ch));
    } 	
    return 0;
} 

题目二
在这里插入图片描述
题目描述
描述
KiKi想判断输入的字符是不是字母,请帮他编程实现。
输入描述:
多组输入,每一行输入一个字符。
输出描述:
针对每组输入,输出单独占一行,判断输入字符是否为字母,输出内容详见输出样例。

#include<stdio.h> int main() 
{
    char a;
    while((a=getchar())!=EOF)
    {
        getchar();//吸收回车
        if(('a'<=a&&a<='z')||('A'<=a&&a<='Z'))
        {
            printf("%c is an alphabet.\n",a);
        }
        else
        {
             printf("%c is not an alphabet.\n",a);
        }
    } 
} 

当然这个代码也可以修改一下,不吸收回车

#include<stdio.h> int main() 
{
    char a;
    while((a=getchar())!=EOF)
    {
    
        if(('a'<=a&&a<='z')||('A'<=a&&a<='Z'))
        {
            printf("%c is an alphabet.\n",a);
        }
        else if
        {
             printf("%c is not an alphabet.\n",a);
        }
    } 
} 

用 if 和 else if,这样我们没有处理的回车,也不会满足其中的任何一个条件,而执行语句.
同时,也可以利用库函数:

#include <stdio.h>
#include <ctype.h> 
int main() 
{
    char a;
    while ((a = getchar()) != EOF)
    {
        getchar();//吸收回车
        if (isupper(a) > 0 || islower(a) > 0)
        {
            printf("%c is an alphabet.\n", a);
        }
        else
        {
            printf("%c is not an alphabet.\n", a);
        }
    }
        return 0; 
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/840461.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HttpServletRequest和HttpServletResponse的获取与使用

相关笔记&#xff1a;【JavaWeb之Servlet】 文章目录 1、Servlet复习2、HttpServletRequest的使用3、HttpServletResponse的使用4、获取HttpServletRequest和HttpServletResponse 1、Servlet复习 Servlet是JavaWeb的三大组件之一&#xff1a; ServletFilter 过滤器Listener 监…

分享一个页面

先看效果&#xff1a; 看下代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>顶部或底部特效</title><style>import url(//fonts.googleapis.com/css?familyLato:300:4…

(亲测解决)PyCharm 从目录下导包提示 unresolved reference(完整图解)

最近在进行一个Flask项目的过程中遇到了unresolved reference 包名的问题&#xff0c;在网上找了好久解决方案&#xff0c;并没有一个能让我一步到位解决问题的。 后来&#xff0c;我对该问题和网上的解决方案进行了分析&#xff0c;发现网上大多数都是针对项目同一目录下的py…

servlet生命周期和初始化参数传递

servlet生命周期和初始化参数传递 1、servlet生命周期 只有第一次访问才会初始化&#xff0c;之后访问都只执行service中的。 除非tomcat关闭重新启动&#xff1a; 2、初始化参数传递

在eclipse里进行Junit单元测试并生成测试报告

在eclipse里进行Junit单元测试&#xff0c;并生成测试报告 准备工作单元测试步骤1.引入Junit2.生成测试类3.生成测试报告 准备工作 eclipse里自带Junit&#xff0c;不需要下载相应jar包&#xff0c;所以你只需要新建一个Java Project&#xff0c;在里面写你想要测试的java类文…

【CodeWhisperer】亚马逊版代码生成工具

大家好&#xff0c;我是荷逸&#xff0c;今天给大家带来的是代码生成工具【CodeWhisperer】 CodeWhisperer简介 CodeWhisperer是亚⻢逊出品的一款基于机器学习的通用代码生成器&#xff0c;可实时提供代码建议。 在编写代码时&#xff0c;它会自动根据我们现有的代码和注释生…

数据特征选择 | Matlab实现具有深度度量学习的时频特征嵌入

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 数据特征选择 | Matlab实现具有深度度量学习的时频特征嵌入。 深度度量学习尝试学习非线性特征嵌入或编码器,它可以减少来自同一类的示例之间的距离(度量)并增加来自不同类的示例之间的距离。 以这种方式工作的…

Portraiture 4.0.3 for windows/Mac简体中文版(ps人像磨皮滤镜插件)

Imagenomic Portraiture系列插件作为PS磨皮美白必备插件&#xff0c;可以说是最强&#xff0c;今天它更新到了4.0.3版本。但是全网都没有汉化包&#xff0c;经过几个日夜汉化&#xff0c;终于汉化完成可能是全网首个Portraiture 4的汉化包&#xff0c;请大家体验&#xff0c;有…

IntelliJ IDEA 如何优雅的添加文档注释(附详细图解)

IntelliJ IDEA 如何优雅的添加文档注释&#xff08;附详细图解&#xff09; &#x1f4cc;提要✍✍类注释✍✍方法注释 &#x1f4cc;提要 在开发过程中&#xff0c;最常用的注释有两种&#xff1a;类注释和方法注释&#xff0c;分别是为类和方法添加作者、日期、版本号、描述等…

[ MySQL ] — 库和表的操作

目录 库的操作 创建数据库 语法&#xff1a; 使用&#xff1a; 字符集和校验规则 查看系统默认字符集以及校验规则 查看数据库支持的字符集 查看数据库支持的字符集校验规则 校验规则对数据库的影响 操纵数据库 查看数据库 显示创建语句 修改数据库 删除数据库 备…

【Jenkins】Jenkins 安装

Jenkins 安装 文章目录 Jenkins 安装一、安装JDK二、安装jenkins三、访问 Jenkins 初始化页面 Jenkins官网地址&#xff1a;https://www.jenkins.io/zh/download/ JDK下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/ 清华源下载RPM包地址&#xff…

dvwa靶场通关(十一)

第十一关&#xff1a;Reflected Cross Site Scripting (XSS) low 这一关没有任何防护&#xff0c;直接输入弹窗 <script>alert(xss)</script> 打开网页源代码&#xff0c; 从源代码中我们可以看到&#xff0c;前面是输出的第一部分Hello&#xff0c;我们输入的脚…

【C语言学习】整数的输入输出、八进制和十六进制

一、整数的输入输出 只有两种形式&#xff1a;int或long long %d:int %u:unsigned %ld:long long %lu:unsigned long long 二、八进制和十六进制 以0开头就是八进制&#xff0c;以0x开头就是十六进制。 无论是八进制还是十六进制只是如何将数字表达为字符串&#xff0c;但计…

Linux(进程)

Linux&#xff08;进程&#xff09; 1. 冯诺依曼结构体系2 . 操作系统&#xff08;OS&#xff09;3.进程task_ struct内容分类查看进程查看PID以及PPIDfork()Linux操作系统进程的状态僵尸进程孤儿进程进程优先级其他概念 1. 冯诺依曼结构体系 冯诺依曼结构也称普林斯顿结构&am…

一百四十六、Xmanager——Xmanager5连接Xshell7并控制服务器桌面

一、目的 由于kettle安装在Linux上&#xff0c;Xshell启动后需要Xmanager。而Xmanager7版本受限、没有免费版&#xff0c;所以就用Xmanager5去连接Xshell7 二、Xmanager5安装包来源 &#xff08;一&#xff09;注册码 注册码&#xff1a;101210-450789-147200 &#xff08…

css实现,正常情况下div从左到右一次排列,宽度超出时,右侧最后一个div固定住,左侧其他div滚动

需求:正常情况下 宽度超出时: 实现: <templete><div class"jieduanbox"><div v-for"(item, index) in stageList" :key"index" style"display: inline-block">.......</div><div class"rightBtn&q…

zookeeper --- 高级篇

一、zookeeper 事件监听机制 1.1、watcher概念 zookeeper提供了数据的发布/订阅功能&#xff0c;多个订阅者可同时监听某一特定主题对象&#xff0c;当该主题对象的自身状态发生变化时(例如节点内容改变、节点下的子节点列表改变等)&#xff0c;会实时、主动通知所有订阅者 …

【数据结构与算法】赫夫曼树

赫夫曼树 基本介绍 给定 n 个权值作为 n 个叶子结点&#xff0c;构造一棵二叉树&#xff0c;若该树的带权路径长度&#xff08;wpl&#xff09;达到最小&#xff0c;称这样的二叉树为最优二叉树&#xff0c;也称为哈夫曼树&#xff08;Huffman Tree&#xff09;&#xff0c;还…

并查集模板的应用:连通块

一、链接 837. 连通块中点的数量 二、题目 给定一个包含 nn 个点&#xff08;编号为 1∼n1∼n&#xff09;的无向图&#xff0c;初始时图中没有边。 现在要进行 mm 个操作&#xff0c;操作共有三种&#xff1a; C a b&#xff0c;在点 aa 和点 bb 之间连一条边&#xff0c…

全志F1C200S嵌入式驱动开发(soc系统集成)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 任何一个嵌入式设备都是由很多的子系统组成的。这里面有硬件、有软件,还可能有机械,并不一定就是大家看到的消费电子那样,即一个soc构成了所有的系统。现实情况是,要构建一个系…