【问题标题】:Unexpected results when assigning values to an array In c将值分配给数组 In c 时出现意外结果
【发布时间】:2012-01-27 03:25:16
【问题描述】:

我正在阅读C The Programming Language Second Edition。我参加了这个练习 [1.6 节中的 1-13,pg。 24 第二版]。

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

我认为一切都很好,除非我尝试确定最后一个字数(VARIABLE tmp)是 10,然后将其分配给 count[tmp-1] 或 count[11] 中的相应索引如果大于。我什至不关心打印一个实际的直方图,我现在只想有一个有效的数组表示。下面是我的程序运行时的输出。

asdasd 
_________________________________
 1  2  3  4  5  6  7  8  9 10 11 
   (x-axis) Length of words 
---------------------------------
[0 SPACE] [0 NEWLINE] [0 TAB] 
[1 WORD] [0.000 KILOBYTE] [6 CHAR]



6---


ARRAy= 1  1  1  1  1  2  0  0  0  0 

这是我的代码

#include <stdio.h>
#define MAX 10


int main (void) {
    //
    int nc,nw,nt,ns,nl;  //nc = bytes, nw = words, nt = tabs, ns = spaces, nl = newlines
    nc = nw = nt = ns = nl = 0;
    //
    int c;                     //getchar()
    int done = 0;             //don't even know I'm a noob just ignore...
    int tmp = 0;              //last word count (this works well)
    int array[MAX + 1];      //For outputting screen formatters like ---
    int count[11];           //THIS is whats broken random values
    int state = 0;
    int waslast = 0;
    float kbcount = 0;
    for (c = 0; c <= MAX; c++)
    count[c] = 0;

    while (done == 0) {
        c = getchar();
        ++nc;

        if (c == ' ' || c == '\n' || c == '\t') {
            waslast = 1;



            if (c == '\t') {
                ++nt;
                state = tmp;
                tmp = 0;
            }
            else if (c == '\n') {
                ++nl;
                state = tmp;
                tmp = 0;
            }
            else if (c == ' ') {
                ++ns;
                state = tmp;
                tmp = 0;
            }
        }

        if (c == EOF) {
            done = 1;
        }
        else if (c != ' ' && c != '\n' && c != '\t') {
            tmp++;
            state = tmp;
            if (waslast == 1) {
                nw++;
                waslast=0;
            }
            if (nc == 1)
                nw++;
        }

        if (tmp <= 10)
            count[tmp-1]++;       //Completely random assignments
        else
            count[11]++;          //This is broken
    }



    // END WHILE
    //
    //



    printf("\n");
    for (c = 1; c <= MAX + 1; c++) {
        printf("___");

    }

    printf("\n");

    for (c = 1; c <= MAX + 1; c++) {
        array[c] = c;
        printf("%2d ", array[c]);
    }

    printf("\n   (x-axis) Length of words \n");

    for (c = 1; c <= MAX + 1; c++){
        printf("---");
    }

    kbcount = (nc-1)/1024;

    printf("\n[%d SPACE] [%d NEWLINE] [%d TAB] \n[%d WORD] [%.3f KILOBYTE] [%d CHAR]\n\n\n\n%d---\n\n\n",
           ns,nl,nt,nw,kbcount,(nc -(nl+nt+ns))-1,state);

    printf("ARRAy=");
    for (c = 0; c<MAX ;++c)
        printf(" %d ",count[c]);
    return 0;


}

~ ~

