提问人:Pratyush 提问时间:9/2/2023 最后编辑:chqrliePratyush 更新时间:9/2/2023 访问量:48
字符串的 scanf 在执行另一个 scanf 后被跳过
scanf for string gets skipped after taking another scanf
问:
这是一个程序,它从用户那里获取输入,即:roll.no,姓名,他的物理,化学和数学标记并打印它们。
如果用于获取字符串输入,则在此程序中不起作用。%[^\n]s
这个程序工作正常
#include <stdio.h>
#include <string.h>
void main()
{
int roll_no;
char student[1000];
float physics, maths, chemistry;
printf("Enter your roll no. : ");
scanf("%d", &roll_no);
fflush(stdin);
printf("\nEnter your name : ");
fflush(stdin);
scanf("%s", student);
fflush(stdin);
printf("\nEnter your physics : ");
scanf("%f", &physics);
printf("\nEnter your maths : ");
scanf("%f", &maths);
printf("\nEnter your chemistry : ");
scanf("%f", &chemistry);
printf("Student's Name : %s\nPhysics Marks : %.2f Chemistry Marks : %.2f Maths Marks : %.2f",
student, physics, chemistry, maths);
}
为了取学生的全名(名字和姓氏),我后来用代替了scanf("%[^\n]s", student);
scanf("%s", student);
当我用于学生数组时,程序采用卷号。然后,用户的输入会跳过学生。它直接跳到物理来获取物理分数。 还用于防止在采用多种数据类型时出现故障,但似乎仍然不起作用%[^\n]s
scanf
scanf
fflush(stdin)
scanf
答:
您的问题存在多个问题和误解:
没有转换规范,尾随不是转换的一部分,它充当必须与输入字符匹配的字符,这不会发生,因为仅在换行符之前或文件末尾停止。
%[^\n]s
s
s
%[^\n]
fflush(stdin)
具有未定义的行为。它不会刷新输入流。您可以读取和丢弃输入行中的剩余字符,包括带有循环的换行符:int c; while ((c = getchar()) != EOF && c !+ '\n') continue;
和 之间的区别在于空格字符的行为:忽略前导空格(包括换行符),然后读取字符并将其存储到目标数组中,直到读取空格并将其推回输入流。相反,读取和存储除换行符之外的任何字符,换行符被推回。
%s
%[^\n]
%s
%[^\n]
上述行为的后果是忽略 by 留下的挂起换行符和任何其他前导空格,然后读取进一步的输入,直到找到下一个空格字符,该字符在输入流中保持挂起状态。 立即停止并返回,因为挂起的换行符不会被忽略并且与规范不匹配。若要跳过此前导空格,应在格式字符串中使用空格:
scanf("%s", student)
scanf("%d", &roll_no)
scanf("%[^\n]", student)
0
scanf
scanf(" %[^\n]", student)
如果输入包含一长串匹配字符,则两者都可以将任意数量的字符存储到目标数组中。这是一个典型的安全漏洞,攻击者可以使用精心构造的输入行来利用它。您应该将要存储的最大字符数传递为 或
%s
%[^\n]
scanf("%999s", student)
scanf(" %999[^\n]", student);
在使用仍未初始化的目标变量时,应始终测试 的返回值以检测无效或缺失的输入,并避免未定义的行为。
scanf()
没有参数的原型是 。
main
int main(void)
这是一个修改后的版本:
#include <stdio.h>
int main(void) {
int roll_no;
char student[1000];
float physics, maths, chemistry;
printf("Enter your roll no.: ");
if (scanf("%d", &roll_no) != 1) {
fprintf(stderr, "invalid input\n");
return 1;
}
printf("\nEnter your name: ");
if (scanf(" %999[^\n]", student) != 1) {
fprintf(stderr, "invalid input\n");
return 1;
}
printf("\nEnter your physics: ");
if (scanf("%f", &physics) != 1) {
fprintf(stderr, "invalid input\n");
return 1;
}
printf("\nEnter your maths: ");
if (scanf("%f", &maths) != 1) {
fprintf(stderr, "invalid input\n");
return 1;
}
printf("\nEnter your chemistry: ");
if (scanf("%f", &chemistry) != 1) {
fprintf(stderr, "invalid input\n");
return 1;
}
printf("Student Name: %s\n"
"Physics Marks: %.2f Chemistry Marks: %.2f Maths Marks: %.2f",
student, physics, chemistry, maths);
return 0;
}
您可以尝试避免代码重复,并在出现错误时使用自定义输入函数(如下所示)重新提示用户:
#include <stdio.h>
int get_integer(const char *prompt, int *dest, int min, int max) {
for (;;) {
int val, c, res;
printf("%s: ", prompt);
res = scanf("%d", &val);
while ((c = getchar()) != EOF && c != '\n')
continue;
if (res == 1) {
if (val >= min || val <= max) {
*dest = val;
return 1;
}
printf("value %d out of range [%d..%d]\n", val, min, max);
} else
if (res == EOF || c == EOF) {
printf("unexpected end of file\n");
return 0;
} else {
printf("invalid input\n");
}
}
}
int get_float(const char *prompt, float *dest) {
for (;;) {
float val;
int c, res;
printf("%s: ", prompt);
res = scanf("%f", &val);
while ((c = getchar()) != EOF && c != '\n')
continue;
if (res == 1) {
*dest = val;
return 1;
} else
if (res == EOF || c == EOF) {
printf("unexpected end of file\n");
*dest = 0;
return 0;
} else {
printf("invalid input\n");
}
}
}
int get_string(const char *prompt, char *dest, size_t size) {
for (;;) {
int c;
size_t n = 0, i = 0;
printf("\n%s: ", prompt);
while ((c = getchar()) != EOF && c != '\n') {
if (i + 1 < size)
dest[i++] = (char)c;
n++;
}
if (i < size) {
dest[i] = '\0';
}
if (n == 0) {
if (c == EOF) {
printf("unexpected end of file\n");
return 0;
}
printf("string cannot be empty\n");
} else {
return 1;
}
}
}
int main(void) {
int roll_no;
char student[1000];
float physics, maths, chemistry;
if (!get_integer("Enter your roll no.", &roll_no, 0, 10000)
|| !get_string("Enter your name", student, sizeof student)
|| !get_float("Enter your physics marks", &physics)
|| !get_float("Enter your maths marks", &maths)
|| !get_float("Enter your chemistry marks", &chemistry)) {
return 1;
}
printf("Student Name: %s\n"
"Physics Marks: %.2f Chemistry Marks: %.2f Maths Marks: %.2f\n",
student, physics, chemistry, maths);
return 0;
}
评论
typedef char *string
评论
stdin
fflush
fflush(stdin);
可能不会做你所希望的。在尾随 s 不正确。scanf() 将换行符留在缓冲区中,值得一读,以了解处理此问题的正确方法。%[^\n]s
%[...]s
%[...]
s
scanf
s
scanf( "%999[^\n]", name );