天天看點

c語言怎麼輸入一個字元串跳出循環,關于字元串:鍵入Quit退出C程式

我在想程式的問題是什麼。 鍵入quit時無法退出程式。

這是我所擁有的:

#include

#include

int main(void) {

char string[200];

printf("Enter a bunch of words:");

do

{

scanf("%[^

]c", string);

}while(strcmp(string,"quit")!=0);

return 0;

}

scanf(" %199[^

]", string);注意%和199之前的空格,以防止寫入string的字元過多。不需要尾随c

您是否對使用scanf進行的鍛煉有規範要求?如果不是,則ID建議其他方法。

@GovindParmar是的,我必須使用scanf,我們不能使用我們尚未學習的任何東西。

@UnholySheep不,它不是。它是一種字元串的掃描格式,該字元串包含除換行符之外的任何字元,後跟文字c。

為什麼使用scanf("%[^

]c", string);而不是fgets (string, sizeof string, stdin)? (然後是strncmp (string,"quit", 4);)

@ DavidC.Rankin這是學校作業的一部分,我不能使用任何尚未教過的東西,是以我必須使用scanf

那scanf(" %[^

]%*c", string);呢? (*是配置設定抑制運算符,允許在不影響傳回的轉換計數的情況下讀取和忽略下一個字元(例如%c)。(應檢查if (scanf(" %[^

]%*c", string) != 1) { * handle error * })

嗨@anon您應該解釋您認為"%[^

]c"的含義。

@AnttiHaapala:并不是真的。 %[^

]将留在輸入流中。是以,下一個字元不能為文字c。

@ DavidC.Rankin hmmm,非常感謝您提供此修複程式,非常感謝,但是我仍然沒有被教過這種技術,是以我必須以一種更簡單的方式來做。有沒有辦法做while(1)然後在循環内做if(strcmp(string," quit")!= 0)break;香港專業教育學院嘗試了這麼多的排列,我不知道如何使它工作。

@jxh當然不可能比對整個格式,但這就是什麼意思。

@jxh它在單詞之間留有空格。我想,如果我沒有它,它将停在第一個空間。

@anon:但是,您想用尾随的c完成什麼?

您的兩個最大問題是使用scanf困擾新C程式員的兩個最常見問題:

You are using an incorrect format string; and

You fail to check the return of scanf.

讓我們首先解決第一件事:

scanf("%[^

]c", string);

您的格式字元串"%[^

]c"使用字元類格式說明符"%[...]"來讀取string的文本。然後是"c" -僅與輸入字元串末尾的文字'c'相比對。那樣寫不會發生,因為"%[^

]"将讀取不是'

'的所有字元,僅保留'

'才能讀取-與'c'不比對。

此外,"%[...]"說明符與"%c"說明符一起不占用前導空格('

'為空格)。是以,在stdin中保留未讀取的'

'時,您對下一個scanf的調用将失敗,因為"%[^

]"不會讀取'

'并且它與'c'不比對,進而導緻比對失敗,即'

'在stdin中仍然未被讀取,事情很快就失控了。

要解決所有問題,您需要記住上面的(2.)并使用字段寬度修飾符來保護string的數組邊界,然後您應讀取并儲存提取并放入string的字元後的字元以驗證是否已讀取完整的輸入行-否則,您有責任在嘗試下一次讀取之前删除stdin中剩餘的所有多餘字元。

對于初學者,您可以使用格式适當受限的字元串,該字元串開頭應包含space,這将導緻scanf放棄所有前導空格,例如

" %199[^

]%c"

請注意,上面的最終字元将被儲存,将進行兩次轉換,是以您将需要一個字元變量來處理最終轉換說明符的結果,例如

