[英]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.