C语言中的getchar()使用详解

目录
  • 前言
  • getchar困惑的点
  • 缓冲区
  • 缓冲区带来的问题
  • getchar工作原理
  • 解决缓冲区带来的问题之清空缓存区
  • 解决最初的困惑
  • 总结

前言

近期我在重新学习C语言时候,我发现了一个严重的问题,getchar我居然不会用了....也不是说不会用,我发现了一个非常让我困惑想不明白的问题。可能我在第一次接触C语言时候,就没有把这个概念弄清楚吧,以至于现在会不明白。

getchar困惑的点

我利用getchar函数输入了一串字符ABCD,然后把这串字符给到ch,然后紧接着我打印这个ch,然后我得到了一个字符A,看到这里大家没有感觉有什么问题对吧,当然没有问题,因为getchar只会读一个字符,自然就只读到了A,然后打印时候也自然而然就只打印了这个A出来。

好的我们接着往下看

看到这个我不知道大家有没有想到一个问题,反正我当时就是因为这个问题所困惑很久的。

首先通过第一个例子,我们知道了,getchar是只会读取一个字符

可是这个例子呢,我输入了一串字符ABCDE,按理说他也只是读取到一个字符,那就是这串字符中的第一个字符A,然后读取到了之后把它给了变量ch, 然后来判断这个ch等不等于EOF。

EOF是文件结束标志,在键盘上也就是ctrl+z 大家可以自己打印一下然后对照ASCII码看一下

很显然,当前这个里面根本就没有ctrl+z,所以条件为真,然后执行打印语句。

根据上面我们那段分析,然后应该打印一个字符A对吗,疑惑的事情发生了,它打印了ABCDE!!!是的,完完整整打印出来了。

可能大家经常见到这个类似程序,然后习以为常了,都觉得是应该完完整整打印出来

好的,讲到这里大家是不是就觉得很困惑了,为什么会这样呢?

那我现在就好好给大家讲一下了,原来这里面还涉及到了一个概念

缓冲区

缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。

那么这个和我们的getchar又有什么联系呢?

当然有联系,当我们调用了getchar函数时候,这个函数内部其实是这样做的:

他此时会先从缓存区中读一遍,此时读完之后发现,缓存区中没有数据,他就会等待外部输入,光标此时就会一闪一闪的~

当我们外部输入了字符之后,然后我们就会敲回车结束,这时候我们输入的字符其实就直接全部存在了缓存区中。

假设我此时输入了字符ABCD,然后回车结束,然后此时缓存区中就有了ABCD\n

注意,有意思的事情来了,还有\n ???哈哈哈哈接着往下看

缓冲区带来的问题

大家仔细看一下有没有发现,为什么我getchar没有输入字符呢 ?

其实不是我没有输入字符,只是在我输入完scanf的字符之后,回车结束这个scanf的输入,然后奇怪的事情发生了,程序就直接结束了,是的,跳过了getchar输入字符这个过程。

大家有没有觉得奇怪?

这就是我刚才上面给大家提到的 \n

是这样的,当我此时调用了scanf函数之后,我外部输入了 ABCD,然后输入完ABCD之后呢我要结束输入,然后我们就会去敲回车,注意!!这个回车其实也是一个字符,然后他也会连同我前面输入的ABCD一起放到缓存区,也就是说此时缓存区中就有了ABCD\n

我们做一个小小的测试就知道了

看到这个打印的结果,大家明白了吧

getchar工作原理

原来调用getchar函数的时候,它其实是直接从缓存区中读,如果缓存区中有数据,他就会直接拿走第一个,然后他的使命也就结束了。其实这里呢就是上面scanf在缓存区中拿走了ABCD,然后还剩下一个 10,这个10其实是\n ,是它在ASCII码中的表示。于是这个剩下的\n就在缓存区中存下去了,然后他此时遇到了getchar函数,然后getchar在缓存区中读,发现:诶,还剩一个\n,那么我就直接拿走,然后他的使命也就便结束了,所以就出现了不会等待我们外部输入的那种情况了。

那么我们可以解决这个问题吗?

解决缓冲区带来的问题之清空缓存区

明白了缓冲区和getchar的联系之后,其实我们想解决就很好办了

我们只需要在getchar读取之前在插入一个getchar函数,也就是说让他在下一次真正getchar读取之前,我们先再用一个getchar函数读一下那个缓存区剩下的\n,这样下一次我们真正的getchar读取时候,缓存区就空了。

好了getchar的工作原理我们彻底明白了,那么我们在回到最初的那个疑惑上面。

解决最初的困惑

第一次循环:首先缓存区为空,光标闪烁,然后等待我的输入

