【问题标题】:The C programming language book example: maybe out of date?C 编程语言书籍示例:可能已过时?
【发布时间】:2012-08-08 03:11:41
【问题描述】:

我开始学习 C,我的一个朋友(比我年长)推荐了 Brian KernighanDennis RitchieThe C Programming Language

然而,在尝试一些示例时,它们的行为与预期不同,并且与书中所写的不同。

例如,这个似乎不起作用(不打印):

#include <stdio.h>

#define IN 1
#define OUT 0

/* count lines, words, and characters in input */

int 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);
   return 0;
}

你认为我应该继续读这本书吗,也许只有几个错误,值得一读?或者有一本适合 C 初学者的更好的书。

编辑:我的假设是使用ENTER 键发送输入将模拟EOF,但事实并非如此。 CTRL+Z 会。

感谢您的帮助。

【问题讨论】:

  • 这是一本了不起的书。如果您能按照自己的方式完成示例并进行练习,您将为自己探索 C 语言打下坚实的基础。
  • 如果ENTER 触发了文件结束条件,则很难或不可能接受多行输入。

标签: c


【解决方案1】:

它对我有用。

$ gcc c.c -o c
$ echo hello world | ./c
1 2 12
$ 

程序从标准输入读取文本,直到到达文件末尾。我怀疑您在从键盘读取时没有正确地发出文件结束条件的信号。在 Linux 和其他类 Unix 系统上,单独在一行上键入 Ctrl-D。在 Windows 上,键入 Ctrl-Z

如果您从 IDE 启动程序,它可能会在新启动的终端窗口中运行程序,该终端窗口会在程序完成时关闭;在这种情况下,窗口可能会在您看到输出之前消失。如果您的 IDE 没有提供覆盖此错误行为的方法,您可以直接从运行 shell 的终端窗口运行它,也可以添加如下行:

getchar();

到程序末尾,return 0; 之前。这导致它在终止之前读取(并忽略)输入字符;您可以在看到输出后键入 Enter。请注意,当您从 shell 执行程序时,这种事情会使程序运行变得更加尴尬,因此请仅在必要时执行此操作。

Kernighan 和 Ritchie 合着的《The C Programming Language》,通常称为 K&R,是一本优秀的 C 书籍;毕竟,里奇在很大程度上发明了这种语言,尽管它确实倾向于假设一些现有的编程知识。确保你有第二版;第一个描述了该语言的早期版本。 (自 K&R2 发布以来,已经有两个新的 ISO C 标准,但它们没有添加任何对介绍性测试至关重要的内容。)

有关其他 C 在线教程和书籍的列表,请参阅comp.lang.c FAQ 的问题 18.9 和 18.10。

