scanf函数输入字符 %c之前要有空格分析
2014-07-17 16:10
218 查看
问题描述如下:
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(每次输入之后都按回车)
![](https://img-blog.csdn.net/20140717163744491?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWloYW9sb3ZlbQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
可见,程序输出"不正常":输入了三次(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;
}
一样的输入:
![](https://img-blog.csdn.net/20140717163603234?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWloYW9sb3ZlbQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
可见,每次多出来的字符其十进制是10,查ascii码表可知其是换行符,由此证明了以上猜想:程序将回车按键也捕获作为一个字符进行了处理。最终导致了不和谐的现象。
解决方案:可以在scanf函数中%c之前输入一个空格符---scanf(" %c"),或者在每次scanf之前清空键盘缓冲区(也就清除了回车换行符)。
将程序中的scnaf函数中的%c之前加上空格之后:
![](https://img-blog.csdn.net/20140717163910696?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWloYW9sb3ZlbQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
输出结果正常了!可是一直不明白为什么要在%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的实现代码见我的下一篇博客分享。
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的实现代码见我的下一篇博客分享。
相关文章推荐
- Smarty - Manual手册 - Chapter 7. Built-in Functions内建函数 - {strip}在显示之前删除每行前后多余的空格和回车字符
- 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
- 在lineEdit中只能输入字符,数字和空格的写法
- 输入一段字符,统计其中有多少单词,单词间用空格分开。
- 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
- 输入一行字符 统计其有多少个单词 (空格分割字符)
- [K&R学习]输入一行字符,并将其中的多个空格用一个空格代替
- 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数
- [Java]练习题007: 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数
- 关于动态存储分配函数的调用,在已经过排序的数组中查找及删除内容的操作,余数的分析,删除字符数组中的空格,对链表的逆置,在源字符串中查找子字符串的个数,函数指针以及函数的调用,循环赋值带来的问题以及插入
- 关于在textarea中输入回车换行和空格字符的正常显示
- 关于在textarea中输入回车换行和空格字符的正常显示
- 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数
- 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数
- 输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数
- 批处理输入密码但不显示字符的代码---分析
- 输入一行字符,统计其中的单词的个数.各单词之间用空格分隔
- 输入一行字符,分别统计出其中的英文字母、空格、数字、和其他字符的个数
- 输入一行字符,分别统计出其中英文字母 空格 数字和其他字符的个数
- C语言:输入一行字符,统计其中有多少单词,单词之间用空格分隔开