我输入了一个字符A,然后我继续输入了回车结束,那么我此时其实输入了两个字符,一个字符A,一个字符 \n,此时他们都被存放在了缓存区。然后缓存区有了数据之后,光标此时不在闪烁,getchar函数便开始直接读取,然后在这一次循环中,getchar函数读取到了一个字符A,然后将它给到ch,然后条件表达式为真(不等于ctrl+z),所以执行打印ch,然后打印出了一个字符A。

第二次循环:这时候缓存区还残留了一个\n,光标不闪烁,getchar也不会等待外部输入

那么此时getchar直接读取到这个缓存区中的\n,继续给到ch,然后表达式还是为真,所以继续打印这个ch,此时因为ch已经是被换掉了\n,所以打印换行,光标位置发生改变。

第三次循环:缓存区为空,getchar读取不到数据,光标闪烁,getchar等待外部输入数据。

至此我们在接着往下看

第一次循环:缓存区为空,getchar读取不到缓存区的数据,于是光标闪烁,getchar等待外部输入数据。

此时我输入了一串ABC,然后回车结束输入。此时缓存区中便有了字符ABCD\n,然后getchar读取第一个字符A,然后将它给到ch,然后条件表达式为真,打印了ch,于是第一个A就出来了。

第二次循环:缓存区还剩余BC\n,getchar直接读取

此时getchar读取到字符B,然后给到ch,条件表达式为真,继续打印ch,此时便得到了AB。

第三次循环:缓存区还剩余C\n,getchar直接读取

然后还是一样getchar读取到C,然后给到ch,之后表达式为真,打印出来了ch,然后经过这一次循环就得到了ABC

第四次循环:缓存区还剩余一个\n,最后打印这个\n,于是光标下一行。

最终结果就得到了ABC

然后我再次输入 ctrl+Z

于是缓存区存在了ctrl+z(EOF),然后getchar去读取,然后给到ch,然后表达式判断,条件为假,ch==EOF,所以循环跳出,程序结束。

总结

getchar函数是直接从缓存区中读取数据,如果缓存区中有数据,则直接读取第一个数据,如果没有数据,那么就光标闪烁,等待外部输入数据。

要非常注意的是,我们其他地方输入的回车也会被存在缓存区当成一个字符,然后后面getchar也会将其直接读出,在这个地方很容易出错!!

