scanf函数输入字符 %c之前要有空格分析

问题描述如下:

test.c

int main(void)

{

    int n = 0;

    char c;

    while (1)

    {

        scanf("%c",&c);

        printf("%c,%d\n",c,++i);

    }

    return 0;

}

       这段程序在vc下运行结果出人意料:

       程序输入:依次输入a,b,c(每次输入之后都按回车)

       可见,程序输出"不正常":输入了三次(a,b,c),却输出了6次(n的值)。每次输入按回车之后,初"正常输出"之外,还多了一个空白行和一行不正常的输出。

原因分析:由程序输出现象分析,可知,每次输入一次之后,实际程序进行了两次处理,即两次while循环,所以输出了两次,而且第二次的输出是一行空白行和一行不正常的数据,怀疑是由于每次输入之后按回车惹的祸,即程序将"回车"也当做一个字符进行处理了,对"回车"的按键,系统将其转换为换行符,换行符不是可见字符,所以程序打印出了一个空白行,之后又打印出n的值。

      为了验证猜想,将程序修给如下:

test.c

int main(void)

{

    int n = 0;

    char c;

    while (1)

    {

        scanf("%c",&c);

        printf("%c,%d %d\n",c,++i,c);//将获取的字符以十进制的形式打印出来

    }

    return 0;

}

    一样的输入:

       可见,每次多出来的字符其十进制是10,查ascii码表可知其是换行符,由此证明了以上猜想:程序将回车按键也捕获作为一个字符进行了处理。最终导致了不和谐的现象。

       解决方案:可以在scanf函数中%c之前输入一个空格符---scanf(" %c"),或者在每次scanf之前清空键盘缓冲区(也就清除了回车换行符)。

       将程序中的scnaf函数中的%c之前加上空格之后:

       输出结果正常了!可是一直不明白为什么要在%c之前加空格,之前看C语言教学视频,老师建议这样做,每次%c之前都要加上空格,说是一个科学家进行科学论证得出的结论。之后就一直对这个保持有一种神秘感。最近又遇到朋友问我这个问题,他问我说有一个程序输入总是不对,我问他是不是字符输入,他说是,我就立马知道是什么问题了。果然,加上空格之后就没问题了。但是我还是不能解释出问什么要这样做。最近在研究Linux内核,我想,会不是是系统平台的问题,我就在Linux系统上测试了此程序,结果和vc里的现象一样,也需要加空格。这说明和操作系统没有关系。后来,我怀疑是计算机硬件的问题,可能是其硬件某些方面的原因造成了这样的现象。可是觉得也不应该啊,在编译器这个层面完全可以解决这个问题啊,只要在编译的时候,编译器在%c之前加一个空格不就得了。我又猜想是编译器的问题。前几天刚在Bochs虚拟机中运行期带gcc编译环境的Linux0.11内核,于是我又在这环境下测试了一下,结果还是一样的现象。

       经过查相关的资料,明白了,这涉及到scanf输入字符串的匹配问题,如果格式字符串中有一个空格,则输入时会跳过相应位置开始出现的所有空格字符(包括空格、换行符,制表符等等)所以在%c之前加一个空格,表示对输入的字符,跳过开始处出现的所有空格(包括空格、换行符、制表符等),如果不加,则由于回车、换行也是一个字符,所以也会对其进行处理。这就导致了一开始的程序,当输入a后按回车,相当于输入了两个字符a和换行符,又由于%c之前无空格所以没有跳过空格。

       其实,这就是scanf函数中的一条处理规则而已,要想彻底理解,那就去看相关的scanf实现代码吧。我在Linux0.11内核代码中没有找到相关的函数,但是在网上找到了Minx系统内核中的scanf.c文件。对其进行分析,可了解一切!

       Minx内核中scanf的实现代码见我的下一篇博客分享。

  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值