C语言的疑难杂症 坑爹的scanf,无私的getchar

控制语句

判断if/ if..else/ if…else if…
循环for/while/do..while

题目1:从终端输入两个数,比较绝对值的大小。

#include <stdlib.h>
#include <stdio.h>
  void main(){
  int i,j,m,n,k;
  scanf("%d\n%d",&i ,&j);
  getchar();
   m = abs( i );  
   n = abs( j );
   k = m>n?m:n;
  printf("%d",k);
  getchar();
}

函数名: abs
功 能: 求整数的绝对值
头文件:stdlib.h
函数原型:int abs(int i); 

题目2:判断输入的字符是数字,大写字母,小写字母或其他字符,多分枝语句(if..else的运用)

#include <stdlib.h>
#include <stdio.h>
  void main(){
  char i ;
  int j;
  printf("请任意输入一个字符\n");
  scanf("%c",&i);
  getchar();
  j = i;
  if(j>=48 && j<=57) printf("\n数字");
  else if(j>=65 && j<=90) printf("\n大写字母");
  else if(j>=97 && j<=122) printf("\n小写字母");
  else printf("\n其它字符");
  getchar();
  getchar();
}
//最后如果只有一个getchar(),输入其它字符时会闪退,有两个就不会,有点意思,值得研究。  

简化版

#include <stdlib.h>
#include <stdio.h>
  void main(){
  char j ;
  printf("请任意输入一个字符\n");
  j = getchar();  //相当于scanf("%c",&j);
  if(j>=48 && j<=57) printf("\n数字");
  else if(j>=‘A’ && j<=‘Z’) printf("\n大写字母");
  else if(j>='a' && j<='z') printf("\n小写字母");
  else printf("\n其它字符");
  getchar();
  getchar();
}

不要偷懒,if后面的大括号不要省,即使只有一行代码。

编写铁路购票系统模型时遇到一个非常头疼的问题:当密码输入错误以后,提示重新输入,但再次输入正确的结果是依然提示出错。以下代码是问题已解决的代码。
/*
*用户登录
*/
printf("\n输入账户:\t");
scanf("%c",&z);
getchar();
printf("\n输入密码:\t");
scanf("%c",&m);
getchar();

/*
*判断输入
*/
if(z == a && m == b){
    printf("");
}else{
    do{     printf("\n账户或密码错误,请重新输入!!\n");
        printf("\n输入账户:\t");
        scanf("%c",&z);
        getchar();
        printf("\n输入密码:\t");
        scanf("%c",&m);
        getchar(); //症结所在,没有它就会出现那个蛋疼的问题
    }while(!(z == a && m == b));
}
printf("\t\t\t\t恭喜您登录成功!!\n");

网上对于该问题的解析:
“`
这是在tc2.0下做的一道题,按正常情况应该是输入2个字符,然后在输出两个字符,可是在我实验的时候,系统只要求输入一个字符,然后就自动结束,我用F7单步执行并跟踪i,j两个变量的时候,发现i变量的值是我输入的值,然后j变量是’\n’,我就是一个回车符,但实际是我不想第二个变量也只是一个回车符呀,请问该怎么办?以前好像听人说是scanf函数有个字符缓存,j变量就是从字符缓里的读取的。

include “stdio.h”

main()
{ char i,j;
scanf(“%c”,&i);
scanf(“%c”,&j);
printf(“%c %c”,i,j);
}

下面根据我的理解,详细展示一下为什么输错一次账户密码后,再次输入对的账户密码依然提示错误:

假定正确密码是1,2,输入值为i,j。

输入正确的操作如下:
输入1,回车,输入2 ,回车,正确。

不可思议的状况如下:
输入1,回车,输入3 ,回车,错误。
再输入1,回车,输入2,回车,错误。
再来,输入1,回车,输入2,回车,错误。(这特么是见鬼了??)

答案揭晓:

因为账户,密码是两个连续输入的值,我们会分开用到两个scanf。问题就出在这里,它是有缓存字符的功能的。什么意思,就是说当你输完第一个数后,无论按键盘上的哪个键,这个字符都会保存到下一个数据的内存下。而通常我们在输完第一个数后都会按回车。那么可能有朋友会问,为什么会在输错一次之后才出现这个问题呢。上面代码部分已经指出了症结所在:getchar,没错就是它。【getchar有一个int型的返回值.当程序调用getchar时.程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中.直到用户按回车为止(回车字符也放在缓冲区中)–此段来源于百度百科】。到这里似乎已经很明白了,两个scanf()碰到一起,如果中间没有getchar(),那么第一个scanf()会缓存一个字符存入第二个待输入数的内存下,而这个字符就是你在输入第一个数与第二个数中间的操作,可能是回车,可能是空格。总之,你不会将两个数不留缝隙的一起输入(那不就成一个数了),所以一定会多出一点什么。
因为当我们第一次输错时,程序会循环让我们输入,也就是说输入的顺序是:账户,密码,账户….所以如果没有上面代码中第二个getchar的话,当你第二次输入时,你的账户在内存里其实已经是一个\n(你要是按空格那就是\0),这是因为你之前按了回车,却没有getchar接住它。,而此时你所认为输入的第一个数只能蹲到第二个数的内存里面了,不错才有鬼了。

去掉那个getchar,问题就重现,爽到抽筋。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值