令博主崩溃的scanf函数-C语言

简介: 令博主崩溃的scanf函数-C语言

前言:


 这篇博客的来源呢,源于一个同学在学习群里发出一段代码,他对代码有疑惑,疑惑的是,为什么只有输出三行,而不是四行?实际上误打误撞的巧合。我在看完那段代码和他的问题之后,和他一起探讨和发挥猜想,更进一步的了解了scanf的使用。


1.了解scanf()、getchar()和putchar


 这段代码相信大家都能懂,如果能让你有点不懂的那就是忘记了getchar()和putchar的一些使用方法 。嗯我们循序渐进,跟着我一起思考!


2.scanf输入的奇怪现象


 其实,我想说的是这个b里的10并不是随机来的,我们还敲了个回车,这时你就问,敲回车不只是为了让scanf确认读取吗?还能有其它作用?


 补充:换行符('\n')的ASCII码值为10,回车('\r')的ASCII码值为13,我们日常说的回车和ASCII码值是不一样,口头说的回车是换行的意思。


 我这补充一说,大家伙可能就知道b里的10怎么来的了吧,没错,就是回车被getchar()读走了。


 输入缓冲区:当我们用在输入的时候,是有这样一块区域存在的,它用来存放你输入的信息,scanf()和getchar()看到这块区域没有内容,就会停下来等你输入。


3.scanf格式对回车的处理


我们看这段,当我们输入5然后回车,第二个scanf并没有让我们等待,而是直接跳过,来到getchar()这等待,因为缓冲区里有回车,并且是scanf("%c", &b);想要的内容,它就直接读取了,而且不需要你回车,这点可以用后面的getchar()等待来证明。


   那这两个连续的输入是怎么实现的呢?当我输入一个5和回车的时候,到第二个scanf("%d", &b);不应该是直接就跳过了吗,因为我缓冲区里有回车在呀,那为什么还要我们输入?


  答案是:缓冲区里面确实是有回车,但是我们要的是"%d",回车不是scanf要的类型,它丢弃掉这个回车后就没有内容了,所以就停下来等我们继续输入。看下面的代码:

 这里是来解释为什么是丢弃的原因,对比看。上面是scanf后,getchar读得到,下面是最后一个getchar要等待,如果我们没有丢弃的话,第二次输入应该是:回车 + 6 + 回车(确认读取),读掉6后还剩两个回车,那我没下面两个getchar没有任何一个需要等待。



 总结一下:scanf输入确实是需要看格式限制的,格式不对,它就不读取,如果还是个回车,那它还会丢弃掉它,如果格式是对的,比如是字符格式,缓冲区里有回车,那它既把回车看成是要读取的内容还看成是结束的标志。



 我们反回去剖析一下,首先输入5回车,等待输入,其实(等待输入前还有一步就是丢弃上次遗留下来的回车),6回车,读取6,此时缓冲区里还有个回车在。

  最后一个10是自己蹦出来的


4.小谈一下:

  到这里你以为就完了吗,不不不,还有的,否则怎么能令博主奔溃呢,博主崩溃的原因是因为在边写的过程中,觉得scanf有好多种情况,边写边觉得有好多种都可以解释。。。ok,继续。


5.格式对scanf的重要性

 这就是同学在群里发的代码,因为输入的情况读者可能不清楚,我来说一下,在输入5后回车,跳到下一行我再输入一个6后回车,来到下一行有整数B:,然后我输入了7后回车,最后就出结果啦。


 大家有疑惑没?如果你把格式里的"%d\n"里的\n看成printf("\n"),那就是你输入5回车,然后换行,再输入6,再换行,也就是4行。我敲出来哈!



 就是他的想法是这样的,但scanf格式里的"%d\n"可不是打印函数里的"\n"噢,可不敢这么想!


 


  这里面也有学问在!那就是,你有没有看到结果是0.833333,很明显是5.0/6的结果,如果我们看向的是整数A:5和整数B:7这两个数字,5.0/7的结果可是0.714286噢。为什么,听我慢慢道来。


  我们最先输入了5和回车('\n'),scanf在缓冲区里只看到5,而回车是我们用来确认的,所以scanf没找到自己格式要的内容,所以要我们继续要输入,但我们回车了,窗口就到下一行了,接着我们在第二行输入6和回车,这下就不一样了,缓冲区里的内容是5'\n'6和一个确认的回车,scanf看到5'\n',那好scanf说:我就读走了,但是存到a里的是5'\n'吗,不是,就是5,%d,其它的只是格式。


  到第二个scanf了,这个时候缓冲区里有6'\n',当我们输入7回车,它就读走了6'\n',也就是把6放进了c。所以结果就是5.0/6啦。


 读完后,希望读者对scanf有更多一点的理解!


 好啦,这就是本节的内容,同以前一样,文章排版,内容分布,或有错误的,都可以在评论中告诉博主,博主也好改正。


 求点赞,求点赞,求点赞!

相关文章
|
6天前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
28 6
|
23天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
31 6
|
1月前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。
|
2月前
|
机器学习/深度学习 C语言
【c语言】一篇文章搞懂函数递归
本文详细介绍了函数递归的概念、思想及其限制条件,并通过求阶乘、打印整数每一位和求斐波那契数等实例,展示了递归的应用。递归的核心在于将大问题分解为小问题,但需注意递归可能导致效率低下和栈溢出的问题。文章最后总结了递归的优缺点,提醒读者在实际编程中合理使用递归。
67 7
|
2月前
|
存储 编译器 程序员
【c语言】函数
本文介绍了C语言中函数的基本概念,包括库函数和自定义函数的定义、使用及示例。库函数如`printf`和`scanf`,通过包含相应的头文件即可使用。自定义函数需指定返回类型、函数名、形式参数等。文中还探讨了函数的调用、形参与实参的区别、return语句的用法、函数嵌套调用、链式访问以及static关键字对变量和函数的影响,强调了static如何改变变量的生命周期和作用域,以及函数的可见性。
33 4
|
2月前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
30 0
|
2月前
|
C语言
【c语言】qsort函数及泛型冒泡排序的模拟实现
本文介绍了C语言中的`qsort`函数及其背后的回调函数概念。`qsort`函数用于对任意类型的数据进行排序,其核心在于通过函数指针调用用户自定义的比较函数。文章还详细讲解了如何实现一个泛型冒泡排序,包括比较函数、交换函数和排序函数的编写,并展示了完整的代码示例。最后,通过实际运行验证了排序的正确性,展示了泛型编程的优势。
23 0
|
C语言
c语言中scanf()、printf()函数
  函数调用scanf(“%d”,  &weight) 包含两个参数:“%d” 和&weight。C用逗号来隔开函数调用中的多个参数; 但是printf()和scanf()函数比较特殊,其函数数目可以不受控制。
869 0
|
2月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
36 3
|
2月前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
43 10