do {

char c;    

int retn;  

fputs ("Enter a bunch of words ('quit' exits):", stdout);

retn = scanf (" %199[^

]%c", string, &c);

(注意:提示已在do {...} while (..);循環内移動)

接下來,您将負責每次檢查scanf的傳回。您必須處理三個條件

(return == EOF)使用者通過按Ctrl + d(或在Windows Ctrl + z上)生成手冊EOF來取消輸入;

(return < expected No. of conversions),必須處理比對或輸入失敗,并且必須考慮輸入緩沖區中可能剩餘的每個字元。 (通常,您将在輸入緩沖區中向前掃描,直到找到'

'或EOF并丢棄其餘的多餘字元,請參見示例中的empty_stdin()函數);和

(return == expected No. of conversions)表示讀取成功-然後由您檢查輸入是否滿足任何其他條件(例如正整數,正浮點等)。

綜上所述,您可以使用scanf循環閱讀并尋找"quit"作為提示退出的關鍵字,如下所示:

do {

char c;    

int retn;  

fputs ("Enter a bunch of words ('quit' exits):", stdout);

retn = scanf (" %199[^

]%c", string, &c);

if (retn == EOF) {      

fputs ("(user canceled input)

", stderr);

return 0;

}

else if (retn < 2) {    

fputs ("input failure.

", stderr);

empty_stdin();

}

else if (c != '

') {  

fprintf (stderr,"warning: input exceeds %d characters.

",

MAXC - 1);

empty_stdin();

}

else    

printf ("string: %s

", string);

} while (strcmp (string,"quit") != 0);

最後,請勿在代碼中使用幻數(200是幻數)。相反,如果您需要一個常數,則#define一個(或多個)。您必須對數字進行寫死的唯一地方是例如scanf field-width修飾符-不能使用變量,宏或命名常量。這是該規則的一個例外。同樣,請勿對檔案名或路徑進行寫死。所有函數都帶有參數,甚至main()都将所需的資訊傳遞給程式。

綜上所述,您可以執行以下操作:

#include

#include

#define MAXC 200    

void empty_stdin (void)

{

int c = getchar();

while (c != EOF && c != '

')

c = getchar();

}

int main (void) {

char string[MAXC];    

do {

char c;    

int retn;  

fputs ("Enter a bunch of words ('quit' exits):", stdout);

retn = scanf (" %199[^

]%c", string, &c);

if (retn == EOF) {      

fputs ("(user canceled input)

", stderr);

return 0;

}

else if (retn < 2) {    

fputs ("input failure.

", stderr);

empty_stdin();

}

else if (c != '

') {  

fprintf (stderr,"warning: input exceeds %d characters.

",

MAXC - 1);

empty_stdin();

}

else    

printf ("string: %s

", string);

} while (strcmp (string,"quit") != 0);

return 0;

}

使用/輸出示例

$ ./bin/scanf_string_quit

Enter a bunch of words ('quit' exits): Hello

string: Hello

Enter a bunch of words ('quit' exits): My dog has fleas and my cat has none.

string: My dog has fleas and my cat has none.

Enter a bunch of words ('quit' exits): quit

string: quit

使用Ctrl + d(或在windoze上為Ctrl + z)生成手冊EOF:

$ ./bin/scanf_string_quit

Enter a bunch of words ('quit' exits): Hello

string: Hello

Enter a bunch of words ('quit' exits): (user canceled input)

将MAXC重置為20并将字段寬度修飾符重置為scanf到19,您可以檢查對太長的行的處理,例如第一個輸入合适,第二個輸入太長:

$ ./bin/scanf_string_quit

Enter a bunch of words ('quit' exits): my dog has fleas and my cat has none.

warning: input exceeds 19 characters.

Enter a bunch of words ('quit' exits): 1234567890123456789

string: 1234567890123456789

Enter a bunch of words ('quit' exits): 12345678901234567890

warning: input exceeds 19 characters.

Enter a bunch of words ('quit' exits): quit

string: quit

仔細檢查一下,如果您還有其他問題,請告訴我。

哇!非常感謝,我非常感謝所有細節。 Ive遵循了您和另一個使用者的建議,一旦我鍵入quit,程式就會退出。但是,這導緻了一個新問題,因為我沒有描述程式的目的,是以你們回答了您認為程式想要的内容,我将釋出一個新問題,更全面地解釋我擁有程式後想要做什麼放棄。

這樣的事情可以接受嗎?

#include

#include

int main(void) {

char string[200] = {0};

printf("Enter a bunch of words:");

do {

memset(string, 0, 200);

scanf("%s", string);

} while (strcmp(string,"quit") != 0);

return 0;

}

您尚未确切說明要對字元串進行的處理,是以很難給出答案。但是,要注意的一件事是,您必須對string做一些事情(我剛剛在這裡将其歸零),以便strcmp識别"退出",或者掃描string的子字元串,因為如果所有内容都會附加在後面,然後您的字元串将是"(...)quit",而strcmp不會将其識别為" quit"。

附帶說明一下,請始終初始化數組,否則可能會發生不良情況。

我不能使用memset,我還沒在課堂上學到:/。但是,我按照您的建議初始化了數組,并且無需memset即可工作。非常感謝!

@anon您也可以使用for循環将string中的每個索引設定為0,但是任務可能不僅僅需要這樣做。很高興這是有用的。

@Joshua我一直都喜歡Integer Overflow Man,他是我最喜歡的超級英雄。确實存在這種危險,但是匿名人士并沒有真正指定他所完成任務的界限,是以我隻是想提出最簡單的建議,以解決他似乎遇到的問題。記憶體安全似乎并不是其中的一部分。

鑒于您提供的稀疏解釋,最直接的更改可能是修改掃描字元串以吞下而不是理論上的c,這實際上是不可能的:

scanf("%[^

]

", string);

為了防止緩沖區溢出,您應該指定緩沖區必須存儲多少空間:

scanf("%199[^

]

", string);

隻要您知道輸入内容永遠不會超過199個字元,這是安全的。但這在理論和實踐上都是一個很弱的假設。超過199的字元将在下一次疊代中作為下一個單詞被掃描,如果輸入的是199 .後跟單詞quit,則程式将意外退出。您需要一種更可靠的方法來掃描到該行的其餘部分并丢棄它,然後再讀取下一行。

您可能會想使用另一個%[...]來捕獲額外的字元,如下所示:

scanf("%199[^

]%*[^

]

", string);

但是,對于輸入少于或等于199個字元的常見情況,這将失敗。這是因為如果轉換導緻輸入為空,則scanf将失敗。是以,将保留在輸入中。

如果限于使用scanf,則需要将掃描分為多個單獨的scanf調用,以便将其餘行的錯誤和非錯誤掃描視為相同的結果,進而導緻第二個scanf吞下換行符本身。

scanf("%199[^

]%*[^

]", string);

scanf("

");