C语言中getchar()函数的理解
2011-11-02 11:39
696 查看
许多初学者都习惯用 char 型变量接收 getchar、getc,fgetc 等函数的返回值,其实这么做是不对的,并且隐含着足以致命的错误。getchar 等函数的返回值类型都是int 型
下面是getchar()的定义:
当这些函数读取出错或者读完文件后,会返回 EOF.EOF 是一个宏,标准规定它的值必须是一个 int 型的负数常量。
通常编译器都会把 EOF 定义为 -1.问题就出在这里,使用 char 型变量接收 getchar 等函数的返回值会导致对 EOF 的辨认出错,或者错把好的数据误认为是 EOF,或者把 EOF 误认为是好的数据。
Int c;
while ( (c = fgetc(fp)) != EOF )
{
Putchar=C;
}
如上例所示,我们很多时候都需要先用一个变量接收 fgetc 等函数的返回值,然后再用这个变量和 EOF 比较,判断是否已经读完文件。
上面这个例子是正确的,把 c 定义为 int 型保证了它能正确接收 fgetc 返回的 EOF,从而保证了这个比较的正确性。但是,如果把 c 定义为 char 型,则会导致意想不到的后果。
首先,因为 fgetc 等函数的返回值是 int 型的,当赋值给 char 型变量时,会发生降级,从而导致数据截断。
例如:
---------------------------------
| 十进制 | int | char |
|--------|--------------|-------|
| 10 | 00 00 00 0A | 0A |
| -1 | FF FF FF FF | FF |
| -2 | FF FF FF FE | FE |
---------------------------------
在此,我们假设 int 和 char 分别是 32 位和 8 位的。
由上表可得,从 int 型到 char 型,损失了 3 个字节的数据。当我们要拿 char 型和 int 型比较的时候,char 型会自动升级为 int 型。
char 型升级为 int 型后的值会因为它到底是 signed char 还是 unsigned char 而有所不同。
不幸的是,如果我们没有使用 signed 或者 unsigned 来修饰 char,那么我们无从知晓 char 到底是指 unsigned char 还是指 signed char,因为这是由编译器决定的。
不过,无论 char 是 signed 的也好,unsigned 的也罢,都不能改变使用 char 型变量接收 fgetc 等函数的返回值是错误的这个事实。
唯一能改变的是该错误导致的后果。前面我们说了,char 型和 int 型比较时,char 会自动升级为 int.
下面我们来看看 signed char 和 unsigned char 在转换成 int 后,它们的值有什么不同:
---------------------------------------
| char | unsigned | signed |
|-------|---------------|-------------|
| 10 | 00 00 00 0A | 00 00 00 0A |
| FF | 00 00 00 FF | FF FF FF FF |
| FE | 00 00 00 FE | FF FF FF FE |
---------------------------------------
由上表可知,当 char 是 unsigned 的时候,其转换为 int 后的值是正数。也就是说,假如我们把 c 定义为 char 型变量,而编译器默认 char 为 unsigned char,那么以下表达式将永远成立。
(c = fgetc(fp))!= EOF /* c 的值永远为正数,而标准规定 EOF 为负数 */
也就是说以下循环是一个死循环。
while ( (c = fgetc(fp)) != EOF )
{
putchar(c);
}
读到这里,可能有些读者朋友会说:“那么我明确把 c 定义为 signed char 型的就没问题了吧!”很遗憾,就算把 c 定义为 signed char,仍然是错误的。假设 fgetc 等函数读到一个字节的值为 FF,那么返回值就是 00 00 00 FF.把这个值赋值给 c 后, c 的值变成 FF.然后 c 的值为了和 EOF 比较,会自动升级为 int 型的值,也就是 FF FF FF FF.从而导致以下表达式不成立。
(c = fgetc(fp)) != EOF /* 读到值为 FF 的字符,误认为 EOF */
也就是说以下循环在没有读完文件的情况下提前退出。
while ( (c = fgetc(fp)) != EOF )
{
putchar(c);
}
综上所述,使用 char 型变量接收 fgetc 等函数的返回值是错误的,我们必须使用 int 型变量接收这些函数的返回值,然后判断接收到的值是否 EOF.只有判断发现该返回值并非 EOF,我们才可以把该值赋值给 char 型变量。
同理,C++ 中,用 char 型变量接收 cin.get() 的返回值也是错误的。不过,把 char 型变量当作参数传递给 cin.get 则是正确的。
例如:
char c = cin.get(); // 错误,理由同上
char c;
cin.get(c); // 正确
第一个getchar()时输入一个字符,按下回车,那么等于你输入了两个字符,一个是你输入的字符被c1读走,还有一个是回车的转义字符。它还在缓冲区中,那么你的第二个getchar()就读走这个回车的转义字符。所以会自己跳过去。你可以在第二个getchar()之前在放一个getchar(),让这个getchar()把缓冲区里的回车字符读掉。然后你就可以输入了。当然你也可以调用相关函数把输入缓冲区flush掉。
getchar有一个int型的返回值.当程序调用getchar时.
程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中.直到用户按回车为止(回车字符也放在缓冲区中).
当用户键入回车之后,getchar才开始从stdio流中每次读入一个字符.
getchar函数的返回值是用户输入的第一个字符的ASCII码,如出错返回-1,且将用户输入的字符回显到屏幕.
如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取.
也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键.
getch与getchar基本功能相同,差别是getch直接从键盘获取键值,不等待用户按回车,只要用户按一个键,getch就立刻返回, getch返回值是用户输入的ASCII码,出错返回-1.输入的字符不会回显在屏幕上.getch函数常用于程序调试中,在调试时,在关键位置显示有关的结果以待查看,然后用getch函数暂停程序运行,当按任意键后程序继续运行.
可以利用getchar()函数让程序调试运行结束后等待编程者按下键盘才返回编辑界面,用法:在主函数结尾,return 0;之前加上getchar();即可
下面是getchar()的定义:
int getchar () { int result; _IO_acquire_lock (_IO_stdin); result = _IO_getc_unlocked (_IO_stdin); _IO_release_lock (_IO_stdin); return result; }
当这些函数读取出错或者读完文件后,会返回 EOF.EOF 是一个宏,标准规定它的值必须是一个 int 型的负数常量。
通常编译器都会把 EOF 定义为 -1.问题就出在这里,使用 char 型变量接收 getchar 等函数的返回值会导致对 EOF 的辨认出错,或者错把好的数据误认为是 EOF,或者把 EOF 误认为是好的数据。
Int c;
while ( (c = fgetc(fp)) != EOF )
{
Putchar=C;
}
如上例所示,我们很多时候都需要先用一个变量接收 fgetc 等函数的返回值,然后再用这个变量和 EOF 比较,判断是否已经读完文件。
上面这个例子是正确的,把 c 定义为 int 型保证了它能正确接收 fgetc 返回的 EOF,从而保证了这个比较的正确性。但是,如果把 c 定义为 char 型,则会导致意想不到的后果。
首先,因为 fgetc 等函数的返回值是 int 型的,当赋值给 char 型变量时,会发生降级,从而导致数据截断。
例如:
---------------------------------
| 十进制 | int | char |
|--------|--------------|-------|
| 10 | 00 00 00 0A | 0A |
| -1 | FF FF FF FF | FF |
| -2 | FF FF FF FE | FE |
---------------------------------
在此,我们假设 int 和 char 分别是 32 位和 8 位的。
由上表可得,从 int 型到 char 型,损失了 3 个字节的数据。当我们要拿 char 型和 int 型比较的时候,char 型会自动升级为 int 型。
char 型升级为 int 型后的值会因为它到底是 signed char 还是 unsigned char 而有所不同。
不幸的是,如果我们没有使用 signed 或者 unsigned 来修饰 char,那么我们无从知晓 char 到底是指 unsigned char 还是指 signed char,因为这是由编译器决定的。
不过,无论 char 是 signed 的也好,unsigned 的也罢,都不能改变使用 char 型变量接收 fgetc 等函数的返回值是错误的这个事实。
唯一能改变的是该错误导致的后果。前面我们说了,char 型和 int 型比较时,char 会自动升级为 int.
下面我们来看看 signed char 和 unsigned char 在转换成 int 后,它们的值有什么不同:
---------------------------------------
| char | unsigned | signed |
|-------|---------------|-------------|
| 10 | 00 00 00 0A | 00 00 00 0A |
| FF | 00 00 00 FF | FF FF FF FF |
| FE | 00 00 00 FE | FF FF FF FE |
---------------------------------------
由上表可知,当 char 是 unsigned 的时候,其转换为 int 后的值是正数。也就是说,假如我们把 c 定义为 char 型变量,而编译器默认 char 为 unsigned char,那么以下表达式将永远成立。
(c = fgetc(fp))!= EOF /* c 的值永远为正数,而标准规定 EOF 为负数 */
也就是说以下循环是一个死循环。
while ( (c = fgetc(fp)) != EOF )
{
putchar(c);
}
读到这里,可能有些读者朋友会说:“那么我明确把 c 定义为 signed char 型的就没问题了吧!”很遗憾,就算把 c 定义为 signed char,仍然是错误的。假设 fgetc 等函数读到一个字节的值为 FF,那么返回值就是 00 00 00 FF.把这个值赋值给 c 后, c 的值变成 FF.然后 c 的值为了和 EOF 比较,会自动升级为 int 型的值,也就是 FF FF FF FF.从而导致以下表达式不成立。
(c = fgetc(fp)) != EOF /* 读到值为 FF 的字符,误认为 EOF */
也就是说以下循环在没有读完文件的情况下提前退出。
while ( (c = fgetc(fp)) != EOF )
{
putchar(c);
}
综上所述,使用 char 型变量接收 fgetc 等函数的返回值是错误的,我们必须使用 int 型变量接收这些函数的返回值,然后判断接收到的值是否 EOF.只有判断发现该返回值并非 EOF,我们才可以把该值赋值给 char 型变量。
同理,C++ 中,用 char 型变量接收 cin.get() 的返回值也是错误的。不过,把 char 型变量当作参数传递给 cin.get 则是正确的。
例如:
char c = cin.get(); // 错误,理由同上
char c;
cin.get(c); // 正确
第一个getchar()时输入一个字符,按下回车,那么等于你输入了两个字符,一个是你输入的字符被c1读走,还有一个是回车的转义字符。它还在缓冲区中,那么你的第二个getchar()就读走这个回车的转义字符。所以会自己跳过去。你可以在第二个getchar()之前在放一个getchar(),让这个getchar()把缓冲区里的回车字符读掉。然后你就可以输入了。当然你也可以调用相关函数把输入缓冲区flush掉。
getchar有一个int型的返回值.当程序调用getchar时.
程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中.直到用户按回车为止(回车字符也放在缓冲区中).
当用户键入回车之后,getchar才开始从stdio流中每次读入一个字符.
getchar函数的返回值是用户输入的第一个字符的ASCII码,如出错返回-1,且将用户输入的字符回显到屏幕.
如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取.
也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键.
getch与getchar基本功能相同,差别是getch直接从键盘获取键值,不等待用户按回车,只要用户按一个键,getch就立刻返回, getch返回值是用户输入的ASCII码,出错返回-1.输入的字符不会回显在屏幕上.getch函数常用于程序调试中,在调试时,在关键位置显示有关的结果以待查看,然后用getch函数暂停程序运行,当按任意键后程序继续运行.
可以利用getchar()函数让程序调试运行结束后等待编程者按下键盘才返回编辑界面,用法:在主函数结尾,return 0;之前加上getchar();即可
相关文章推荐
- C语言中getchar()函数的理解
- 换个角度理解C语言getchar()、getch()、scanf()函数
- c语言getchar()函数使用总结
- 轻松理解C语言的入口函数main
- 深入理解C语言的函数调用过程
- 深入理解C语言的函数调用过程
- c语言 对printf函数的理解
- 深入理解C语言-07 函数
- C语言使用scanf函数获取数据后,使用getchar()无法获得字符的处理方法
- 基于C语言sprintf函数的深入理解
- C语言中函数的进一步理解
- 有助于理解C语言一些函数的面试题
- C语言stdio.h中printf函数输出‘12’结果理解
- 深入理解计算机系统中一个echo()函数的C语言实现
- 基于C语言sprintf函数的深入理解
- 深入理解C语言中的free函数。
- 基于C语言sprintf函数的深入理解
- C语言#getchar()函数
- C语言(七) 深度理解函数
- C语言sprintf函数的深入理解