C语言中getchar()的原理以及易错点解析

目录
  • 一.getchar()系列
    • 1.getchar()工作原理及作用
    • 2.使用getchar()清理回车\n
    • 3.使用getchar()清理缓存
    • 4.混合scanf()与getchar()
  • 总结

一.getchar()系列

1.getchar()工作原理及作用

工作原理:getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了,第一次getchar()时,确实需要人工的输入,但是如果你输了多个字符,以后的getchar()再执行时就会直接从缓冲区中读取了。

实际上是 输入设备->内存缓冲区->getchar()

你按的键是放进缓冲区了,然后供程序getchar()

你有没有试过按住很多键然后等一会儿会滴滴滴滴响,就是缓冲区满了,你后头按的键没有存进缓冲区.

键盘输入的字符都存到缓冲区内,一旦键入回车,getchar就进入缓冲区读取字符,一次只返回第一个字符作为getchar函数的值,如果有循环或足够多的getchar语句,就会依次读出缓冲区内的所有字符直到’\n’.要理解这一点,之所以你输入的一系列字符被依次读出来,是因为循环的作用使得反复利用getchar在缓冲区里读取字符,而不是getchar可以读取多个字符,事实上getchar每次只能读取一个字符.如果需要取消’\n’的影响,可以用getchar();来清除,这里getchar();只是取得了’\n’但是并没有赋给任何字符变量,所以不会有影响,相当于清除了这个字符.

作用1:从缓冲区读走一个字符,相当于清除缓冲区。

作用2:前面的scanf()在读取输入时会在缓冲区中留下一个字符’\n’(输入完按回车键所致),所以如果不在此加一个getchar()把这个回车符取走的话,接下来的scanf()就不会等待从键盘键入字符,而是会直接取走这个“无用的”回车符,从而导致读取有误。

2.使用getchar()清理回车\n

这个问题转载自n_s_X14,但是作者在文章最后留了一个问题,现在在这里给大家解释一下原因。

文章的源码为:

#include <stdio.h>

int main(void){
    char m[40];
    char n;
    printf("please input first str:\n");    //提示用户输入第一个字符串
    scanf("%s",m);                         //获取用户第一个输入字符串
    printf("you input str is :%s\n",m);    //输出用户的输入的第一个字符串
    printf("input second char :\n");        //提示用户输入第二个字符
    scanf("%c",&n);                         //获取用户的第二个字符
    printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
    return 0;

}

Output:

please input first str:
abc
you input str is :abc
input second char :
now you input second char is :

Program ended with exit code: 0

问题:我们第一次输入abc后成功打印出来了you input str is :abc,但是执行到printf("input second char :\n");时,还没等到第二次输入就打印出来了。这是为什么??

原因:

其实在我们第一次输入并按下回车的时候,控制台一共获得了四个字符,分别是:a、b、c、回车(enter)。但是因为scanf()方法遇到非字符的时候会结束从控制台的获取,所以在输入’abc’后,按下 ‘回车(enter)’ 的同时,将’abc’这个值以字符串的形式赋值给了类型为 ‘char’ 的 ‘m’ 数组,将使用过后的字符串: ‘回车(enter)’ 保存在控制台输入的缓冲区,然后继续执行下一段输出代码,然后又要求用户输入。此时,因为上一次被使用过后的字符串被保存在缓冲区,现在scanf()方法从控制台的缓冲区获取上一次被使用过后的字符串,并只截取第一个字符: ‘回车(enter)’ ,此时控制台缓冲区才算使用完了。所以在看似被跳过的输入,其实已经scanf()方法已经获取了我们的输入了,这个输入就是一个 ‘回车(enter)’ 。

解决问题:

使用getchar()方法,清除掉abc后面的缓存(回车enter)。

#include <stdio.h>

int main(void){
    char m[40];
    char n;
    printf("please input first str:\n");    //提示用户输入第一个字符串
    scanf("%s",m);                         //获取用户第一个输入字符串
    printf("you input str is :%s\n",m);    //输出用户的输入的第一个字符串
    getchar();
    printf("input second char :\n");        //提示用户输入第二个字符
    scanf("%c",&n);                         //获取用户的第二个字符
    printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
    return 0;

}

Output:

please input first str:
abc
you input str is :abc
input second char :
de
now you input second char is :d
Program ended with exit code: 0

3.使用getchar()清理缓存

文章结束时留了一个问题:如果在第一次输入ab后加一个空格再回车,又会出现原来的问题,即程序只输出了ab后就自动跳过下一次的输入之间退出了,控制台输出如下图所示。

原因

在获取用户第一个输入字符串时,scanf("%s",&m);,我们用%s作为转换说明,%s的作用是“把输入解释成字符串。从第一个非空白字符开始,到下一个空白字符之前的所有字符都是输入。”所以scanf把输入的ab空格+回车就理解为ab+回车(ab后面没有空格),但是依然以ab空格+回车的形式存储在缓存区。我们输入ab空格+回车,在缓存区是这样存放的:

其中,第三格存放的为空格键。