【问题讨论】:

    标签: c arrays histogram


    【解决方案1】:

    c 数组从 0 开始索引。count[11]++; 超出数组范围。

    11 元素数组的有效索引是索引 0 到 10(含)。数组count 中的第11 个元素位于count[10]

    【讨论】:

      【解决方案2】:

      你犯了三个主要错误。前两个是文体,让我 - 和大多数其他人 - 不想阅读代码和帮助。最后一个是你的逻辑错误......好吧,无论如何。

      1. 花时间输入有意义的变量名。或者至少是截断的。比如 NumTabs 或任何适合你风格的东西。
      2. 降低缩进样式。适当的缩进有助于更容易理解程序流程。

      所以,当你这样做时,你最大的明显错误是:

      count[11]++;          //This is broken
      

      在代码中,它被定义为:

      int count[11];
      

      该数组中有 11 个整数。但是,您不是从 1 开始引用它们。您从 0 开始引用它们。count[0]、count[1]...count[10] 都是有效的。像这样:

      0 1 2 3 4 5 6 7 8 9 10

      正如您所见,这是 11 个数字,尽管它最多只能达到 10 个。如果您希望能够访问 count[11],您必须将 count 声明为

      int count[12];
      

      这被称为非一错误。这是一个非常基本的错误,但不要感觉太糟糕,即使是大师最终也会犯下(通常更复杂和更严重)相同基本错误的版本。一般来说,字符串处理也是一种真正的痛苦。

      无论如何,如果这还不够,如果你想从概念上想象它——这不是它的工作方式,而是从概念上——你的数组分配了 11 个 int,'count' 是指向它的指针。所以 (pointer+0) 将指向第一个整数,这与指针 [0] 相同。 (pointer+1) 这与说 pointer[1] 将指向第二个整数是一样的。 (pointer+5)/pointer[5] 会指向第 6 个整数,(pointer+11)/pointer[11] 会指向第 12 个 - 这不存在,因为它们只有 11 个。

      【讨论】:

      • 对不起,但正如我所说,这实际上是你好世界的下一步,也是我在 stackoverflow 上的第一篇文章。另外我不知道 count[10] 是指 0-9 还是 0-10,但现在我明白了,这本书中没有太多适合新手的信息,但感谢您的帮助。
      • @user1114092: count[10] 创建count[0]count[1]count[2]、...和count[9]count[10] 未定义,但访问它很可能会导致不好的事情发生。
      • @KeithThompson 不需要道歉 - 特别是如果这是您从 hello world 迈出的第一步。你做得很好!从经验中汲取一些建议——尽早养成好习惯,这样你就不必(痛苦地)以后再学习坏习惯。 mctyler 的帖子对您​​的代码进行了很多压缩和更改,但如果您研究它,他也会提出一些很好的建议(特别是枚举的使用。这是一个简单的“有限状态机”的相当清楚的例子),尽管它可能有点此刻超越你。
      • @user1114092 叹息。抱歉,我也是 StackOverflow 的新手。我的意思是针对您,而不是 KeithThompson,他刚刚编辑了缩进并对此发表了评论:-P(感谢 keith!)
      【解决方案3】:

      两个您的程序包含的三个附加点(错误)是

      • 整数的除法产生一个整数的结果,所以在:

        float kbcount = (nc-1)/1024;

      变量kbcount 设置为nc - 1 除以1024 的整数除法的整数 结果。

      我相信你想说的是:

      float kbcount = (nc - 1) / 1024.0;

      由于其中一个部分(本例中的分母)是浮点数,因此优先规则将(提升)两个部分都转换为浮点值,然后除法变为浮点点除法,所以结果将是一个浮点值它的小数(十进制)值。阅读 The C Programming Language 的 Section 2.7(第 42 页)以获得更好的解释。

      接下来,

      • 您可以简化确定 c 是单词的一部分还是“空白”(空格、制表符、换行符)的一部分的逻辑,以使您的程序更短且更易于理解。

      例如:

      enum state_t = {whitespace, printable};
      ...
      
      enum state_t state = whitespace;
      while (EOF != (c = getchar())) {
          bytes++;
      
          if (is_whitespace(c)) {
              if (state == printable) { /* the whitespace ends the 'word' state */
                  count[length % MAX]++;
                  length = 0;
              }
              ...
              state = whitespace;
          } else {
              if (state == whitespace) {
                  /* starting a new word */
                  wordcount++;
              }
              length++ /* word length */
              state = printable;
          }
          ...
          /* anything else you want to do */
      }
      /* done reading standard input (stdin), now print report... */
      

      请注意,使用更好的变量名更容易阅读。

      最后,

      • 您是新手或初学者,不是noob

      参考:

      //don't even know I'm a noob just ignore...
      

      老实说,每个程序员在开始和学习新的编程语言时都会犯错误。但这是自然学习过程的一部分。您通过探索、尝试新的事物并发现两者,什么有效,什么无效来学习。这是一个过程,希望您能够享受努力的挑战,不仅要考虑问题的解决方案,还要将解决方案解构为合乎逻辑的小步骤,然后编写它正确地使用合成语言,在这种情况下,C

      【讨论】:

      • 你知道这可能是我见过的最简单的有限状态机设计模式的最清晰的例子之一。你应该概括它并制作一个教程,概念和设计模式非常有用。您发现的大多数教学文献……总的来说,IMO 很糟糕。
      • @OrgnlDave,谢谢。我并没有试图确保它是一个 FSM 设计,这可能就是它简单易懂的原因。假期结束后,我会考虑写一个教程。
      猜你喜欢
      • 1970-01-01
      • 2018-10-27
      • 1970-01-01
      • 1970-01-01
      • 2020-04-25
      • 1970-01-01
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多