【讨论】:

    【解决方案2】:

    K&R 因怀旧和由丹尼斯·里奇 (Dennis Ritchie) 所写而受到了很多“跟风炒作”。毫无疑问,它是有史以来最著名的编程书籍。然而,在我看来,这对初学者来说并不是一本好书。

    主要原因是这本书是在良好的编程风格发明之前编写的。大多数示例都是用大多数现代 C 程序员认为是相当混乱的编码风格编写的。什么是好的和坏的编码风格当然是一个主观的话题。但以你为例。可以改写成这样:

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    
    /* count lines, words, and characters in input */
    
    int main (void)
    {
       int  ch;
       int  linefeeds_n = 0;
       int  words_n     = 0;
       int  chars_n     = 0;
       bool new_word    = true;
    
    
       while ((ch = getchar()) != EOF) 
       {
         if (ch == '\n')
         {
           new_word = true;       
           linefeeds_n++;
         }
         else if (ch == ' ' || ch == '\t')
         {
           new_word = true;
         }
         else if (new_word)
         {
           new_word = false;
           words_n++;
         }
    
         chars_n++;
       }
    
       printf("%d %d %d\n", 
              linefeeds_n, 
              words_n, 
              chars_n);
    
       return EXIT_SUCCESS;
    }
    

    我发现上述风格更具可读性和正确性。变化是:

    • 合理的变量名称。
    • 可读的变量声明列表。
    • 没有神秘的状态变量。请改用 bool 类型。
    • 始终对每个语句使用 {},以防止出现大量经典错误。
    • 没有针对“\n”的多重检查(更快的代码)。
    • while 循环结束时的计数器增量(常用编码风格)。
    • 按照 C99 结束 main() 的正确方法。
    • 关于 main() 的吹毛求疵,声明为 void 而不是空括号。

    它们没有大的变化,没有大的问题,但一切都很快堆积起来......

    此代码也是使用最新 C99/C11 标准的功能编写的,这是您在 K&R 中找不到的,因为这本书也没有跟上最新的 C 标准。

    此外,在 K&R 中还有一些案例,这本书是不正确的,或者它宣扬了公然危险的做法。一个完美的例子是:对 malloc 的结果进行类型转换。更多有效批评本书的例子可以在this article找到。

    由于存在大量错误、错误和拼写错误,因此请确保在阅读 K&R 时始终将errata 放在触手可及的范围内。

    【讨论】:

    • -1:使用char 类型的对象来保存getchar() 的结果是一个大NO-NO。见c-faq.com/stdio/getcharc.html
    • @pmg 哎呀,感谢您指出这一点。这只是摆脱编译器警告的快速解决方案。固定。
    【解决方案3】:

    该程序运行良好。请注意,它在打印任何内容之前需要一些输入;它计算输入中的行数、单词数和字符数。因此,如果您将代码编译成example 并运行:

    echo this has four words | example
    

    你会看到输出:

    1 4 20
    

    (即 1 行,4 个单词,20 个字符)。

    【讨论】:

      【解决方案4】:

      所以,你的程序可能什么也不打印,但在你按下 Ctrl+C 或类似的东西之前不会给你提示,对吧?这意味着您永远不会退出 while 循环,这意味着您的输入中没有 EOF。

      该书基于较旧的体系结构,这些体系结构可能对构成 EOF 的内容有不同的约定。我对这本书的建议是继续读下去,保持灵活的思维,这样你就可以解释错误并解决它们。从书本上学习是很棒的,但是在你开始使用它并自己调试它之前,你不会真正集成它。例如,如果我不知道这个程序中发生了什么,我可能会在 while 循环中放置一个 printf 来获取有关循环行为的一些反馈。我还可以尝试将 EOF 更改为其他内容(可能是 -1、.、//)。想象一下,你是一个只会玩东西的小孩,你可能会学得更快。至少这是我的经验。

      至于其他值得学习的书籍,我强烈推荐 Jon Erickson 的《黑客,剥削的艺术》一书。它不需要以前的编程经验,第二章是对 C 的非常全面的介绍。我从这本书的这一章中学到了更多关于计算机如何真正工作的知识,而不是在一所私立大学的 3 个学期的计算机编程课程中。它以非常清晰但密集的方式解释了如何使用 GNU 调试器、编译器如何解释您编写的代码、内存如何工作(堆栈、bss 等),最重要的是,它解释了如何看待生活中的其他事物作为程序(法律,生物学等)。如果你有毅力通过它,本书的其余部分将教你大量有用的信息。

      祝你好运,黑客愉快!

      【讨论】:

        【解决方案5】:

        它对我来说很好用。它真的不应该过时,因为语言在相当长的一段时间内没有太大变化。互联网和书籍中存在的一些示例可能是特定于操作系统的。一个典型的例子是system("PAUSE");,它只适用于 Windows,但可以转换为一个哨兵循环,不断询问你是否要再次运行它或有一个选项菜单。我运行了这个例子并点击了 ctrl-d,它输出了5 3 14。以下是我的输入。最后两个是空行。

        bla
        blah
        2
        

        我通常通过在 *nix 上重定向输入(例如 ./a.out &lt; a.in)来运行此类程序

        【讨论】:

          【解决方案6】:

          《The C Programming Language》对你来说是一本非常好的书,相信你的朋友。 你什么都看不到的原因是你没有结束你的输入。 在像这样的 Unix 中,您可以输入 Ctrl + D,以结束您的输入。 程序没问题,我测试一下。

          【讨论】:

            【解决方案7】:

            C 编程语言是 Dennis Ritchie 的一本好书。但是,如果您对此感到不满意,可以使用另一本书:
            Let Us C-作者:Yashwant Kanetkar 读完这本书后,如果你想看看你真正了解 C 的多少(也就是说,你对它的语法和怪癖了解多少),你可以试试这个:
            测试你的 C 技能 - Yashwant Kanetkar

            【讨论】:

              猜你喜欢
              • 2010-09-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多