【问题标题】:Printing Word Length Histogram in C在 C 中打印字长直方图
【发布时间】:2014-09-10 06:40:00
【问题描述】:

好的,所以我正在使用 Kernighan 和 Ritchie 的“C 编程语言”,我正在练习 1.13,但我似乎无法正确理解这一点。我的程序似乎打印得不多。问题如下:

练习 1-13。编写一个程序来打印其输入中单词长度的直方图。绘制直方图很容易 横条;垂直方向更具挑战性。

除了创建变量,这是我的伪代码,用于读取输入并存储我想要存储在数组中的内容。

  1. 创建一个数组——在这种情况下,我的数组大小为 21(21 个元素,从 0 到 20),最初都赋值为 0。它有 21 个元素,因为我不会使用超过 20 个字符的单词。我意识到这很奇怪,因为没有单词有零个字符。
  2. 开始计算输入中的字符数。
  3. 如果我遇到空格、制表符或换行符(即,这意味着第一个单词结束),请停止。
  4. 根据单词的字符数,递增数组中的特定位置(即,如果单词有两个字符,则在数组中位置 2 的元素上加 1)。
  5. 增加 wordCounter 变量——这个变量正如它的名字所表明的那样,会跟踪输入中已“读取”的单词数。
  6. 继续对每个单词执行此操作,直到达到 EOF。

这是我打印直方图(水平)的伪代码。

  1. 对于第一个位置,使用刻度线打印存储在数组第一个位置(即 0)的值 |
  2. 对数组中的每个元素执行此操作。

这是我的代码:

#include <stdio.h>

#define SIZEOFWORDSOFLENGTH 21

int main() {
    int wordsOfLength[SIZEOFWORDSOFLENGTH];
    int c, i, j;
    int lengthCounter = 0;

    /*Initializing all array elements to 0.*/
    for (i = 0; i < SIZEOFWORDSOFLENGTH; i++)
        wordsOfLength[i] = 0;

    /*Going through the input and counting.*/
    while ((c = getchar()) != EOF) {
        ++lengthCounter;
        if (c == ' ' || c == '\t' || c == '\n') {
            ++wordsOfLength[lengthCounter - 1];
            lengthCounter = 0;
        }
    }

    for (i = 0; i < SIZZEOFWORDSOFLENGTH; i++) {
        printf("Words of Length %d: ", i);
        /*The third argument of the following for loop was previously j = j*/
        for (j = 0; j < SIZEOFWORDSOFLENGTH; j++) {
            while (j < wordsOfLength[i]) {
                printf("|");
                /*Was previously j++ instead of break*/
                break;
            }
        }
        printf("\n");
    }
}

我手动调试了它,但我似乎找不到问题。也许一些非常简单的事情正在我脑海中浮现。另外,我知道以前有人问过这个问题,但我并不想为实际问题找到解决方案,我认为我的伪代码是正确的,如果不是有点正确,我只是想知道我的代码有什么问题,也许可以学到一些东西.提前谢谢你。

【问题讨论】:

  • 请注意,您应该在wordsOfLength 的声明中使用宏SIZEOFWORDSOFLENGTH。如果文件中的第一个字符是空白、制表符或换行符,您应该查看会发生什么。
  • @JonathanLeffler 谢谢乔纳森,我忘了提到我假设我没有前导空格、制表符或换行符。我还在 wordsOfLength 的声明中包含了宏 SIZEOFWORDSOFLENGTH。

标签: c arrays for-loop histogram kernighan-and-ritchie


【解决方案1】:

Ji-Young Parkanswer 所示,读取循环存在问题,因为它在数组wordsOfLength 中使用了负索引。我会保持生活简单并让wordsOfLength[i] 存储长度为i 的单词数,尽管它实际上浪费了wordsOfLength[0]。我会使用来自&lt;ctype.h&gt; 的宏来发现单词边界,并且我会记录我是否在一个单词中。您因使用int c 而获得荣誉。

int inword = 0;
while ((c = getchar()) != EOF)
{
    if (!isspace(c))
        lengthCounter++;
    else if (inword)
    {
        wordsOfLength[lengthCounter]++;
        lengthCounter = 0;
        inword = 0;
    }
}
if (inword)
    wordsOfLength[lengthCounter]++;

此代码不会被文件中的前导空白所迷惑。如果您认为阅读“antidisestablishmentarianism”(28)或“floccinaucinihilipilification”(29)或其他怪诞长词有任何风险,您应该在盲目地将其用作索引之前检查lengthCounter,或者从计数中删除过长的词或将它们全部映射到“20+ 个字符”类。

你最后的三重循环也很成问题——它目前是:

for (i = 0; i < SIZZEOFWORDSOFLENGTH; i++) {
    printf("Words of Length %d: ", i);
    /*The third argument of the following for loop was previously j = j*/
    for (j = 0; j < SIZEOFWORDSOFLENGTH; j++) {
        while (j < wordsOfLength[i]) {
            printf("|");
            /*Was previously j++ instead of break*/
            break;
        }
    }
    printf("\n");
}

根据我的计划,我会从i = 1 开始,但这不是主要问题。我会确保第一个 printf() 打印 2 位数字,以对齐长度为 10-20 的字数的输出。

内部for 循环应受wordsOfLength[i] 而不是SIZEOFWORDSOFLENGTH 约束,while 循环是多余的(尤其是因为您每次都在第一次迭代时中断它)。你只需要简单的嵌套for 循环:

for (i = 1; i < SIZZEOFWORDSOFLENGTH; i++)
{
    printf("Words of Length %2d: ", i);
    for (j = 0; j < wordsOfLength[i]; j++)
        printf("|");
    printf("\n");
}

现在唯一的问题是wordsOfLength 中的最大值是否太长而无法舒适(例如,您已经阅读了莎士比亚的全部作品,因此有些词出现了数千次)。

【讨论】:

    【解决方案2】:

    你不需要从lengthCounter中减去'1'

    ++wordsOfLength[lengthCounter - '1'];
    

    应该是

    ++wordsOfLength[lengthCounter];
    

    【讨论】:

    • 感谢您的回复。假设我写了“嗨,我的名字是 Rene”之类的东西作为输入。在 while 循环的第三次迭代中,lengthCounter 的值不是 3 吗?由于第一个单词“Hi”的长度为 2,我不需要减去一个,使其成为 [lengthCoutner - '1']。我将通过执行 ++wordsOfLength[lengthCounter - '1']; 来增加数组的第二个位置;没有?
    • @ReneAlejandroSantiago:使用lengthCounter - '1'(在1 周围加上单引号)意味着您可能会从长度中减去49。如果你写了lengthCounter - 11 周围没有单引号),你可能会有更好的论据。
    • 啊,对,以防万一,您需要减去 1,而不是 '1'。 '1'是一个字符,不是数字,当你在算术表达式中使用'1'时,它被转换成一个整数值49。
    • @JonathanLeffler 这个特殊的程序依赖于数字字符表示的属性。例如,测试 if (c >= '0' && c
    • @ReneAlejandroSantiago 在 C 中,1 和 '1' 表示不同。如果您运行以下代码 print("%d\n", (int)1); 可以看到差异print("%d\n", (int)'1'); '1' 是数字 1 的字符表示,实际上并不表示数字 1。您可以在ascii-code.com 上查看 ASCII 字符的值
    猜你喜欢
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    • 2011-06-15
    相关资源
    最近更新 更多