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语言,是个初学者,就今天遇到的几个小问题和大家分享一下,如果有更好的解决方案和对问题的理解,也欢迎大家一起讨论。