简体   繁体   English

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

[英]Why is this array being initialized in an odd way?

I am reading K&R 2nd Edition and I am having trouble understanding exercise 1-13. 我正在阅读K&R第二版,但在理解练习1-13时遇到困难。 The answer is this code 答案是这样的代码

#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;

}

At the top, wl is being declared and initialized. 在顶部, wl被声明和初始化。 What I don't understand is why is it looping through it and setting everything to zero if it just counts the length of words? 我不明白的是,如果它只计算单词的长度,为什么要遍历它并将所有内容都设置为零? It doesn't keep track of how many words there are, it just keeps track of the word length so why is everything set to 0? 它不会跟踪有多少个单词,而只会跟踪单词的长度,因此为什么将所有内容都设置为0?

I know this is unclear it's just been stressing me out for the past 20 minutes and I don't know why. 我知道目前还不清楚,这只是过去20分钟给我的压力,我不知道为什么。

The i th element of the array wl[] is the number of words of length i that have been found in an input file. 数组wl[]i个元素是在输入文件中找到的长度为i的单词数。 The wl[] array needs to be zero-initialized first so that ++wl[nc]; 必须先将wl[]数组初始化为零,以便++wl[nc]; does not cause undefined behavior by attempting to use an uninitialized variable, and so that array elements that represent word lengths that are not present reflect that no such word lengths were found. 不会通过尝试使用未初始化的变量而导致未定义的行为,因此表示不存在的字长的数组元素反映未找到此类字长。

Note that ++wl[nc] increments the value wl[nc] when a word of length nc is encountered. 注意, ++wl[nc]递增值wl[nc]长度的字时nc遇到。 If the array were not initialized, the first time the code attempts to increment an array element, it would be attempting to increment an indeterminate value. 如果未初始化数组,则代码首次尝试递增数组元素时,它将尝试递增不确定值。 This attempt would cause undefined behavior. 此尝试将导致未定义的行为。

Further, array indices that represent counts of word lengths that are not found in the input should hold values of zero, but without the zero-initialization, these values would be indeterminate. 此外,表示在输入中找不到的字长计数的数组索引应保持零值,但如果不进行零初始化,则这些值将不确定。 Even attempting to print these indeterminate values would cause undefined behavior. 即使尝试打印这些不确定的值也会导致未定义的行为。

The moral: initialize variables to sensible values, or store values in them, before attempting to use them. 道德观念:在尝试使用变量之前,将变量初始化为明智的值,或将值存储在其中。

It would seem simpler and be more clear to use an array initializer to zero-initialize the wl[] array: 使用数组初始值设定项对wl[]数组进行零初始化似乎更加简单明了:

int wl[MAXWORD] = { 0 };

After this, there is no need for the loop that sets the array values to zero (unless the array is used again) for another file. 此后,就不需要将另一个文件的数组值设置为零(除非再次使用该数组)的循环。 But, the posted code is from The C Answer Book by Tondo and Gimpel. 但是,发布的代码来自Tondo和Gimpel的The C Answer Book This book provides solutions to the exercises found in the second edition of K&R in the style of K&R, and using only ideas that have been introduced in the book before each exercise. 本书以K&R的形式提供了第二版K&R中的练习的解决方案,并且仅使用每次练习之前书中介绍的思想。 This exercise, 1.13, occurs in "Chapter 1 - A Tutorial Introduction". 此练习1.13在“第1章-教程简介”中进行。 This is a brief tour of the language lacking many details to be found later in the book. 这是该语言的简短介绍,缺少许多细节,稍后将在书中找到。 At this point, assignment and arrays have been introduced, but array initializers have not (this has to wait until Chapter 4), and the K&R code that uses arrays has initialized arrays using loops thus far. 至此,已经引入了赋值和数组,但是还没有引入数组初始化器(必须等到第4章),并且到目前为止,使用数组的K&R代码已经使用循环对数组进行了初始化。 Don't read too much into code style from the introductory chapter of a book that is 30+ years old. 从30岁以上的书的入门章节中,不要过多地了解代码风格。

Much has changed in C since K&R was published, eg, main() is no longer a valid function signature for the main() function. 自K&R发布以来,C语言发生了许多变化,例如main()不再是main()函数的有效函数签名。 Note that the function signature must be one of int main(void) or int main(int argc, char *argv[]) (or alternatively int main(int argc, char **argv) ), with a caveat for implementation-defined signatures for main() . 请注意,函数签名必须是int main(void)int main(int argc, char *argv[]) (或int main(int argc, char **argv) )之一,并为实现定义了警告main()签名。

Everything is set to 0 because if you dont initialize the array, the array will be initialize with random number in it. 一切都设置为0,因为如果不初始化数组,则将使用随机数初始化数组。 Random number will cause error in your program. 随机数将导致程序错误。 Instead of looping in every position of your array you could do this int wl[MAXWORD] = {0}; 不必循环遍历数组的每个位置,您可以执行以下操作: int wl[MAXWORD] = {0}; at the place of int wl[MAXWORD]; int wl[MAXWORD]; this will put 0 at every position in your array so you dont hava to do the loop. 这会将0放置在数组中的每个位置,因此您不必执行循环。

I edited your code and put some comments in as I was working through it, to explain what's going on. 我编辑了您的代码并在处理过程中添加了一些注释,以解释发生了什么。 I also changed some of your histogram calculations because they didn't seem to make sense to me. 我还更改了您的某些直方图计算,因为它们对我而言似乎没有意义。

Bottom line: It's using a primitive "state machine" to count up the letters in each group of characters that isn't white space. 底线:它使用原始的“状态机”来计算不是空格的每组字符中的字母。 It stores this in wl[] such that wl[i] contains an integer that tells you how many groups of characters (sometimes called "tokens") has a word length of i . 它将其存储在wl[] ,以便wl[i]包含一个整数,该整数告诉您有多少个字符组(有时称为“令牌”)的字长为i Because this is done by incrementing the appropriate element of w[] , each element must be initialized to zero. 因为这是通过增加w[]的适当元素来完成的,所以必须将每个元素初始化为零。 Failing to do so would lead to undefined behavior, but probably would result in nonsensical and absurdly large counts in each element of w[] . 否则,将导致不确定的行为,但可能会导致w[]每个元素中的计数变得荒谬而荒谬。

Additionally, any token with a length that can't be reflected in w[] will be tallied in the ovflow variable, so at the end there will be an accounting of every token. 另外,任何长度不能在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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM