2013-10-03 18 views
0

在以下代碼中,char陣列在位置1和位置2處最多打印100個字符,但在位置3處僅打印22.此行爲的原因是什麼?char陣列本身(K&R1-16&1-17)

#include<stdio.h> 
/* print the longest input line */ 
/*Exercise 1-16. Revise the main routine of the longest-line program so it will correctly print the length of arbitrary long input lines, and as much as possible of the text.*/ 

#define MAXLENGTH 100 

int mygetline(char s[], int limit); 
void charcopy(char to[], char from[]); 

int main(){ 
    char current[MAXLENGTH]; 
    char longest[MAXLENGTH]; 
    int curlen; 
    int maxlen; 

    maxlen = 0; 
    while((curlen = mygetline(current, MAXLENGTH)) > 0){ 
    if (curlen > 80) 
     printf("\nvery long:%d; %s\n", curlen, current);//#1# prints 100 digits 
    if(curlen>maxlen){ 
     maxlen=curlen; 
     charcopy(longest, current); 
     printf("\nlonger:%d; %s\n", maxlen, longest);//#2# prints 100 digits 
    } 
    } 
    if (maxlen)//char array seems to truncates itself at scope boundry. 
    printf("\nlongest:%d; %s\n", maxlen, longest);//#3# prints 22 digits 
    printf("\nall done!\n"); 
    return 0; 
} 

int mygetline(char s[], int limit){ 
    int i, c; 
    for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i) 
    s[i]=c; 
    if(c=='\n'){ 
    s[i]=c; 
    ++i;} 
    else 
    if(i >= limit-1) 
     while (((c=getchar()) != EOF) && c != '\n') 
    ++i; 
    s[i]='\0'; 
    return i-1; 
} 


void charcopy(char to[], char from[]){ 
    int i; 
    i=0; 
    while((to[i] = from[i]) != '\0'){ 
    ++i;} 
} 

它的位置標記爲3註釋中只打印22個字符而不是100個。它非常奇怪。

編輯: 作爲每斯科茨答案,我已經改變mygetline這樣:

int mygetline(char s[], int limit){ 
    int i, c, k; 
    for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i) 
    s[i]=c; 
    if((c=='\n') && (i < limit -1)){ 
    s[i]=c; 
    ++i;} 
    else{//if we are over the limit, just store the num of char entered without storing chars 
    k = 0; 
    while (((c=getchar()) != EOF) && c != '\n') 
     ++k;} 
    s[i]='\0'; 
    return i+k; 
} 

如可以看到的,如果輸入過沖限制,然後NUM輸入的字符被存儲在完全新的變量,K這不接觸陣列。我仍然截斷了最後一行打印的行,並且我得到奇怪的32770作爲行長度。爲什麼?可以看出,陣列正在被嬰兒坐着,蹣跚學步,並且只餵食精確量的焦炭而不再飲食。

編輯:第一個列表的問題是,正如斯科特所指出的那樣,我是超數組。第二個mygetline的問題是k=0;在if嵌套中初始化。向上移動初始化並使其成爲全局函數,似乎解決了第二個問題。

工作mygetline如下:

int mygetline(char s[], int limit){ 
    int i, c, k; 
    k=0; 
    for(i=0; i < limit-1 && ((c=getchar()) != EOF) && c != '\n'; ++i) 
    s[i]=c; 
    if((c=='\n') && (i < limit -1)){ 
    s[i]=c; 
    ++i;} 
    else{//if we are over the limit, just add the num of char entered without storing chars 
    while (((c=getchar()) != EOF) && c != '\n') 
     ++k;} 
    s[i]='\0'; 
    return i+k; 
} 
+3

認識到,除非我們知道'mygetline'和'charcopy'做了什麼,否則我們不能回答這個問題,第三行打印maxlen = 100或者maxlen = 22? –

+0

試圖這樣做。我可以看到...... – aamermoquim

+2

你的問題出現在mygetline中,你是否看到了一種可以寫在數組邊界之外的方式?這會破壞你的數據(你可以相當安全地打賭它不在代碼中)原本是K&R的...... :-)事實上,直接導致問題的線路是他們的,但你改變了它的表現他們有。) –

回答

1

好了,你需要知道的關於C的一點是,它不照看你的。如果你有一個聲明爲char foo[4]的數組並且嘗試寫入foo[20],那麼C根本不會抱怨。 (如果寫入受限內存(如NULL),它通常會引發分段違規,但如果您有權訪問內存,則可以執行任何您想要的操作。)

因此,當您寫入一個數組,比你應該做的更多?官方的答案是「未定義的行爲」 - 一個完全通用的全面答案,並說:「這取決於編譯器。」但是,在大多數C編譯器中,它會執行一些所謂的破壞堆棧的操作。

您在任何函數(包括main)中要求的內存都分配在一個很好的單個連貫塊中。所以在你的主函數中,對於current,你有100字節,longest有100字節,curlen有4字節,maxlen有4字節(假設是32位整數,寫到current[123],C會讓你這樣做 - 它會把你寫的任何東西寫在longest[23]的地方。 (通常,再次,這是技術上未定義的行爲,所以不保證這會發生。)

您的問題是mygetline中的行,您設置s[i] = '\0';。問題是,你讓i比數組大。如果您在該行之前printf("i = %d\n", i);,則會看到i = 123.您的最後一行不如最大行更大,因此您將覆蓋longest中您不想覆蓋的數據。

有很多方法可以解決這個問題。也就是說,確保當你設置'\ 0'時,確保i <= limit - 1。 (您可以通過將s[i] = '\0'行移動到while !EOF行以上並將其設置爲s[limit - 1]來做到這一點,以確保您不會超過,還需要在if語句中添加{}。通常,這是一個很好的政策將它們添加到任何if或while語句中,它們佔據一條線,但要確保您在正確的位置編碼。)請記住,該指令是「獲得最大長度,而不是最大字符串。」

如果你實際上在前兩行看到100個字符,我會感到驚訝。看到122.