C语言直方图 && EOF释疑

用C语言统计单词长度出现的频率
#include <stdio.h>

#define MAX_LEN 10  //单词的最大长度
#define IN  1
#define OUT 0

int main(void)
{
    int len;    //每个单词的长度
    int wc[MAX_LEN+1] = {0};  //每个长度对应的单词数
    int c, i, j;
    int state;
	int maxnum=0;	//wc[]中的最大数

    len = c = i = 0;
	state = OUT;
    while((c = getchar()) != EOF)  {
		if(c == ' ' || c == '\t' || c == '\n') {
            if(state == IN)  {	//或者 if(len > 0)
				if(len >= MAX_LEN) {
					wc[MAX_LEN]++;
					len = MAX_LEN;	//单词长度大于MAX_LEN
				}
				else {
					wc[len]++;
				}
				if(maxnum < wc[len])
					maxnum = wc[len];
                len = 0;
				state = OUT;
            }
		}
		else if(state == OUT) {
			state = IN;
			len = 0;	//单词真实的长度为len+1
		}
			else
				len++;
	}

	putchar('\n');

	for(i = maxnum; i > 0; i--) {
		printf("%3d|", i);
		for(j = 0; j <= MAX_LEN; j++) {
			if(wc[j] >= i)
				printf(" * ");
			else
				printf("   ");
		}
		putchar('\n');
	}
	printf("   +");
	for(i = 0; i <= MAX_LEN; i++)
		printf("___");
	printf("\n   ");
	for(i = 0; i < MAX_LEN; i++) {
		printf("%3d", i+1);
	}
	printf(" >10");
	putchar('\n');
	return 0;
}

效果图


EOF释疑(转自这里)

首先要明白一点,EOF并不是标志结尾的特殊字符,而是文字流(stream,标准输入或者文件)达到结尾时返回的一个信号量,在stdio.h中定义为常量,其值常常为-1,只在文本文件中存在,二进制文件中不存在。

1.如果是从标准输入中读取stream,如下程序

int c;//定义为int类型,因为返回值EOF(-1)是int类型的
while((c=getchar()) != EOF)
    putchar(c);
由于标准输入中无法事先判断长度,无法判断是否是End Of File,所以需要手动输入一个字符表示达到EOF。

Windows中,在新的一行开头中按下Ctrl+Z,表示达到EOF(因为Windows输入是阻塞式的,所以在敲下换行键之前不会检测Ctrl+Z);

Linux中,在新的一行开头,按下Ctrl-D,表示达到EOF(或者在一行的中间按两次Ctrl-D,因为在一行的中间按下Ctrl-D,表示输出"标准输入"的缓存区);

2.如果是从文件中读取stream,一般写成如下形式

int c;
while ((c = fgetc(fp)) != EOF){
    c = fgetc(fp);
    do something;
}

这样写有一个问题。fgetc()不仅是遇到文件结尾时返回EOF,而且当发生错误时,也会返回EOF。因此,C语言又提供了feof()函数,用来保证确实是到了文件结尾。上面的代码feof()版本的写法就是:
int c;
while (!feof(fp)) {
  c = fgetc(fp);
  do something;
}
但是,这样写也有问题。fgetc()读取文件的最后一个字符以后,C语言的feof()函数依然返回0,表明没有到达文件结尾;只有当fgetc()向后再读取一个字符(即越过最后一个字符),feof()才会返回一个非零值,表示到达文件结尾。
所以,按照上面这样写法,如果一个文件含有n个字符,那么while循环的内部操作会运行n+1次。所以,最保险的写法是像下面这样:
int c = fgetc(fp);
while (c != EOF) {
  do something;
  c = fgetc(fp);
}
if (feof(fp)) {
  printf("\n End of file reached.");
} else {
  printf("\n Something went wrong.");
}


这样在读取stream时,如果c = fgetc(fp) 读到的是二进制的-1,怎么区分读到的c(-1)跟信号值(-1)呢?

一种解释(不一定对,欢迎讨论):

在文本文件中,数据以字符的ASCII码值的形式存放。ASCII码值的范围是0~255,不可能出现-1,-1实际上是‘-’ 和‘1’,而fgetc是文本视图处理文件的,因此可以用EOF作为文件结束标志输入的。

注意:EOF只存在文本视图中,二进制视图是通过比较文件长度来判断是否达到文件结尾。

原文地址:https://www.cnblogs.com/java20130726/p/3218679.html