当程序运行完 getchar();后,只清除了第三格中的空格键,因为一次执行getchar();只清除一个缓存,留下了第四格中的回车键,因此再次出现了同样的问题。

解决问题:那么就是说只要运行两次getchar();,清除掉第三格和第四格就可以正常了。

#include <stdio.h>

int main(void){
    char m[40];
    char n;
    printf("please input first str:\n");    //提示用户输入第一个字符串
    scanf("%s",m);                         //获取用户第一个输入字符串
    printf("you input str is :%s\n",m);    //输出用户的输入的第一个字符串

    getchar();                              //第一次清除缓存
    getchar(); 								//第二次清除缓存

    printf("input second char :\n");        //提示用户输入第二个字符
    scanf("%c",&n);                         //获取用户的第二个字符
    printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
    return 0;

}

Output:

由此可见,当我们第一次输入ab空格+回车后,程序正常运行。

进一步:如果我们输入的是a空格b+回车scanf("%s",m); 这一步只能读取到a,因为a后面有空格。但是a空格b+回车在缓冲区这样存放:

因此,如果想要程序正常运行则需要在输出用户的输入的第一个字符串后加入三次getchar();操作,即删除掉第二,第三,第四格的内容。

问题:如果我们输入a空格bbbbbbbb+回车,那可能需要无数个getchar();来清除缓存,这时应该怎么办??

解决方法:加入while循环while(getchar()!='\n') continue;

#include <stdio.h>

int main(void){
    char m[40];
    char n;
    printf("please input first str:\n");    //提示用户输入第一个字符串
    scanf("%s",m);                         //获取用户第一个输入字符串
    printf("you input str is :%s\n",m);    //输出用户的输入的第一个字符串

    while(getchar()!='\n')					//通过while循环删除缓存
        continue;

    printf("input second char :\n");        //提示用户输入第二个字符
    scanf("%c",&n);                         //获取用户的第二个字符
    printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
    return 0;

}

这时,我们输入a空格bbbbbbbb+回车,程序正常运行。

解析:

 while(getchar()!='\n')
        continue;

可以看出这段代码代替了无数个getchar(),他的作用是跳过剩余的输入行

第一次while循环消除第二格缓存,第二次while循环消除第三格缓存……直到第八次。最后一次同样,getchar()也消除了回车。

while(getchar()!='\n')可以拆分成两步,

第一步调用getchar()方法(这里getchar();只是取得了’\n’但是并没有赋给任何字符变量,所以不会有影响,相当于清除了这个字符)。

第二步判断获取到的缓存是否等于’\n’。

4.混合scanf()与getchar()

假设程序要求用getchar()处理字符输入,用scanf()处理数值输入,这两个函数都能很好的完成任务,但是不能混合使用因为getchar()读取每个字符,包括空格、制表符和换行符;而scanf()在读取数字时则会跳过空格、制表符和换行符。

例:

要求用户输入一个字母和两个数字,输出以第一个数字为行数,第二个数字为列数,以字母为内容的数列,要求可以不断输入直至键入回车退出程序:

#include <stdio.h>
void display(char cr,int lines,int width);
int main(int argc, const char * argv[]) {

    int ch;
    int rows,cols;
    printf("Enter a character and two integers:\n");
    while((ch=getchar())!= '\n'){
        scanf("%d %d", &rows,&cols);
        display(ch, rows, cols);
        printf("Enter another character and two integers;\n");
        printf("Enter a newline to quit.\n");
    }
    printf("Bye.\n");
    return 0;

    }
void display(char cr,int lines,int width){
    int row,col;

    for(row=1; row<= lines; row++){
        for(col =1; col<=width; col++){
            putchar(cr);
        }
        putchar('\n');
            }
}

output:

我们发现,在第一次输入成功打印后,程序自动退出。这明显不符合我们的题目要求。

原因是,输入的c23其实是c23+换行符,scanf()函数把这个换行符留在了缓存中。getchar()不会跳过换行符,所以在进入下一轮迭代时,还没来得及输入字符,它就读取了换行符,然后将其赋值给了ch。而ch是换行符正式终止循环的条件。

如何改进??

  1. 我们需要删除scanf()函数留在缓存中的换行符即可。
  2. 在if语句中使用一个break语句,可以在scanf()的返回值不等于2时终止程序,即如果一个或两个输入值不是整数或者遇到文件结尾就终止程序。
#include <stdio.h>
void display(char cr,int lines,int width);
int main(int argc, const char * argv[]) {

    int ch;
    int rows,cols;
    printf("Enter a character and two integers:\n");
    while((ch=getchar())!= '\n'){
        if( scanf("%d %d", &rows,&cols)!=2 ){
            break;
        }
        display(ch, rows, cols);

        while(getchar()!='\n'){
            continue;
        }
        printf("Enter another character and two integers;\n");
        printf("Enter a newline to quit.\n");
    }
    printf("Bye.\n");
    return 0;

    }
void display(char cr,int lines,int width){
    int row,col;

    for(row=1; row<= lines; row++){
        for(col =1; col<=width; col++){
            putchar(cr);
        }
        putchar('\n');
            }
}

