2013-07-16 51 views
0

全部,調整,報如何在C中分析輸入?

末碼如果我要問用戶進行輸入和搶用,比如說,scanf函數的它(),請問如何處理工作(具體關於緩衝液等)?

什麼意思是當人們引用'沖洗'的緩衝區?我也聽說,刷新輸入(或者,而不是定義?)是不好的做法,但刷新輸出流是fflush()創建的功能。 - 在上文中,'stream'的含義是什麼?

因此,在程序上,如果我要問像輸入:

printf("Enter a string: "); 
    scanf("%s", string); 

發生了什麼輸入;字符串在哪裏被scanf函數'抓住'?

輸入緩衝區中出現「空白」是什麼? (空格字符,NULL,等等?)


在我的腦海裏,雖然文學我讀從來沒有專門針對這些問題,我想象中的來自用戶的輸入,或者從文件,存儲在一些臨時字符數組中被訪問,並使用適當的指針進行打印/存儲。

我之所以提這件事是因爲我有一個相關的問題,下面的代碼:

int main(){ 
    char string[20]; 
    char string2[20]; 

//strlen test 
    printf("Enter a string: "); 
     scanf("%s", string); 
    printf("\t length: %d\n", strlen(string)); 

//strcat test 
    printf("Enter two strings to concatentate: "); 
     scanf("%s %s", string, string2); 
    strcat(string2, string); 
    printf("\nConcatenated: %s\n\n\n", string); 

return 0; 

}

順便說一句:)strlen的(和strcat的()以上功能均在本地定義,因此參數可能與您從C庫中熟悉的參數不匹配。

產生以下輸出:

img

我假定,一旦scanf函數遇到空白它假定字符串的末尾。儘管如此,剩餘的輸入仍然存在於緩衝區中。然後,當我要求更多的輸入時,輸入的數據被放置在緩衝區的末尾。因此,這次scanf()被調用時,'andothernonsensehere'被作爲下一個輸入,因爲它在緩衝區中較早存在。

雖然,如果我上面說的是真的,不應該第二個'andothernonsensehere'字符串和在第二個調用'sherrell'輸入的第一個字符串連接在一起嗎?


TL;博士verison 如何刷新緩衝區,以確保輸入的下一個事件將被scanf函數被捕獲()?


完整,編輯,代碼:

#include <stdio.h> 

int main(){ 
    char string[20]; 
    char string2[20]; 

//strlen test 
    printf("Enter a string: "); 
     scanf("%s", string); 
    printf("\t length: %d\n", strlen(string)); 
    clear(); //make sure buffer is empty 

//strcat test 
    printf("Enter two strings to concatentate: "); 
     scanf("%s %s", string, string2); 

    strcat(string2, string); 
    printf("\nConcatenated: %s\n\n\n", string); 

    return 0; 
} 

void strcat(char *toCopy, char *org){ 
    while(*org != NULL) org++; //find end of characters 
    while((*org++ = *toCopy++) != NULL); //copy 
} 

int strlen(char *a){ 
    char *b = a; 
    while(*b++ != NULL); 
    return b-a; 
} 


void clear(){ 
    while(getchar() != '\n'); 
} 

回答

1

你基本上已經明白了,雖然緩衝可能不是你認爲的地方。

scanf不保存緩衝區。從概念上講,它每次只讀取一個字符,直到格式或輸入被耗盡。

但是,終端輸入通常由終端驅動程序緩衝。或者,爲了更加準確,如果沒有等待讀取的字符,則即使程序僅讀取一個字符,直到按下鍵輸入,終端輸入的請求也不會返回任何內容。未讀字符保留在內核中,在那裏它們將按照請求提供給用戶程序。 (終端驅動程序還可以處理在輸入字符時回顯字符,處理退格和其他許多事情)。但是,所有這些行爲都可以改變。有關詳細信息,請參閱man sttyman termios(可能還有man tty_ioctl)。許多。因此scanf完全不知道會發生什麼。它只會消耗字符,直到滿足爲止,並在必要時調用ungetc以返回它讀取的最後一個字符,但不需要。

現在,你的問題:

不應該第二個「andothernonsensehere」字符串,並在第二個呼叫進入第一個字符串,「sherrell,」級聯?

答:是的,他們應該。他們將與標準庫函數strcat,只要你把它的參數以正確的順序,並確保string有足夠的空間來保存拼接加上終止NUL字符。如你所說,我不能對你的strcat做任何假設,所以我不知道它的參數與標準庫版本的順序相同。但是,如果確實如此,那麼您看到的行爲是預期的:strcat將追加stringstring2(覆蓋隨機內存,因爲string2不足以容納級聯)的結尾,但不會更改string(除非string是被覆蓋的隨機存儲器)。因此,當您打印出string時,您會看到它原來的內容,即20個字符的字符串,其末尾的NUL字節也會覆蓋其他隨機存儲位置。

由於所有這些未定義的行爲正在進行,您的程序可能產生幾乎任何輸出,或者它可能已經分段或觸發nasal demons。我認爲你的C編譯器可能會在雙字邊界上對齊字符串,因爲我預計string2會立即跟隨string,因此在將20個字符放入string後尾隨NUL將成爲string2的第一個字節,當scanf填入string2時被覆蓋。在這一點上追加stringstring2的後果將是,嗯,有趣。

+0

謝謝,這個概念現在更有意義了,我在OP的最後加上了完整的代碼,包括我的strcat版本()。任何建議? – sherrellbc

+1

@sherrellbc:我的建議:使用'-Wall'(至少),並使'string'和'string2'變大(或使用更短的輸入)。 (NULL是一個指針);把strlen,strcat並在開始時清楚,並更改名稱以避免與gcc內建相撞;並將這兩個緩衝區更改爲40個字符。它運行良好。 (gcc仍然正確地提醒忽略scanf的返回值,你應該總是檢查scanf的返回值。) – rici

+0

功能配置是一個值得關注的問題嗎? (即在主之前/之後)。我總是以這樣一種方式進行編程,使得我包含了習慣中的函數原型(儘管不在這裏)。我知道,如果你有一個函數調用另一個函數,它定義在它自己下面,那麼調用函數將不會「看到」定義的函數,程序將不會編譯。我驚訝地發現,我編寫的代碼是由於缺少函數原型以及main調用定義後定義的函數而編譯的。 – sherrellbc

0
String2 

是未聲明的,其輸入是 「」 空字符串。因此,您輸入第一個並與空字符串連接產生與原始輸入相同的字符串 %s是「輸入」,其中s代表字符串,並將其存儲在字符串內。哪裏是你從哪裏獲得輸入。

+0

我沒有發佈整個代碼。這是上面列出的問題很明顯的一個例子。 – sherrellbc

+0

這個答案根本與我的問題無關。我知道scanf()函數是如何工作的。 – sherrellbc

+0

scanf(「%s%s」,string,string2); 這條線是它給你的問題 – Shang