我在想程式的問題是什麼。 鍵入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("
");