4

我开始学习 C 和我的一个朋友(比我大)The C Programming LanguageBrian KernighanDennis Ritchie建议。

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

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

#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 做。

感谢您的帮助。

4

7 回答 7

9

这个对我有用。

$ 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 。

于 2012-08-08T03:18:20.780 回答
4

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

主要原因是这本书是在良好的编程风格发明之前编写的。大多数示例都是用大多数现代 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() 的正确方法。
  • Nitpick 关于 main(),声明为 void 而不是空括号。

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

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

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

由于存在大量错误、错误和拼写错误,因此请确保在阅读 K&R 时始终将勘误表放在手边。

于 2012-08-08T07:45:58.190 回答
3

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

echo this has four words | example

你会看到输出:

1 4 20

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

于 2012-08-08T03:15:21.417 回答
2

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

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

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

祝你好运,黑客愉快!

于 2012-08-08T03:36:04.137 回答
0

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

bla
blah
2

./a.out < a.in我通常通过在 *nix 上重定向输入来运行此类程序

于 2012-08-08T03:17:49.213 回答
0

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

于 2012-08-08T03:22:33.707 回答
-2

C 编程语言是 Dennis Ritchie 的一本好书。但是,如果您对它不满意,您可以使用另一本书:
Let Us C-by Yashwant Kanetkar 读完这本书后,您想看看您真正了解多少 C(即您知道多少关于它的语法和怪癖),你可以试试这个:
Test Your C Skills-by Yashwant Kanetkar

于 2012-08-08T03:24:52.450 回答