我正在尝试编写一个简单的程序,它将读取两个输入行,一个整数,后跟一个字符串。但是,它似乎对我不起作用。
int main()
{
int i;
char str[1024];
scanf("%d", &i);
scanf("%[^\n]", str);
printf("%d\n", i);
printf("%s\n", str);
return 0;
}
输入整数并按“Enter”后,程序立即打印整数。它不等我输入字符串。怎么了?什么是正确的编程方式?
答案 0 :(得分:3)
%[^\n]
的问题在于,当要读取的第一个字符是换行符时,会失败,并将其推回stdin
。
输入第一个scanf
的号码后,按 Enter 。第一个%d
中的scanf
使用该数字,将 Enter keypress生成的换行符('\n'
)留在标准输入流中({{ 1}})。下一个stdin
中的%[^\n]
会看到此scanf
,但由于此答案第一段中给出的原因而失败。
解决方案包括:
将\n
更改为scanf("%d", &i);
。 scanf("%d%*c", &i);
的作用是,它扫描并丢弃一个角色。
我不推荐这种方式,因为邪恶的用户可以通过输入%*c
,例如:scanf
来欺骗<number><a character>\n
,并且您将再次遇到同样的问题。< / p>
在2j\n
之前添加空格(任何空格字符都可以),即将%[^\n]
更改为scanf("%[^\n]", str);
@Bathsheba mentioned in a comment。< / p>
空格字符的作用是,它扫描并丢弃任意数量的空白字符,包括无字符,直到第一个非空白字符。
这意味着在输入第二个scanf(" %[^\n]", str);
时,将跳过任何前导空白字符。
这是我的建议:在scanf
之后清除stdin
。创建一个函数:
scanf
并使用void flushstdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
每次scanf
后调用它。
与您的问题无关的问题包括:
如果flushstdin();
失败,则不处理此案例。这可能是由于各种原因造成的,例如输入格式错误,例如为scanf
输入字母表。
为此,请检查%d
的返回值。它返回成功扫描和分配的项目数,如果遇到scanf
,则返回-1。
您不检查缓冲区溢出。您需要阻止超过1023个字符(NUL终止符为+1)扫描到EOF
。
这可以通过使用str
中的长度说明符来实现。
scanf
或main
声明int main(void)
,而不是int main(int argc, char* argv[])
。int main()
(stdio.h
和printf
)scanf
答案 1 :(得分:0)
这很简单,就可以了:
scanf("%d %[^\n]s", &i, str);
答案 2 :(得分:0)
Instateed scanf()
使用fgets()
后跟sscanf()
。
使用<stdio.h>
中的原型检查几乎所有函数的返回值。
#include <stdio.h>
int main(void) {
int i;
char test[1024]; // I try to avoid identifiers starting with "str"
char tmp[10000]; // input buffer
// first line
if (fgets(tmp, sizeof tmp, stdin)) {
if (sscanf(tmp, "%d", &i) != 1) {
/* conversion error */;
}
} else {
/* input error */;
}
// second line: read directly into test
if (fgets(test, sizeof test, stdin)) {
size_t len = strlen(test);
if (test[len - 1] == '\n') test[--len] = 0; // remove trailing ENTER
// use i and test
printf("i is %d\n", i);
printf("test is \"%s\" (len: %d)\n", test, (int)len);
} else {
/* input error */;
}
return 0;
}