关于C Prime Plus书中第八章使用EOF作为循环测试条件 改写程序清单7.7来统计文本文件单词量中的问题解析

C Prime Plus第六版书中P224页提到:
“第 7 章演示的统计单词程序(程序清单7.7),计算单词个数直至遇到第1个|字符。把ch的char类型改成int类型,把循环测试中的|替换成EOF,便可用该程序来计算文本文件中的单词量。”
原程序如下:

#include<stdio.h>
#include<ctype.h>//为isspace()函数提供原型
#include<stdbool.h>//为bool、true、false提供定义
#define STOP '|'
int main(void)
{
	char c;//读入字符
	char prev;//读入的前一个字符
	long n_chars = 0L;//字符数
	int n_lines = 0;//行数
	int n_words = 0;//单词数
	int p_lines = 0;//不完整的行数
	bool inword = false;//如果c在单词中,inword等于true

	printf("Enter text to be analyzed(| to terminate):\n");
	prev = '\n';//用于识别完整的行
	while ((c = getchar()) != STOP)
	{
		n_chars++;//统计字符
		if (c == '\n')
			n_lines++;//统计行
		if (!isspace(c) && !inword)
		{
			inword = true;//开始一个新的单词
			n_words++;//统计单词
		}
		if (isspace(c) && inword)
			inword = false;//打到单词的末尾
		prev = c;//保存字符的值
	}

	if (prev != '\n')
		p_lines = 1;
	printf("characters = %ld,words = %d,lines = %d, ",
		n_chars, n_words, n_lines);
	printf("partial lines = %d\n", p_lines);

	return 0;
}

按照书中所说,要将char c改成int c,但是在Windows+VS2019的环境下,char默认实际上是-128-127,而不是书里面说的0-255,因此也可以不改成int,尽管如此,char默认为-128-127或者使用int都会给后面读取文本中的单词量带来错误,这点后面再提,接着是把原程序的|改成EOF,得到改写后的程序如下:

#include<stdio.h>
#include<ctype.h>//为isspace()函数提供原型
#include<stdbool.h>//为bool、true、false提供定义
int main(void)
{
	char c;//读入字符
	char prev;//读入的前一个字符
	long n_chars = 0L;//字符数
	int n_lines = 0;//行数
	int n_words = 0;//单词数
	int p_lines = 0;//不完整的行数
	bool inword = false;//如果c在单词中,inword等于true

	printf("Enter text to be analyzed(CTRL+Z to terminate):\n");
	prev = '\n';//用于识别完整的行
	while ((c = getchar()) != EOF)
	{
		n_chars++;//统计字符
		if (c == '\n')
			n_lines++;//统计行
		if (!isspace(c) && !inword)
		{
			inword = true;//开始一个新的单词
			n_words++;//统计单词
		}
		if (isspace(c) && inword)
			inword = false;//打到单词的末尾
		prev = c;//保存字符的值
	}

	if (prev != '\n')
		p_lines = 1;
	printf("characters = %ld,words = %d,lines = %d, ",
		n_chars, n_words, n_lines);
	printf("partial lines = %d\n", p_lines);

	return 0;
}

将改好的程序编译链接后,运行cmd打开命令行窗口,将一个编好英文语句内容的txt文件重定向给这个exe程序,会出现以下错误:
在这里插入图片描述
为什么会出现这个错误?问题就出在刚才讲的,char现在是默认-128-127的范围,而如果使用了程序中的isspace测试空格函数,这个函数是在isctype.c中定义的,其认为现在默认的char的范围和定义中的不一致,因此会出现这个错误。实际上,这个程序在VS中按F5直接编译链接运行,输入英文语句是可以正常工作的,而如果输入中文,由于中文字符使得char类型的c溢出,c可能被赋予负值,会出现和图中一样的错误窗口,用命令行窗口将txt文件重定向给exe程序作为输入,尽管txt中语句是全英文,也会直接弹出这个错误,这是和VS中运行不一样的地方。
那么如果按照网上的做法,把c简单定义为unsigned char可行吗?至少在这个测试条件下应该是不行的,如果将c定义为unsigned char,那么即使键盘敲入CTRL+Z即EOF信号,赋值给c也会变成255,也就是和循环测试条件里的EOF永远不相等,这样循环永远不会结束,CTRL+Z失效。关于这点,如何在使用EOF作为循环测试条件的同时使用ctype.h中的测试函数,也希望有大佬能够指教。
接下来把程序中使用的isspace测试函数去掉,使用关系运算符代替原来的测试条件:

#include<stdio.h>
int main(void)
{
	const false = 0;
	const true = 1;
	char c;//读入字符
	char prev;//读入的前一个字符
	long n_chars = 0L;//字符数
	int n_lines = 0;//行数
	int n_words = 0;//单词数
	int p_lines = 0;//不完整的行数
	int inword = false;//如果c在单词中,inword等于true

	printf("Enter text to be analyzed(Ctrl+Z to terminate):\n");
	prev = '\n';//用于识别完整的行
	while ((c = getchar()) != EOF)
	{
		n_chars++;//统计字符
		if (c == '\n')
			n_lines++;//统计行
		if (c != ' ' && !inword)
		{
			inword = true;//开始一个新的单词
			n_words++;//统计单词
		}
		if (c == ' ' && inword)
			inword = false;//打到单词的末尾
		prev = c;//保存字符的值
	}

	if (prev != '\n')
		p_lines = 1;
	printf("characters = %ld,words = %d,lines = %d, ",
		n_chars, n_words, n_lines);
	printf("partial lines = %d\n", p_lines);

	return 0;
}

这里还有一个小问题,编译连接后生成的exe如果双击运行,输入英文语句和CTRL+Z结束输入后,窗口会直接消失,这是因为exe程序默认运行结束后直接关闭窗口,而在VS中按F5运行,由于VS2019默认调试结束不关闭控制台窗口,因此会看到while循环结束后打印的内容,如果想看到exe运行后的结果,应该在程序开始加入#include <stdlib.h> 在return 0;前加入system(“pause”); 这样exe运行结束后窗口不会关闭,才能看到while循环结束后打印的内容。(关于这个小问题真的是找了好久,以为是代码本身出了什么错误,最后在之前收藏的一篇VS入门的程序中看到这段,才想起exe直接运行结束后窗口会自动关闭)。
小弟也是从头捡起C语言,是个初学者,就今天遇到的几个小问题和大家分享一下,如果有更好的解决方案和对问题的理解,也欢迎大家一起讨论。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值