为什么用奇怪的方式初始化此数组?

时间:2018-12-06 02:15:30

标签: c arrays

我正在阅读K&R第二版,但在理解练习1-13时遇到困难。答案是这样的代码

#include <stdio.h>

#define MAXHIST 15  
#define MAXWORD 11  
#define IN 1        
#define OUT 0      


main()
{

    int c, i, nc, state;
    int len;
    int maxvalue;
    int ovflow;
    int wl[MAXWORD];

    state = OUT;
    nc = 0;         
    ovflow = 0;

    for (i = 0; i < MAXWORD; i++)
        wl[i] = 0;  

    while ((c = getchar()) != EOF)
    {
        if(c == ' ' || c == '\n' || c == '\t')
        {
            state = OUT;            
            if (nc > 0)
            {
                if (nc < MAXWORD)   
                    ++wl[nc];       
                else
                    ++ovflow;       
            }                       
            nc = 0;                 
        }
        else if (state == OUT)
        {
            state = IN;             
            nc = 1;                 
        }
        else
            ++nc;                   
    }

    maxvalue = 0;
    for (i = 1; i < MAXWORD; ++i)
    {
        if(wl[i] > maxvalue)
            maxvalue = wl[i];       
    }

    for(i = 1; i < MAXWORD; ++i)
    {
        printf("%5d - %5d : ", i, wl[i]);
        if(wl[i] > 0)
        {
            if((len = wl[i] * MAXHIST / maxvalue) <= 0)
                len = 1;
        }
        else
            len = 0;

        while(len > 0)
        {
            putchar('*');
            --len;
        }
        putchar('\n');
    }

    if (ovflow > 0)
        printf("There are %d words >= %d\n", ovflow, MAXWORD);

    return 0;

}

在顶部,wl被声明和初始化。我不明白的是,如果它只计算单词的长度,为什么要遍历它并将所有内容都设置为零?它不会跟踪有多少个单词,而只会跟踪单词的长度,因此为什么将所有内容都设置为0?

我知道目前还不清楚,在过去的20分钟里一直在向我施加压力,我不知道为什么。

3 个答案:

答案 0 :(得分:3)

数组i的第wl[]个元素是在输入文件中找到的长度为i的单词数。 wl[]数组需要首先进行零初始化,以便++wl[nc];不会通过尝试使用未初始化的变量而导致未定义的行为,并且表示不存在的字长的数组元素反映出否找到了这样的字长。

请注意,遇到长度为++wl[nc]的单词时,wl[nc]将使值nc递增。如果未初始化数组,则代码第一次尝试递增数组元素时,它将试图递增 indeterminate 值。这种尝试将导致不确定的行为。

此外,表示在输入中找不到的字长计数的数组索引应保持零值,但如果不进行零初始化,则这些值将不确定。即使尝试打印这些不确定的值也会导致未定义的行为。

道德:将变量初始化为明智的值,或在尝试使用它们之前将其存储在其中。

使用数组初始值设定项对wl[]数组进行零初始化似乎更加简单明了:

int wl[MAXWORD] = { 0 };

此后,无需执行将另一个文件的数组值设置为零(除非再次使用该数组)的循环。但是,发布的代码来自Tondo和Gimpel的 The C Answer Book 。本书以K&R的形式提供了第二版K&R中的练习的解决方案,并且仅使用每次练习之前书中介绍的思想。此练习1.13在“第1章-教程简介”中进行。这是该语言的简短介绍,缺少许多细节,稍后将在书中找到。至此,已经引入了赋值和数组,但是还没有引入数组初始化器(必须等到第4章),并且到目前为止,使用数组的K&R代码已经使用循环对数组进行了初始化。请不要从已有30多年历史的书籍的介绍性章节中过多地了解代码风格。

自K&R发布以来,C语言发生了许多变化,例如main()不再是main()函数的有效函数签名。请注意,函数签名必须是int main(void)int main(int argc, char *argv[])(或int main(int argc, char **argv))之一,并警告main()的实现定义的签名。

答案 1 :(得分:1)

所有设置为0,因为如果不初始化数组,则将使用随机数初始化数组。随机数将导致程序错误。除了可以循环遍历数组的每个位置之外,您还可以在int wl[MAXWORD] = {0};处执行int wl[MAXWORD];,这将在数组的每个位置放置0,因此您不必进行循环。

答案 2 :(得分:-1)

