天天看點

K&R《C程式設計語言》p23:列印最長的輸入行

零、代碼

#include <stdio.h>
#define MAXLINE 1000    // 輸入行的最大長度 

int max;                // 儲存目前為止最長行的長度

char line[MAXLINE];        // 儲存目前的輸入行  
char longest[MAXLINE];    // 儲存最長的行 

int get_line(void);        
void copy_longest_line(void);        


int main()
{
    int cur_len;        // 目前行的長度
    extern int max;
    extern char longest[];
    
    max = 0;
    while ((cur_len = get_line()) > 0)
    {
        printf("The current line's length is : %d\n", cur_len);
        if (cur_len > max)
        {
            // 如果目前行的長度大于上次儲存的最大長度,則最大長度要更新為目前長度
            // 并且要把目前行的内容放到longest數組中,此時longest數組原先的内容會被覆寫掉
            max = cur_len;
            copy_longest_line();
        }
    }
    
    if(max > 0)
    {
        printf("\nThe max length of the input lines is : %d\n", max);
        printf("The longest line is : %s\n", longest);
    }
    
    return 0;
}


// 将目前輸入行的内容儲存到line數組中
int get_line(void)
{
    int c=0, i=0;
    extern char line[];
    
    /**
     * 繼續循環需要三個條件:
     * (1) i小于999,因為數組的最大長度為1000(即0~999),line[999]要放換行符'\n',是以輸入字元隻能放在line[0]~line[998]
     * (2) 輸入的字元不為檔案結束符,Windows的檔案結束符為ctrl+z,mac/linux/unix的檔案結束符為ctrl+d
     * (3) 輸入的字元不為換行符'\n',因為一旦換符,那就是新的一行了
     */
    for (; i < MAXLINE-1 && (c= getchar()) != EOF && c != '\n'; ++i)
    {
        line[i] = c;
    }
    
    if (c == '\n')
    {
        line[i] = c;
        ++i;
    }
    
    // 換行符的下一個字元是行結束符'\0','\0'不算在行長度内
    line[i] = '\0';
    
    return i;
}


void copy_longest_line(void)
{
    int i = 0;
    extern char line[], longest[]; 
    
    // 先把line[i]指派給longest[i],再判斷longest[i]是不是行結束符'\0'
    while ((longest[i] = line [i]) != '\0')
    {
        ++i;
    }
}      

一、運作結果

輸入

a

abc

ab

ctrl + z

K&amp;R《C程式設計語言》p23:列印最長的輸入行

二、分析

1 定義數組char c[10],可存放十個字元,從c[0]~c[9]。注意計算機是從0開始計數而不是從1開始計數,是以最後一個元素是c[9]而不是c[10]。

2 字元與數字是一一對應的。具體而言,就是每個字元都對應着一個ascii編碼。

比如:

a對應97,b對應98,其它小寫字母以此類推;

A對應65,B對應66,其它大寫字母以此類推;

字元‘1’對應49,字元‘2’對應50,其它數字以此類推;

回車符‘\r’對應13,換行符‘\n’對應10;

行結束符‘\0’對應0。​

是以,整型數組既可以用來存放整型元素,也可以用來存放字元元素;

同理,字元數組既可以用來存放字元元素,也可以用來存放整型元素。

3 在C語言中,字元數組是以’\0’作為行結束符的,并且行結束符不算在字元數組的長度内。

例子:輸入abc并換行,這在長度為10的字元數組c[10]中是這麼放的

a b c \n \0

這裡c[0] = ‘a’, c[1] = ‘b’, c[2] = ‘c’, c[3]= ‘\n’, c[4] = ‘\0’, c[5]~c[9]都為空。

其長度為4,行結束符’\0’不算在長度内。

4 get_line函數中有個句子

for (; i < MAXLINE-1 && (c=getchar()) != EOF && c != '\n'; ++i)

等價于

for (i = 0; i < MAXLINE-1 && (c=getchar()) != EOF && c != '\n'; ++i)

因為i = 0;上面已經出現過,是以這裡不寫也可以。

5 本程式的執行過程

(0)最開始max=0;

(1)第一次輸入a并且換行,get_line()函數的執行順序為

i = 0時; 輸入‘a’,循環的三個條件都滿足,先執行line[0] = ‘a’;

再執行i++,i的值變為1

i = 1時; 輸入換行符’\n‘ ,循環條件有一個不滿足,結束循環

繼續執行if(c == ‘\n’),這個條件是成立的,是以line[1] = ‘\n’,i++,i的值變為2

繼續執行line[2] = ‘\0’

繼續執行return 2。傳回的2就是目前行的長度。

此時main()函數中cur_len=2,max=0, cur_max > max成立,執行max = cur_len,即max由原先的0更新為 2。再執行copy_longest_line()函數。

copy_longest_line()函數中,

longest[0] = line[0] = ‘a’

longest[1] = line[1] = ‘\n’

longest[2] = line[2] = ‘\0’循環結束

(2)第二次輸入abc并換行,get_line()函數的執行順序為

while語句中,

i = 0時,line[0] = ‘a’,i++,i的值變為1;

i = 1時,line[1] = ‘b’,i++,i的值變為2;

i = 2時,line[2] = ‘c’,i++,i的值變為3;

i = 3時,line[3] = ‘\n’,循環結束;

if語句中

line[3] = ‘\n’, i++, i的值變為4

line[4] = ‘\0’;

return 4;

main()函數中,

cur_len的值為get_line()的傳回值4,上次得到的max值為2,cur_len>max,max=cur_len=4,即max的值由原先的2更新為4,并執行copy_longest_line()函數。

copy_longest_line()函數中,

longest[0] = line[0] = ‘a’;

longest[1] = line[1] = ‘b’;

longest[2] = line[2] = ‘c’;

longest[3] = line[3] = ‘\n’;

longest[4] = line[4] = ‘\0’;

循環結束。

(3)第3次輸入ab并換行,執行get_line()函數,

line[0] = ‘a’;

line[1] = ‘b’;

line[2] = ‘\n’;

line[3] = ‘\0’;

return 3;

因為cur_len=3, max=4, cur_len>max不成立,是以max仍為上次得到的4不作改變,并且copy_longest_line()函數不被執行。

6 本程式中,全局變量max,line[1000], longest[1000]的定義和使用都在同一個檔案中,并且是先定義後使用,是以實際上所有的extern語句都可以去掉。

但是若全局變量的定義在一個檔案内(比如test1.c),使用在另一個檔案内(比如test2.c),那麼extern語句不能省。

代碼:

#include <stdio.h>
#define MAXLINE 1000    // 輸入行的最大長度 

int max;                // 儲存目前為止最長行的長度

char line[MAXLINE];        // 儲存目前的輸入行  
char longest[MAXLINE];    // 儲存最長的行 

int get_line(void);        
void copy_longest_line(void);        


int main()
{
    int cur_len;        // 目前行的長度

    max = 0;
    while ((cur_len = get_line()) > 0)
    {
        printf("The current line's length is : %d\n", cur_len);
        if (cur_len > max)
        {
            // 如果目前行的長度大于上次儲存的最大長度,則最大長度要更新為目前長度
            // 并且要把目前行的内容放到longest數組中,此時longest數組原先的内容會被覆寫掉
            max = cur_len;
            copy_longest_line();
        }
    }
    
    if(max > 0)
    {
        printf("\nThe max length of the input lines is : %d\n", max);
        printf("The longest line is : %s\n", longest);
    }
    
    return 0;
}


// 将目前輸入行的内容儲存到line數組中
int get_line(void)
{
    int c=0, i=0;
    
    /**
     * 繼續循環需要三個條件:
     * (1) i小于999,因為數組的最大長度為1000(即0~999),line[999]要放換行符'\n',是以輸入字元隻能放在line[0]~line[998]
     * (2) 輸入的字元不為檔案結束符,Windows的檔案結束符為ctrl+z,mac/linux/unix的檔案結束符為ctrl+d
     * (3) 輸入的字元不為換行符'\n',因為一旦換符,那就是新的一行了
     */
    for (; i < MAXLINE-1 && (c= getchar()) != EOF && c != '\n'; ++i)
    {
        line[i] = c;
    }
    
    if (c == '\n')
    {
        line[i] = c;
        ++i;
    }
    
    // 換行符的下一個字元是行結束符'\0','\0'不算在行長度内
    line[i] = '\0';
    
    return i;
}


void copy_longest_line(void)
{
    int i = 0;
    
    // 先把line[i]指派給longest[i],再判斷longest[i]是不是行結束符'\0'
    while ((longest[i] = line [i]) != '\0')
    {
        ++i;
    }
}