深入解析为什么char c; c = fgetc(fp)是不对的? (在两个公司的面试题中, 都见过这个题)

       我们先来看看下面这个程序在VC++6.0中的运行情况(说明, 我自己已经建立好了test.txt文件夹, 并写了一些内容):

#include <stdio.h>

int main()
{
	char c;
	FILE *fp = fopen("test.txt", "r");
	if(NULL == fp)
	{
		return 1;
	}

	while(EOF != (c = fgetc(fp)))
	{
		putchar(c);
	}

	fclose(fp);
	printf("\n");

	return 0;
}
      在VC++6.0中运行的结果是:

abcdefg


       看起来没有问题, 那么在其他系统中运行呢? 我试了几个环境, 发现都是OK的, 但是, 上面程序是有问题的。

       先从逻辑上来说吧, 在正常情况下, fgetc函数返回的范围就是char的范围, 因此正常情况下用char c;中的c去存这个返回的值, 是足够的。 但是, 当已经达到文件尾或者fgetc函数出错的时候, 就会返回一个错误值, 那怎么去存错误值呢? 显然c的范围必须必char的范围要大才可, 所以用char c;是不正确的。

      从实际上来说, 我们知道, 在大多数系统中char被默认为signed char, 所谓范围是-128-127. 所以, 如果已经达到文件尾或者fgetc函数出错, 则会返回-1, 而EOF的值也通常是-1, 所以, 在上面的程序中, while循环可以顺利退出。 但是, 在有的系统中, char被默认为unsigned char, 此时, 如果fgetc函数返回-1, 一旦赋值给c后, c就是个正值了, 于是上面的while陷入了死循环。因此, 应该用int c;来存-1.

     要说明的是, 在所有系统中, int被默认为signed int,  但char却比较特别, 不一定是signed char, 尽管绝大多是时候是。(这一论断在《C++编程思想》的第一卷中有介绍, 请参考第三章"C++中的C"中的叙述)

     

      可见, 为了程序的可移植性, 应该用int c;  其实, 你看看, fgetc的原型中, 返回值的类型就是int.

     

      “我的疑惑”:我们再来仔细思考一下, 比如在VC++6.0中, 改为int c;后就不会有问题吗? 我把char形的-1写入到文件中, 读取的也是-1, 那岂不是错判为“fgetc函数遇到了文件尾或者出错”了? 那while循环岂不是不正确地结束了? 带着这些疑问, 我们先来看看下面这个简单的程序;

#include <stdio.h>

int main()
{
	FILE *fp = fopen("test.txt", "w");
	if(NULL == fp)
	{
		return 1;
	}

	char ch = -1; 
	fputc(ch, fp); // 实际上fputc的原型要求ch为int, 不过不影响我做测试, 因为char在VC++6.0中的范围是-128-127. 
	fclose(fp);

	

	int c;
	fp = fopen("test.txt", "r");
	if(NULL == fp)
	{
		return 1;
	}

	c = fgetc(fp);
	printf("%d", c);  // 是255, 而不是-1哈
	fclose(fp);
	printf("\n");

	return 0;
}
     上述结果中, c的值是255, 而不是-1, 这就说明, 在正常情况下, fgetc从文件中读出的不可能是负值, 因为ascii值不可能是负值。  而我们知道, 一旦达到文件尾或者fgetc函数出错, 会返回-1, 可见, 正确的值和错误的值是完全区分开了的。 进而可知, 上面“我的疑惑”不再疑惑。

     

      我们再来反思一下, char c; c = fgetc(fp);在VC++6.0中真的不存在问题吗?上菜:

#include <stdio.h>

int main()
{
	FILE *fp = fopen("test.txt", "w");
	if(NULL == fp)
	{
		return 1;
	}

	fputc(128, fp);
	fclose(fp);

	

	char c;
	fp = fopen("test.txt", "r");
	if(NULL == fp)
	{
		return 1;
	}

	c = fgetc(fp);
	printf("%d", c);  // 是-128, 而不是128哈, 所以即使在VC++6.0中,char c;也是错误的
	fclose(fp);
	printf("\n");

	return 0;
}
  

      综上所述: 必须用int c;  , 而类似的函数还有getc, getchar. 

      希望大家在以后的笔试面试中注意这点, 在实际项目中也多加注意。最后强调一句, char可以为负, 但ascii值却没有负值。



你可能感兴趣的:(深入解析为什么char c; c = fgetc(fp)是不对的? (在两个公司的面试题中, 都见过这个题))