C语言scanf函数以及缓存详解

C语言scanf函数以及缓存详解前言自学到 C 语言 scanf printf getchar gets 的时候 我觉得这个几个函数并没有什么特别的难得 但是后来写程序的时候却出现了一些小错误总是解决不了 上网查了查 是对于 C 语言缓存的不理解 所以今天本篇博文就集中炮火 用我自己的理解 对这块知识进行一个剖析 本博文中有一些知识点我个人认为还是不成熟 我也没找到能让我信服的知识 如有大神指点迷津 欢迎在评论区留言

前言

  1. 以下代码都是在VC6.0环境下完成的;
  2. 对于缓冲这个知识,我觉得还有一些疏漏或错误,但是我又没找到很详尽的资料,有知道的朋友欢迎留言讨论;

需要清楚的几个知识点(以笔记本电脑为例)

  1. 人们一个传统的思维就是,笔记本是一个整体,键盘,鼠标,硬盘,显示器,话筒,摄像头,喇叭等都是一个整体;这些组合起来确实是一个笔记本,但是对于CPU来说,这些设备都是外部输入输出设备(I/O),输出的是什么,输入的是什么?是数据
  2. 什么是输入设备,什么是输出设备?
    输入设备:首先这是一个设备,设备的功能是用来输入信息;比如键盘,鼠标,咱们很容易理解键盘,当我在这儿敲打键盘写博客的时候,屏幕上会显示字,所以这是一个键盘向电脑输入信息的设备;这里注意:对于键盘来说,数据是在输入(到电脑),但对于CPU来说,数据是在读取
    输出设备:同理就是用来输出信息的设备,比如你眼前的这个笔记本电脑屏幕;屏幕可以显示动画,文字,图片和视频;同理还有打印机,咱们经常打印一个word文件,很显然,CPU讲这个word输出到打印机;此时,对于打印机和屏幕来说,数据是在读取,对于CPU来说,数据是在写入(到输出设备)

  3. C语言中scanf()函数的分隔符:空格(space),回车(enter),指标符(table);

scanf() :标准输入函数

定义:scanf()函数在stdio.h头文件中可以找到声明;如下图;
这里写图片描述
返回值:从上图中可以看出函数返回值类型是 int ,所以函数结束是有返回类型的;一般返回值为:EOF,0,1,2,3…其对应的意义是:
比如:scanf(“%d%d”,&x,&y);


返回值 意义
EOF 程序遇到错误或遇到end of file
0 x和y都没有被成功读入
1 只有x被成功读入
2 x和y都被成功读入

处理机制
scanf()以删除的方式从缓冲区读取数据(输入设备的数据存储缓冲区,比如键盘);也就是说,scanf从缓冲区读入一个数据项,该数据项在缓冲区中就被清除掉了。而如果scanf需要读取一个数据项,返现缓冲区当前是空的,那么程序就会在scanf代码处阻塞,等待用户输入,scanf函数接收到相应的数据项之后,在缓冲区中将这一数据项清除,scanf函数返回,程序继续执行。
我们以一个简单程序流程说明处理机制:

1.编写代码:

#include <stdio.h> void main() { int a; printf("请输入一个整数:"); scanf("%d",&a); printf("a=%d\n",a); }
  1. 输出结果
    这里写图片描述
  2. 处理机制 (这里只针对%d)
    这里写图片描述
    当程序执行到“scanf(“%d”,&a);”时,程序向CPU发出指令,要求其先检测输入缓冲内有没有数据,本程序内输入缓冲内没有数据,CPU开始等待输入设备(键盘)向输入缓冲内输入数据,这里咱们输入一个“2”,输入后按enter(回车),此时2和换行符一并被输入设备写入输入缓冲,输入缓冲检测到有回车进来了,CPU开始执行读取指令,将2读取后将其从输入缓冲清除,从输入缓冲将数据“2”赋值给a,由于a是一个具体的地址空间变量,所以赋值结束后,CPU将a的值写入输入缓冲,对于笔记本电脑而言,a的保存输出设备就是电脑硬盘,所以电脑硬盘就是输出设备;这样就完成了几个操作;(以上并不是详细的讲解,比如将2从输入设备删除后,还剩一个换行符没处理,下面说缓冲的时候再详细说)

  3. scanf对不同类型输入的处理方式
    4.1 整数%d
    对于整型数据的输入,也就是说”%d”类型的输入,scanf默认的分割符是所有的空白字符(空格,回车和指标符都行)。也就是说如果一个scanf函数中出现scanf(“%d%d”,&a,&b),那么用任何一个空白字符来分隔两个整数a,b的值,变量a,b都可以接收到正确的输入。另外,要注意的是,scanf对于数字输入,会忽略输入数据项前面的空白字符
    下面举个例子:


