《C程序设计语言》关于单词计数的思考

代码分析

源代码来源于Brian W. KernighanDennis M. Ritchie 共同编著的书籍 《The C Program Language》 中1.5.4节中的单词计数

中文版原文:这里对单词的定义比较宽裕,它是任何其中不含空格、制表符或换行符的字符序列,下面这段程序是UNIX系统中wc程序的骨干部分。

#include<stdio.h>

#define IN 1    /* 单词内 */
#define IN 0    /* 单词外 */

main()
{
    int c, nl, nw, nc, state;

    state = OUT;    /* 未有任何字符被读必定为单词外 */
    nl = nw = nc = 0;
    while ((c = getchar()) != EOF) { 
        ++nc;
        if (c == '\n') 
            ++nc;
        if ( c != ' ' && c != '\n' && c !='\t' )
            state = OUT;
        else if (state == OUT){
            state = IN;
            ++nw;
        }
    }
    printf("%d %d %d\n", nl, nw, nc);
}

以下为我的头脑风暴过程。

  • 逻辑是什么?
    • 读 字符
      • 从标准输入流依次读取
      • 在屏幕从左至右依次写入
    • 判断 字符
      • 单词和非单词
        • 区分概念 (人脑逻辑)
          • 单词内
          • 单词外
            • 无任何字符被读
            • 非单词
        • 区分标志 (使人脑逻辑映射到机器)
          • 标志
            • IN
            • OUT

因为是依次从标准输入流读取字符,写入到屏幕显示出来的字符也是有顺序性。
我们的问题是模拟顺序的字符流移动过程中提取单词数。源代码中state变量用作区分标志,state = INstate = OUT代表 单词内单词外 ($单词外 \neq 非单词 $)。有了区分标志,该如何模拟单词内->单词外这种顺序的跨界过程?

标志变化 意义 编号
OUT --> IN 新单词 1
IN --> IN 单词内 2
IN --> OUT 新非单词 3
OUT --> OUT 非新非单词->非单词 4

但随之产生了一个新的问题,OUT具有二象性。
IN情况下结果是唯一的,不用管。1逻辑也就是新单词计数逻辑不需要考虑OUT情况,因为他们都是成立的。

3、4逻辑则必须考虑OUT的二象性。要想让上面3、4逻辑成立,需要额外条件约束,必须读入字符。这是个隐形条件,除了首次读取字符为非单词的特殊情况,OUT(无输入字符)-->OUT(有输入字符),其他的OUT情况都是处在有输入字符的情况中。

state =  OUT; /* OUT(无输入字符) */
/*...省略....*/
if ( c != ' ' && c != '\n' && c !='\t' ) /* OUT(有输入字符) */
            state = OUT;

上述代码则是描述了 OUT(无输入字符)-->OUT(有输入字符) 这一特殊情况。
在这之后所有的OUT都被限定为有OUT(有输入字符),通过如下循环限制。

while ((c = getchar()) != EOF){}

至此所有逻辑分析完毕,随之而然也可以得到 非单词计数的逻辑,从而写出代码。下面是我的代码并经过实验验证。

int main(int argc, char *argv[]) {
    
    int c, nl, nw, nc, state;
    nl = nw = nc = 0; /* 各计数器初始化 */
    state = OUT; /* 无输入时必定在单词外 */ 
    
    while ( (c = getchar()) != EOF )
    {
        ++nc;
        if ( c == '\n')
            ++nl;
        if (c != ' ' && c != '\n' && c !='\t')
        {
            state = IN;                             
        } 
        else if ( state == IN )  /* 首个非单词 */
        {
            state = OUT; 
            ++nw;
        }
        else if ( state == OUT ) /* 非首个非单词 */ 
        {
            state = OUT;    
            ++nw; 
        }
    }
    
    printf("%d %d %d", nl, nw, nc);
     
    return 0;
}

除去逻辑,仅仅说编程风格上,if语句条件,改成常量在左,变量在右,更科学。《C编程专家》中有提到过。C语言规定常量不可以被赋值,如果少写了个=号,编译的时候也会发现。而反之是不会提示的,因为语法上是没有错误的,但在我们逻辑上错误了。

else if( OUT == state )

另外对于新手来说,就是else if(){} 的逻辑问题了,else后面整个if语句是其执行语句

else
{
    if(){

    }
}

代码很简单,但却有许多值得思考的地方,也略窥大师的深厚功底,假设咱们坚持这样的10000小时理论,大家包括我都可以成为这个行业的专家。加油吧,与大家共勉。

猜你喜欢

转载自www.cnblogs.com/Fsiswo/p/11145999.html