到此这篇关于C语言中的getchar()使用详解的文章就介绍到这了,更多相关C语言getchar()内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言中getchar()的返回类型为什么是int详解

    前言 在C语言中有个重要的库函数getchar(),可从终端获得一个字符的ASCII码值.在终端输入字符时并非输入一个字符就会返回,而是在遇到回车换行前,所有输入的在C语言中有个重要的库函数getchar(),可从终端获得一个字符的ASCII码值.在终端输入字符时并非输入一个字符就会返回,而是在遇到回车换行前,所有输入的字符都会缓冲在键盘缓冲器中,直到回车换行一次性将所有字符按序依次赋给相应的变量,在这里一定要注意最后一个字符即'\n',该字符也会赋给一个相应的变量(当然这要你定义的用来接收字符

  • C语言中的getchar和putchar的使用方法

    C语言中的getchar和putchar的使用方法 getchar是以行为单位进行存取的. 当用getchar进行输入时,如果输入的第一个字符为有效字符(即输入是文件结束符EOF,Windows下为组合键Ctrl+Z, Unix/Linux下为组合键Ctrl+D),那么只有当最后一个输入字符为换行符'\n'(也可以是文件结束符EOF,EOF将在后面讨论)时, getchar才会停止执行,整个程序将会往下执行.譬如下面程序段: while((c = getchar()) != EOF){ putc

  • c语言中getch,getche,getchar的区别

    getchar 是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说 ,如果stdin有数据的话不用输入就可以直接读取了.而getch()和getche()是conio.h中的库函数,它的作用是从键盘接收字符. getch() 实际是一个输入命令,作用是从键盘接收一个字符,而且并不把这个字符显示出来,就是说,你按了一个键后它并不在屏幕上显示你按的什么,而继续运行后面的代码,所以我们在C++中可以用它来实现"按任意键继续"的效果,即程序中遇到getch();这行语

  • 基于C语言EOF与getchar()的使用详解

    大师级经典的著作,要字斟句酌的去读,去理解.以前在看K&R的The C Programming Language(SecondEdition)第1.5节的字符输入/输出,被getchar()和EOF所迷惑了.可能主要还是由于没有搞清楚getchar()的工作原理和EOF的用法.因此,感觉很有必要总结一下,不然,很多琐碎的知识点长时间过后就会淡忘的,只有写下来才是最好的方法. 其实,getchar()最典型的程序也就几行代码而已.本人所用的环境是DebianGNU/Linux,在其他系统下也一样.

  • C语言中的getchar()使用详解

    目录 前言 getchar困惑的点 缓冲区 缓冲区带来的问题 getchar工作原理 解决缓冲区带来的问题之清空缓存区 解决最初的困惑 总结 前言 近期我在重新学习C语言时候,我发现了一个严重的问题,getchar我居然不会用了....也不是说不会用,我发现了一个非常让我困惑想不明白的问题.可能我在第一次接触C语言时候,就没有把这个概念弄清楚吧,以至于现在会不明白. getchar困惑的点 我利用getchar函数输入了一串字符ABCD,然后把这串字符给到ch,然后紧接着我打印这个ch,然后我得

  • C 语言中strstr函数实例详解

    C 语言中strstr函数实例详解 strstr函数 strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串.如果是,则该函数返回str2在str1中首次出现的地址:否则,返回NULL const char* strstr(const char* str1,const char* str2); char* strstr(char* str1,const char* str2); 库中实现的strstr #include <stdio.h> #include <

  • Go语言中sync.Cond使用详解

    目录 sync.Cond 可以用来干什么? 与 Sync.Mutex 的区别 sync.Cond 使用场景 sync.Cond sync.Cond 有哪些方法 NewCond 创建实例 Broadcast 广播唤醒所有 Signal 唤醒一个协程 Wait 等待 代码示例 sync.Cond 可以用来干什么? Golang 的 sync 包中的 Cond 实现了一种条件变量,可以使用多个 Reader 等待公共资源. 每个 Cond 都会关联一个 Lock ,当修改条件或者调用 Wait 方法,

  • go语言中GoMock安装使用详解

    目录 安装 开始 使用参数匹配器 经验之谈 安装 GoMock是一个Go框架.它与内置的测试包整合得很好,并在单元测试时提供了灵活性.正如我们所知,对具有外部资源(数据库.网络和文件)或依赖关系的代码进行单元测试总是很麻烦. 为了使用GoMock,我们需要安装gomock包github.com/golang/mock/gomock和mockgen代码生成工具github.com/golang/mock/mockgen.使用这个命令行: go get github.com/golang/mock/

  • go语言中decimal的用法详解

    目录 1. 精度丢失的case 2. decimal的应用场景 3. 使用decimal 4. decimal其他实用的场景 4.1 获取结果的整数部分 4.2 小数点后填充 4.3 比较数字的大小 5 小结 decimal是为了解决Golang中浮点数计算时精度丢失问题而生的一个库,使用decimal库我们可以避免在go中使用浮点数出现精度丢失的问题. github地址:https://github.com/shopspring/decimal 1. 精度丢失的case func TestFl

  • C语言中continue的用法详解

    目录 前言 continue 在while中的用法 continue 在for中的用法 continue 在剔除多余元素的用法 附:continue与break的区别 总结 前言 continue语句的作用是跳过本次循环体中余下尚未执行的语句,立即进行下一次的循环条件判定,可以理解为仅结束本次循环. 注意:continue语句并没有使整个循环终止. continue 在while中的用法 //continue 在while中的用法 #include<stdio.h> int main() {

  • 关于C语言中E-R图的详解

    E-R  英文缩写为(Entity Relationship Diagram)也称实体-联系图. 提供了表示实体类型.属性和联系的方法,用来描述现实世界的概念模型. 下面就讲详解e-r图,如下: 从上面的的图可以看到一个完整的e-r图有四个部分: 1.矩形框,矩形表示实体型,矩形框内写明实体名: 2.椭圆框,椭圆表示实体的属性,并用无向边将其与相应的实体型连接起来: 3.菱形框,菱形表示实体型之间的联系,在菱形框内写明联系名, 4.联系线,实体与属性之间:实体与联系之间:联系与属性之间用直线相连

  • R语言中devtools的使用详解

    今天安装r语言devtools包,尝试很多种方法也不能决解,下面这个问题是改变镜像,然后就会可以安装了(3.4.2版本) Warning in install.packages : InternetOpenUrl failed: '无法解析服务器的名称或地址' Warning in install.packages : InternetOpenUrl failed: '不能连接到吊销服务器,或者未能获得最终响应.' Warning in install.packages : InternetOp

  • C语言中的malloc使用详解

    一.原型:extern void *malloc(unsigned int num_bytes); 头文件:#include <malloc.h> 或 #include <alloc.h> (注意:alloc.h 与 malloc.h 的内容是完全一致的.) 功能:分配长度为num_bytes字节的内存块 说明:如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL. 当内存不再使用时,应使用free()函数将内存块释放. 举例: #include<stdio.h&g

随机推荐