[英]fgets() doesn't work as expected in C
給出以下代碼:
#include <stdio.h>
int main()
{
int testcase;
char arr[30];
int f,F,m;
scanf("%d",&testcase);
while(testcase--)
{
printf("Enter the string\n");
fgets(arr,20,stdin);
printf("Enter a character\n");
F=getchar();
while((f=getchar())!=EOF && f!='\n')
;
putchar(F);
printf("\n");
printf("Enter a number\n");
scanf("%d",&m);
}
return 0;
}
我希望用戶輸入一個字符串,一個字符和一個數字,直到測試用例變為零為止。
我的疑問/問題:
1.用戶無法輸入字符串。 似乎fgets
無法正常工作。 為什么?
2.如果我使用scanf
而不是fgets
,則getchar
無法正常工作,即我在其中輸入的任何字符都只是putchar
作為新行。 為什么?
謝謝您的幫助。
混合函數fgets()
, scanf()
和getchar()
容易出錯。 scanf()
函數通常在輸入流中留下一個\\n
字符,而fgets()
通常不這樣做,這意味着對I / O函數的下一個調用可能或可能不需要處理上一個調用留下的內容在輸入流中。
更好的解決方案是對所有用戶輸入使用一種樣式的I / O功能。 與sscanf()
結合使用的fgets()
可以很好地實現此目的。 應該檢查函數的返回值,並且在發生錯誤的情況下fgets()
將返回空指針。 sscanf()
返回成功分配的數量,可用於驗證輸入是否如預期的那樣。
這是發布代碼的修改版本。 fgets()
將輸入存儲在慷慨分配的緩沖區中; 請注意,如果有足夠的空間,此函數最多可以存儲\\n
字符(包括\\n
字符)的輸入。 如果預期輸入字符串不包含空格,則可以使用sscanf()
提取字符串,而無需擔心換行符; 類似地,使用sscanf()
提取字符或數字輸入可減輕代碼對\\n
進一步處理的負擔。
#include <stdio.h>
int main(void)
{
int testcase;
char arr[30];
char F;
int m;
char buffer[1000];
do {
puts("Enter number of test cases:");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
} while (sscanf(buffer, "%d", &testcase) != 1 || testcase < 0);
while(testcase--)
{
puts("Enter the string");
/* if string should not contain spaces... */
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
sscanf(buffer, "%29s", arr);
printf("You entered: %s\n", arr);
putchar('\n');
puts("Enter a character");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
sscanf(buffer, "%c", &F);
printf("You entered: %c\n", F);
putchar('\n');
do {
puts("Enter a number");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
} while (sscanf(buffer, "%d", &m) != 1);
printf("You entered: %d\n", m);
putchar('\n');
}
return 0;
}
另一方面,如果輸入字符串可能包含空格,則fgets()
可以將輸入直接讀取到arr
,但是存儲的字符串將包含\\n
字符,應該將其刪除。 一種方法是使用strcspn()
函數找到\\n
的索引:
#include <string.h> // for strcspn()
/* ... */
puts("Enter the string");
/* or, if string may contain spaces */
if (fgets(arr, sizeof arr, stdin) == NULL) {
/* handle error */
}
/* replace newline */
arr[strcspn(arr, "\r\n")] = '\0';
printf("You entered: %s\n", arr);
putchar('\n');
/* ... */
請注意,在將%s
與scanf()
函數一起使用時,應始終指定最大寬度,以避免緩沖區溢出。 在這里,當讀入arr
時它是%29s
,因為arr
可以容納30個char
,並且必須為空終止符( \\0
)保留空間。 檢查sscanf()
返回值以查看用戶輸入是否無效,在這種情況下,將再次要求輸入。 如果測試用例的數量小於0,則必須再次輸入。
一個簡單的技巧是編寫一個函數來解釋換行符。 在每個scanf之后調用clear()
void clear (void){
int c = 0;
while ((c = getchar()) != '\n' && c != EOF);
}
請參閱此問題以獲取進一步的說明: C:多個scanf,當我為一個scanf輸入一個值時,它將跳過第二個scanf
最終得到了解決方案,我們如何才能安全地同時使用scanf和fgets。
#include <stdio.h>
int main()
{
int testcase,f,F,m;
char arr[30];
scanf("%d",&testcase);
while((f=getchar())!=EOF && f!='\n')
;
while(testcase--)
{
printf("Enter the string\n");
fgets(arr,30,stdin);
printf("Enter a character\n");
F=getchar();
while((f=getchar())!=EOF && f!='\n')
;
putchar(F);
printf("\n");
printf("Enter a number\n");
scanf("%d",&m);
while((f=getchar())!=EOF && f!='\n')
;
}
}
我們需要確保在fgets讀取任何內容之前,請使用簡單的while循環清空緩沖區。
感謝所有人的幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.