#include <stdio.h> void main() { int a,b; printf("请输入a和b的值:"); scanf("%d%d",&a,&b); //分隔符用空格 printf("a=%d\nb=%d\n",a,b); printf("----------------\n"); int c,d; printf("请输入c和d的值:"); scanf("%d%d",&c,&d); //分隔符用Tab printf("c=%d\nd=%d\n",c,d); printf("----------------\n"); }
#include <stdio.h> void main() { char a[5],b[5]; int i; printf("请输入a和b的值:"); scanf("%s%s",a,b); printf("a=%s,b=%s\n",a,b); for(i=0;i<5;i++) printf("%d:(%c) ",a[i],a[i]); printf("\n"); for(i=0;i<5;i++) printf("%d:(%c) ",b[i],b[i]); printf("\n"); printf("请再次输入a和b的值:"); scanf("%s%s",a,b); printf("a=%s,b=%s\n",a,b); for(i=0;i<5;i++) printf("%d:(%c) ",a[i],a[i]); printf("\n"); for(i=0;i<5;i++) printf("%d:(%c) ",b[i],b[i]); printf("\n"); }

4.3 字符%c (注意
scanf在处理对字符数据的输入时,既不会忽略前导空白字符,默认也没有任何分隔字符。所有的字符,包括空白字符都会被当成输入字符。举个例子:

 #include <stdio.h> void main() { char a ,b ; printf("请输入a和b的值:"); scanf("%c%c",&a,&b); printf("a=%c,b=%c\n",a,b); printf("请输入a和b的值:"); scanf("%c%c",&a,&b); printf("a=%c,b=%c\n",a,b); }

C语言中的缓冲区

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





缓冲区的刷新
下面几种情况将引起缓冲区刷新,也就是清空所有数据:
1) 缓冲区被写满;
2) 执行flush语句;
3) 执行endl语句;
4) 关闭文件;




fflush(stdin)函数清楚缓冲区
举例:

 #include <stdio.h> void main() { char a ,b ; printf("请输入a和b的值:"); scanf("%c%c",&a,&b); fflush(stdin); //清楚输入缓冲区; printf("a=%c,b=%c\n",a,b); printf("请输入a和b的值:"); scanf("%c%c",&a,&b); printf("a=%c,b=%c\n",a,b); }
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232518.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • [译] Android 生命周期备忘录 — 第三部分:Fragments

    [译] Android 生命周期备忘录 — 第三部分:Fragments

    2021年7月4日
    77
  • VM虚拟机桥接模式无法联网解决办法

    VM虚拟机桥接模式无法联网解决办法1.背景介绍:桥接模式—-使虚拟机客户机可以和主机在同一网段,这样,和主机同局域网内的其他主机就也可以ping到虚拟机了;因此,虚拟机设置为桥接模式,且设为静态IP,这样以后就可以方便的使用虚拟机了;2.问题描述:桥接模式之前是好用的,但是主机有一天突然宕机了,重启之后,打开虚拟机,发现主机和虚拟机客户机相互之间ping不通;测试:a.将虚拟机IP获取方式改为自

    2022年5月6日
    69
  • 深入理解Java注解类型(@Annotation)[通俗易懂]

    深入理解Java注解类型(@Annotation)[通俗易懂]【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)http://blog.csdn.net/javazejian/article/details/71860633出自【zejian的博客】关联文章:深入理解Java类型信息(Class对象)与反射机制深入理解Java枚举类型(enum)深入理解Java注解类型(@Annotation)深入理解

    2022年7月8日
    24
  • C 语言漏洞最严重,PHP 最易受攻击,程序员该怎么写代码?「建议收藏」

    C 语言漏洞最严重,PHP 最易受攻击,程序员该怎么写代码?

    2022年2月14日
    39
  • 如何运行SpringBoot项目

    如何运行SpringBoot项目最近在Ecplise上面写了一个简单的SpringBoot的测试项目,SpringBoot里面是有主函数的:我们知道的是在Ecplise上面找到这个主函数然后runas-&gt;javaApplication就可以了但是总不能一直不脱离Ecplise,总要出来自己单练的第一步:我就新建的一个文件夹boottest,然后右键导出整个工程:导出的是jar包,然后我们看…

    2022年10月13日
    2
  • 35岁以上的IT人士如果有一天被公司裁员了,该怎么办?

    35岁以上的IT人士如果有一天被公司裁员了,该怎么办?我觉得裁员和年龄无关,和本人的技能,工作态度,处事规则有关系。大家都知道华为裁员比例厉害,特别是对35岁以上的,会感到中年危机。但是我几个在华为的同学,都到了40岁了工作依然好好的,也没有见谁被裁掉。如果在工作中保持积极的态度,做事主动,平常多学习,和同事,领导的关系都不错,那么也不会被裁掉。作为已经到而立之年的中年人,给大家一点建议吧。在工作和生活中时刻保持乐观的心态,做事积极主动,多想多思考,与同事和领导友好相处,尽量让自己成为不可替代的人。那么你就不会被裁掉,也不会有中年危机。…

    2022年7月18日
    48

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号