令博主崩溃的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有更多一点的理解!


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


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

相关文章
|
7天前
|
C语言
【C语言基础考研向】05 scanf读取标准输入超详解
本文详细解析了C语言中`scanf`函数的工作原理及常见问题。首先介绍了`scanf`如何处理标准输入,并通过示例说明了为何有时会出现阻塞现象及其解决办法。接着探讨了当输入包含多种数据类型时,特别是字符型数据的处理方式,强调了格式控制的重要性,并给出了正确的输入格式示例。通过正确配置,可以避免因空格和换行符导致的问题,确保数据准确读取。
23 10
|
8天前
|
存储 C语言
【C语言基础考研向】10 字符数组初始化及传递和scanf 读取字符串
本文介绍了C语言中字符数组的初始化方法及其在函数间传递的注意事项。字符数组初始化有两种方式:逐个字符赋值或整体初始化字符串。实际工作中常用后者,如`char c[10]="hello"`。示例代码展示了如何初始化及传递字符数组,并解释了为何未正确添加结束符`\0`会导致乱码。此外,还讨论了`scanf`函数读取字符串时忽略空格和回车的特点。
|
8天前
|
存储 Serverless C语言
【C语言基础考研向】11 gets函数与puts函数及str系列字符串操作函数
本文介绍了C语言中的`gets`和`puts`函数,`gets`用于从标准输入读取字符串直至换行符,并自动添加字符串结束标志`\0`。`puts`则用于向标准输出打印字符串并自动换行。此外,文章还详细讲解了`str`系列字符串操作函数,包括统计字符串长度的`strlen`、复制字符串的`strcpy`、比较字符串的`strcmp`以及拼接字符串的`strcat`。通过示例代码展示了这些函数的具体应用及注意事项。
|
11天前
|
存储 C语言
C语言程序设计核心详解 第十章:位运算和c语言文件操作详解_文件操作函数
本文详细介绍了C语言中的位运算和文件操作。位运算包括按位与、或、异或、取反、左移和右移等六种运算符及其复合赋值运算符,每种运算符的功能和应用场景都有具体说明。文件操作部分则涵盖了文件的概念、分类、文件类型指针、文件的打开与关闭、读写操作及当前读写位置的调整等内容,提供了丰富的示例帮助理解。通过对本文的学习,读者可以全面掌握C语言中的位运算和文件处理技术。
|
11天前
|
存储 C语言
C语言程序设计核心详解 第七章 函数和预编译命令
本章介绍C语言中的函数定义与使用,以及预编译命令。主要内容包括函数的定义格式、调用方式和示例分析。C程序结构分为`main()`单框架或多子函数框架。函数不能嵌套定义但可互相调用。变量具有类型、作用范围和存储类别三种属性,其中作用范围分为局部和全局。预编译命令包括文件包含和宏定义,宏定义分为无参和带参两种形式。此外,还介绍了变量的存储类别及其特点。通过实例详细解析了函数调用过程及宏定义的应用。
|
11天前
|
C语言
C语言程序设计核心详解 第三章:顺序结构,printf(),scanf()详解
本章介绍顺序结构的基本框架及C语言的标准输入输出。程序从`main()`开始依次执行,框架包括输入、计算和输出三部分。重点讲解了`printf()`与`scanf()`函数:`printf()`用于格式化输出,支持多种占位符;`scanf()`用于格式化输入,需注意普通字符与占位符的区别。此外还介绍了`putchar()`和`getchar()`函数,分别用于输出和接收单个字符。
|
16天前
|
Linux C语言
C语言 多进程编程(三)信号处理方式和自定义处理函数
本文详细介绍了Linux系统中进程间通信的关键机制——信号。首先解释了信号作为一种异步通知机制的特点及其主要来源,接着列举了常见的信号类型及其定义。文章进一步探讨了信号的处理流程和Linux中处理信号的方式,包括忽略信号、捕捉信号以及执行默认操作。此外,通过具体示例演示了如何创建子进程并通过信号进行控制。最后,讲解了如何通过`signal`函数自定义信号处理函数,并提供了完整的示例代码,展示了父子进程之间通过信号进行通信的过程。
|
16天前
|
C语言
C语言 字符串操作函数
本文档详细介绍了多个常用的字符串操作函数,包括 `strlen`、`strcpy`、`strncpy`、`strcat`、`strncat`、`strcmp`、`strncpy`、`sprintf`、`itoa`、`strchr`、`strspn`、`strcspn`、`strstr` 和 `strtok`。每个函数均提供了语法说明、参数解释、返回值描述及示例代码。此外,还给出了部分函数的自实现版本,帮助读者深入理解其工作原理。通过这些函数,可以轻松地进行字符串长度计算、复制、连接、比较等操作。
|
4月前
|
存储 C语言
C 语言函数完全指南:创建、调用、参数传递、返回值解析
函数是一段代码块,只有在被调用时才会运行。 您可以将数据(称为参数)传递给函数。 函数用于执行某些操作,它们对于重用代码很重要:定义一次代码,并多次使用。
137 3
|
3月前
|
存储 C语言
C语言的函数返回值和指针
C|函数返回值(区分各类值)和指针(区分各类存储空间)的细节