Output:

题外话:

scanf()中转化符的问题

问题:从上面两张图片中可以看出,当scanf("%d",&c);改为scanf("%c",&c);时,控制台中出现了图二的问题。character为什么为空白??

原因:

如果格式是%c,那么任何字符都是它想要的,所以第二个程序中的第二个scanf("%c")会得到‘+’后面的空格’ '。如果格式是%d,则会忽略任何空白字符(空格、回车、制表符等),忽略的意思是,从缓冲区里删除,但并不保存;如果遇到数字,则拿出并保存给后面的整数,也就是说%d的时候,scanf想要的字符是数字和空白符。所以第一个程序里的第二个scanf("%d")忽略掉了空格,正确输入了数字。

总结

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

(0)

相关推荐

  • 基于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语言中的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语言中getchar()的返回类型为什么是int详解

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

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

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

  • C语言中getchar()的原理以及易错点解析

    目录 一.getchar()系列 1.getchar()工作原理及作用 2.使用getchar()清理回车\n 3.使用getchar()清理缓存 4.混合scanf()与getchar() 总结 一.getchar()系列 1.getchar()工作原理及作用 工作原理:getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了,第一次getchar()时,确实需要人工的输入,但是如果你输了多个字符,以后的

  • C语言中getchar的用法以及实例解析

    目录 getchar解析 一.getchar的返回类型及作用机制 二.根据一段代码初步了解 三.实例(“输入密码”)进一步了解 1.代码达不到理想效果 2.输入的密码中有空格 总结 getchar解析 一.getchar的返回类型及作用机制 getchar——读取字符的函数 int getchar(void) 返回类型为int,参数为void. 有人可能会有疑惑,getchar既然是读取字符的,为什么返回类型是int呢? 1.getchar其实返回的是字符的ASCII码值(整数). 2.getc

  • Go语言中的Base64编码原理介绍以及使用

    目录 前言 Go Base64编码 什么是Base64编码 为什么需要Base64编码 Base64编码原理 编码步骤 位数不足情况 Base64解码原理 Base64标准编码变种 总结 前言 在网络中传递参数时,我们经常会对参数进行Base64编码,那么Go 语言中如何进行Base64编码呢?Base64编码的原理是怎样的呢?通过这篇文章一起来了解下吧! Go Base64编码 标准Base64编码 // 标准Base64编码     src := "hello world"   

  • 易语言中DLL命令的开发与使用介绍

    一.关于易语言DLL 从易语言3.6版开始,已经能够支持对DLL动态链接库的开发, 编译出的DLL是标准的DLL,和其他编程语言生成的标准DLL的调用方法相同.易语言编写出的DLL,在非独立编译exe时只需要DLL文件随应用程序一起发行,而独立编译exe时无需将DLL文件随应用程序一起发行. 二.新建易语言DLL程序 新建一个易语言程序,然后选择 Windows动态链接库 图标,易语言就会自动创建 出编写DLL动态链接库的代码区(程序集),如下图所示: 创建完毕就可以在代码区里编写DLL程序.

  • 关于易语言中“如果”命令详解

    本命令根据提供的逻辑参数的值,来决定是否改变程序的执行位置,如果提供的逻辑参数值为真,程序继续顺序向下执行,否则跳转到左侧箭头线指向的命令处去执行. 语法: 无返回值 如果 (条件) 参数名 描 述 条件 必需的: 逻辑型.本条件值的结果决定下一步程序执行位置. 说明: 如果命令的条件参数必须为逻辑型,可以为一个或多个逻辑型条件语句组成,多个逻辑型条件语句之间可以用"或"或者"且"连接, 如果符合如果编辑框.内容 = "你好易语言"的条件,就执行

  • 易语言中“如果真”命令的实例分享

    本命令根据提供的逻辑参数的值,来决定是否改变程序的执行位置,如果提供的逻辑参数值为真,程序继续顺序向下执行,否则跳转到左侧箭头线指向的命令处去执行.同"如果"命令相比,本命令没有为假时的程序部分. 语法: 无返回值 如果真 (条件) 参数名 描 述 条件 必需的: 逻辑型.本条件值的结果决定下一步程序执行位置. 例程 说明: 如果真命令和如果命令相似,如果真的条件也必须是逻辑型,可以用"或者""并且"连接多个条件. 此段语句运行时,如果编辑框中的

  • 易语言中“取错误码”命令详解

    如果执行某数据库命令失败,在其后执行本命令可以取回非 0 的数据库错误码值.如果该数据库命令执行成功,执行本命令将返回 0 . 语法: 整数型 取错误码 () 例程: 说明: 首先把要操作的数据库打开,然后执行"写()"命令,程序将改写"改写字段编辑框"中输入的字段,改写内容为"改写内容编辑框"中的内容.如果改写成功,会弹出信息框显示"写入数据成功":如果改写失败,会弹出信息框提示失败,将本次操作的错误码和错误信息取出,并显示

随机推荐