混合使用像
fgets()
、
scanf()
和
getchar()
这样的函数容易出错。
scanf()
函数通常在输入流中留下一个
\n
字符,而
fgets()
通常不会这样做,这意味着下一次调用I/O函数可能需要处理先前调用留下的输入流中的内容。
更好的解决方案是对所有用户输入使用一种I/O函数风格。 使用与
sscanf()
结合使用的
fgets()
可以很好地解决此问题。应检查函数的返回值,并且
fgets()
在错误时返回空指针;
sscanf()
返回成功分配的数量,可以用于验证输入是否符合预期。
以下是已发布代码的修改版本。
fgets()
将输入存储在大量分配的缓冲区中;请注意,如果有足够的空间,此函数将输入存储到包括
\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) {
}
} while (sscanf(buffer, "%d", &testcase) != 1 || testcase < 0);
while(testcase--)
{
puts("Enter the string");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
}
sscanf(buffer, "%29s", arr);
printf("You entered: %s\n", arr);
putchar('\n');
puts("Enter a character");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
}
sscanf(buffer, "%c", &F);
printf("You entered: %c\n", F);
putchar('\n');
do {
puts("Enter a number");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
}
} while (sscanf(buffer, "%d", &m) != 1);
printf("You entered: %d\n", m);
putchar('\n');
}
return 0;
}
另一方面,如果输入字符串
可能包含空格,则
fgets()
可以直接将输入读入
arr
中,但是存储的字符串将包含一个
\n
字符,这应该被删除。一种方法是使用
strcspn()
函数找到
\n
的索引:
#include <string.h>
puts("Enter the string");
if (fgets(arr, sizeof arr, stdin) == NULL) {
}
arr[strcspn(arr, "\r\n")] = '\0';
printf("You entered: %s\n", arr);
putchar('\n');
请注意,在使用
scanf()
函数时,应始终指定最大宽度以避免缓冲区溢出。在这里,当读入
arr
时,它是
%29s
,因为
arr
可以容纳30个
char
,并且必须保留空间用于空终止符(
\ 0
)。检查从
sscanf()
返回的值是否无效,如果无效,则再次要求输入。如果测试用例的数量小于0,则必须重新输入。
scanf("%d%*c", &testcase);
-->scanf("%d%*c", &testcase);
跳过数字后的换行符。 - BLUEPIXYstdin
中。因此,您必须消耗掉额外的换行符'\n'
,因为它存在于输入流中。 - WhiteSwordscanf()
和fgets()
混合使用,以避免出现问题;尝试使用fgets()
与sscanf()
结合使用,而不是仅使用scanf()
。 - ad absurdum