《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小时理论,大家包括我都可以成为这个行业的专家。加油吧,与大家共勉。

原文地址:https://www.cnblogs.com/Fsiswo/p/11145999.html

时间: 2024-08-09 15:56:33

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

重读《C程序设计语言》(2):导言

这一章主要是概要的介绍C语言,通过实际程序引入C语言的基本元素.至于具体细节,后续章节将进一步介绍. (1)学习一门新程序设计语言的唯一途径就是使用它编写程序. /* * Copyright (C) [email protected] */ #include <stdio.h> main() { printf("hello, world\n"); } (2)在UNIX中,要运行上述代码,首先要在某个文件中建立这个程序,并以" .c "作为文件的扩展名.通

自然语言处理第二讲:单词计数

自然语言处理:单词计数 这一讲主要内容(Today): 1.语料库及其性质: 2.Zipf 法则: 3.标注语料库例子: 4.分词算法: 一. 语料库及其性质: a) 什么是语料库(Corpora) i. 一个语料库就是一份自然发生的语言文本的载体,以机器可读形式存储: ii. 一种平衡语料库尝试在语言或者其他领域具有代表性: b) 译者注:平行语料库与平衡语料库的特点与区别 i. 平行语料库通常是由双语或多语的对应语料构成,常常是翻译文本构成.例如:Babel English-Chinese

程序设计语言基本概念语 与经典真题

一.基本概念 在计算机中,程序设计语言可划分为低级语言和高级语言两大类,与高级语言相比,用低级语言开发的程序,其运行效率高,但开发效率低.与程序设计相关的基本概念如下. (1)低级语言:又称面向机器语言,它是特定的计算机系统所固有的语言. (2)汇编语言:是机器语言的一种提升,它使用了一些助记符来表示机器指令中的操作码和操作数.但它仍然是一种和计算机机器语言十分接近的语言,使用起来仍然不太方便. (3)高级语言:与人们的自然语言比较接近,使用起来很方便,也极大的提高了程序设计效率. (4)编译程

c程序设计语言第一章2

练习1.13编写一个程序,打印输入中单词长度的直方图.水平方向的直方图比较容易绘制,垂直方向的直方图则要困难些 1 #include <stdio.h> 2 #include <stdlib.h> 3 #define MAXHIST 15//定义直方图的最大值 4 #define MAXWORD 11//定义单词的最大字符数 5 #define IN 1 6 #define OUT 0 7 int main() 8 { 9 int nc;//单词所含的字符数 10 int maxv

程序设计语言学习

人,程序,计算机 计算机的诞生就是为了帮助人们完成一些任务.计算机以其速度快.失误少.持续时间长.保存时间久等特点弥补了人类的不足. 程序是计算机完成人类任务的计划书.说明书.指导书或者说是执行步骤. 运行程序就是计算机照着计划书执行任务的过程. 程序设计语言则是人们写计划书的语言.与人们给自己写计划书用汉语.英语等语言一样,人们给计算机写计划书要用计算机能够认识的语言——机器语言,也就是01串.这也是可编程计算机刚刚出现时人们使用的语言. 但是01这种二进制的语言不好记忆.不好交流.不好理解,

大数据【四】MapReduce(单词计数;二次排序;计数器;join;分布式缓存)

   前言: 根据前面的几篇博客学习,现在可以进行MapReduce学习了.本篇博客首先阐述了MapReduce的概念及使用原理,其次直接从五个实验中实践学习(单词计数,二次排序,计数器,join,分布式缓存). 一 概述 定义 MapReduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE).这样做的好处是可以在任务被分解后,可以通过大量机器进行并行计算,减少整个操作的时间. 适用范围:数据量大,但是数据种类小可以放入内存. 基

对于《C程序设计语言》的一点理解

想必学C语言的人大都看过这一经典书籍.对于我来说,处于不同学习层次,阅读这本书的感觉是不一样的,每次阅读都会有一番新的感悟.第一次阅读时先读的英文版,读的很困难,主要是记录不会的单词:第二遍就顺利多了,但是对于其中的内容缺乏较深入的了解:第三遍就直接买了机械工业出版社出版的中文版,尝试读了一遍,但是对于后面几章特别是指针部分几乎读不下去:然后就开始做上面的练习,主要是做了前6章的练习,这其中费了不少时间和精力,还有一部分练习没有做. 对了,需要对这一分类下的博文做出几点说明. ①笔记中所说的[教

02:名字、作用域和约束(Bindings)-[程序设计语言]-摘记&amp;注解

阅读导航 本系列其他文章目录请戳这里. 1.名字.约束时间(Binding Time) 2.对象生存期和存储管理 2.1静态分配 2.2基于栈的分配 2.2堆分配和垃圾收集 3.作用域规则 3.1静态作用域 3.2嵌套子程序 3.3动态作用域 4.引用环境的约束 4.1子程序闭包 4.2一级和二级子程序 5.作用域里的约束 1.名字.约束时间(Binding Time) 在本篇博文开始前先介绍两个约定:第一个是“对象”,除非在介绍面向对象语言时,本系列中出现的对象均是指任何可以有名字的东西,比如

软考-程序设计语言基础(编译原理)

首先声明一下,本系列软考的文章是针对软件设计师(中级)的. 在软件设计师考试中,关于程序设计语言这一章节,前面的知识很基础,像一些控制结构和数据类型的知识我想大家都非常熟练就没有总结在图里. 本章节的重点内容在于编译原理,编译原理指的是编译器是将汇编或高级计算机语言翻译为二进制机器语言代码的计算机程序.内容主要包括文法.正规式.有限自动机.语法推导树. 好了,不多说,还是老规矩用图来介绍. 重点看一下编译原理,展开前三项看看. 文法,是描述语法结构的形式规则: 正规式是描述程序语言单词的表达式,