我编辑了您的代码并在处理过程中添加了一些注释,以解释发生了什么。我还更改了您的某些直方图计算方式,因为它们对我而言似乎没有意义。

底线:它使用原始的“状态机”来计数不是空格的每组字符中的字母。它将其存储在wl[]中,以便wl[i]包含一个整数,该整数告诉您有多少组字符(有时称为“令牌”)的字长为i。因为这是通过递增w[]的适当元素来完成的,所以必须将每个元素初始化为零。不这样做将导致不确定的行为,但可能会导致w[]的每个元素中的计数变得荒谬而荒谬。

此外,任何长度无法反映在w[]中的令牌都将被记入ovflow变量中,因此最后 将会 是每个令牌的记帐。

#include <stdio.h>

#define MAXHIST 15  
#define MAXWORD 11  
#define IN 1        
#define OUT 0      


int main(void) {
  int c, i, nc, state;
  int len;
  int maxvalue;
  int ovflow;
  int wl[MAXWORD];

  // Initializations
  state = OUT;  //Start off not assuming we're IN a word
  nc = 0;       //Start off with a character count of 0 for current word
  ovflow = 0;   //Start off not assuming any words > MAXWORD length

  // Start off with our counters of words at each length at zero
  for (i = 0; i < MAXWORD; i++) {
    wl[i] = 0;  
  }

  // Main loop to count characters in each 'word'
  // state keeps track of whether we are IN a word or OUTside of one
  // For each character in the input stream...
  //   - If it's whitespace, set our state to being OUTside of a word
  //     and, if we have a character count in nc (meaning we've just left
  //     a word), increment the counter in the wl (word length) array.
  //     For example, if we've just counted five characters, increment
  //     wl[5], to reflect that we now know there is one more word with 
  //     a length of five.  If we've exceeded the maximum word length,
  //     then increment our overflow counter.  Either way, since we're
  //     currently looking at a whitespace character, reset the character
  //     counter so that we can start counting characters with our next
  //     word. 
  //   - If we encounter something other than whitespace, and we were 
  //     until now OUTside of a word, change our state to being IN a word
  //     and start the character counter off at 1.
  //   - If we encounter something other than whitespace, and we are
  //     still in a word (not OUTside of a word), then just increment
  //     the character counter.
  while ((c = getchar()) != EOF) {
    if (c == ' ' || c == '\n' || c == '\t') {
      state = OUT;            
      if (nc > 0) {
        if (nc < MAXWORD) ++wl[nc];
        else ++ovflow;       
      }                       
      nc = 0;                 
    } else if (state == OUT) {
      state = IN;             
      nc = 1;                 
    } else {
      ++nc;
    }
  }

  // Find out which length has the most number of words in it by looping
  // through the word length array. 
  maxvalue = 0;
  for (i = 1; i < MAXWORD; ++i) {
    if(wl[i] > maxvalue) maxvalue = wl[i];       
  }

  // Print out our histogram
  for (i = 1; i < MAXWORD; ++i) {
    // Print the word length - then the number of words with that length
    printf("%5d - %5d : ", i, wl[i]);

    if (wl[i] > 0) {
      len = wl[i] * MAXHIST / maxvalue;
      if (len <= 0) len = 1;
    } else {
      len = 0;
    }

    // This is confusing and unnecessary.  It's integer division, with no
    // negative numbers.  What we want to have happen is that the length
    // of the bar will be 0 if wl[i] is zero; that the bar will have length
    // 1 if the bar is otherwise too small to represent; and that it will be
    // expressed as some fraction of MAXHIST otherwise. 
    //if(wl[i] > 0)
    //    {
    //        if((len = wl[i] * MAXHIST / maxvalue) <= 0)
    //            len = 1;
    //    }
    //    else
    //        len = 0;

    // Multiply MAXHIST (our histogram maximum length) times the relative 
    // fraction, i.e., we're using a histogram bar length of MAXHIST for
    // our statistical mode, and interpolating everything else. 
    len = ((double)wl[i] / maxvalue) * MAXHIST; 

    // Our one special case might be if maxvalue is huge, a word length
    // with just one occurrence might be rounded down to zero.  We can fix
    // that manually instead of using a weird logic structure.
    if ((len == 0) && (wl[i] > 0)) len = 1;

    while (len > 0) {
      putchar('*');
      --len;
    }

    putchar('\n');
  }

  // If any words exceeded the maximum word length, say how many there were.
  if (ovflow > 0) printf("There are %d words >= %d\n", ovflow, MAXWORD);

  return 0;
}