1.5.4 单词计数
第四个实用程序,用于统计行数、单词数与字符数。这里对单词的定义比较宽松,它是任何其中不包含空格、制表符或换行符的字符序列。
#include
#define IN 1 /* 在单词内 */
#define OUT 0 /* 在单词外*/
/* 统计输入的行数、单词数与字符数*/
main() {
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n')
++nl;
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
下列语句
nl = nw = nc = 0;
将把其中的3个变量nl、nw与nc都设置为0。运算符 || 代表OR(逻辑或),所以
if (c == ' ' || c == '\n' || c == '\t')
的意义时“如果c是空格,或c是换行符,或c是制表符‘。相应的&&代表AND(逻辑与),它比||高一个优先级。由&&或||连接的表达式由左至右求值,并保证在求值过程中只要能够判断最终的结果为真或假,求值就立即终止。
练习1-11 你准备如何测试单词计数程序?如果程序中存在某种错误,那么什么样的输入最可能发现年这类错误呢?
练习1-12 编写一个程序,以每行一个单词的形式打印其输入。
————————————————————————————————————
练习1-11 其实就是测试用例的编写:
test1:不输入任何字符,直接结束输入(Ctrl+D)。res:0 0 0
test2:输入1个字符,a,按结束。 res:1 1 1
test3:输入2个字符,中间带有空格或制表符,a a,按结束。 res:1 2 3
test4:输入2个字符,中间不带空格,aa,按结束。res:1 1 2
test5:输入2行,第一行输入1个字符,a;第二行输入1个字符,a,按结束。res:2 2 3
test6:输入2行,第一行输入1个字符,a;第二行输入2个字符,中间带有空格或制表符,a a,按结束。res:2 3 5
test7:输入2行,第一行输入1个字符,a;第二行输入2个字符,中间不带空格,aa,按结束。res:2 2 4
test8:输入换行符\n或者制表符\t或者空格,按结束。res:1 0 1
进行上面测试用例测试,会发现test2输出: 0 1 1,与预期不符,后面的基本都是,少一行。这是什么原因呢?是因为程序以换行符\n作为1行的结束,但是如果这一行输入字符了但是没有输入换行符,这一行就统计不上,所以就得在输出时,判断当前行有没有输入,如果有,就要计算当前行。程序修改如下:
#include
#define IN 1 /* 在单词内 */
#define OUT 0 /* 在单词外*/
/* 统计输入的行数、单词数与字符数*/
main() {
int c, nl, nw, nc, state, iflag; // iflag表示这一行有没有输入字符
state = OUT;
iflag = 0;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
iflag = 1; // 只要有一个输入,那么当前行就要计算
++nc;
if (c == '\n') {
iflag = 0; // 每次换行重置当前行是否输入装态
++nl;
}
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
if (iflag == 1)
++nl;
printf("%d %d %d\n", nl, nw, nc);
}
————————————————————————————————————
练习1-12
#include
/* 练习1-12 编写一个程序,以每行一个单词的形式打印其输入。*/
main() {
int c;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\t' || c =='\n') {
if(c != '\n')
putchar('\n');
} else {
putchar(c);
}
}
}