[英]Why is this array being initialized in an odd way?
我正在阅读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分钟给我的压力,我不知道为什么。
数组wl[]
第i
个元素是在输入文件中找到的长度为i
的单词数。 必须先将wl[]
数组初始化为零,以便++wl[nc];
不会通过尝试使用未初始化的变量而导致未定义的行为,因此表示不存在的字长的数组元素反映未找到此类字长。
注意, ++wl[nc]
递增值wl[nc]
长度的字时nc
遇到。 如果未初始化数组,则代码首次尝试递增数组元素时,它将尝试递增不确定值。 此尝试将导致未定义的行为。
此外,表示在输入中找不到的字长计数的数组索引应保持零值,但如果不进行零初始化,则这些值将不确定。 即使尝试打印这些不确定的值也会导致未定义的行为。
道德观念:在尝试使用变量之前,将变量初始化为明智的值,或将值存储在其中。
使用数组初始值设定项对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()
签名。
一切都设置为0,因为如果不初始化数组,则将使用随机数初始化数组。 随机数将导致程序错误。 不必循环遍历数组的每个位置,您可以执行以下操作: int wl[MAXWORD] = {0};
在int wl[MAXWORD];
这会将0放置在数组中的每个位置,因此您不必执行循环。
我编辑了您的代码并在处理过程中添加了一些注释,以解释发生了什么。 我还更改了您的某些直方图计算,因为它们对我而言似乎没有意义。
底线:它使用原始的“状态机”来计算不是空格的每组字符中的字母。 它将其存储在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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.