当第一次运行for循环时,程序等待用户输入。但在第一次之后,两条scanf线似乎被跳过了。
我已经注释掉了misc代码:
#include <stdio.h>
int n = 0;
struct student {
int age;
char name[20];
};
void enterStudents() {
printf("How many students do you want to enter? \n");
scanf("%d", &n);
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
scanf("%d", &list[i].age);
printf("Enter student number %d's name: ", i+1);
scanf(" %c", list[i].name);
}
listSort(list);
}
/**int listSort(struct student list[n]) {
char tempName[20];
int tempAge;
for(int i=0; i<n-1; i++){
if(list[n].age < list[n+1].age) {
tempAge = list[n].age;
strcpy(tempName, list[n].name);
list[n].age = list[n+1].age;
strcpy(list[n].name, list[n+1].name);
list[n+1].age = tempAge;
strcpy(list[n+1].name, tempName);
}
}
}**/
int main() {
enterStudents();
}
答案 0 :(得分:1)
初学者经常忽略scanf
的一个问题是,如果转换
失败或转换转换的字符少于用户输入的字符数(for
使用%c
代替%s
)的示例,然后scanf
将保留未转换的内容
输入缓冲区中的字符。 scanf
的后续调用将首先尝试
在再次读取之前转换输入缓冲区中的那些字符
来自用户。
在您的情况下,您使用了%c
,但用户输入的内容比a长
单个字符。转换中只使用了1个字符,剩下的就剩下了
在输入缓冲区中。在下一个for
次迭代scanf("%d")
尝试转换
保留在输入缓冲区中的字符,并且因为用户输入了名称的非数字,scanf
失败,下一个scanf
只读取第一个字符和
留下其他人等等。这就是为什么scanf
会跳过这些电话。
您应该检查scanf
的返回值,它返回的数字
它成功转换了。如果你得到的话,这是很好的信息
转换次数超出预期,然后您知道scanf
调用失败,您可以
对此作出反应。如果你正在阅读字符串,你也可以清理缓冲区,
空格后的换行符和单词留在缓冲区中,这可能会导致
随后调用scanf
会有些麻烦。你可以使用这样的函数:
void clean_stdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
所以你的功能应该是这样的:
int enterStudents() {
printf("How many students do you want to enter? \n");
if(scanf("%d", &n) != 1)
{
fprintf(stderr, "Could not read from the user\n");
return -1; // failure
}
if(n <= 0)
{
fprintf(stderr, "invalid number of students\n");
return -1;
}
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
if(scanf("%d", &list[i].age) != 1)
{
fprintf(stderr, "could not read age from the user\n");
return -1;
}
printf("Enter student number %d's name: ", i+1);
if(scanf("%19s", list[i].name) != 1)
{
fprintf(stderr, "could not read name from the user\n");
return -1;
}
// cleaning stdin
clean_stdin();
}
...
return n; // sucess
}
请注意,我已更改了该功能,以便在失败时返回-1并且 学生阅读成功的数量,因此呼叫者可以知道出了什么问题并得到了 同时的学生人数。一般来说,为了使你的代码 更强大,你应该永远信任用户,而你应该仔细检查 用户输入。您必须检查用户是否输入了否定号码 学生数量。 &#34;正确&#34;心灵设置是&#34;用户试图打破你的 代码输入错误的数据,我必须处理#34;。我知道,代码 变得稍微大一点,但它更强大,如果出现问题,你就可以了 可以更快地缩小范围(基于错误消息) 错误。在你的代码中,当某些东西失败时,你真的不知道它在哪里 可能发生了。
另请注意,在名称扫描中,我使用了scanf("%19s", ..)
而不是%s
。该
原因是如果名称较长,使用%s
可能会溢出缓冲区
比缓冲区可以容纳。如果名称超过19个字符,它将
溢出缓冲区。使用"%19s"
,您将限制应该使用的字符数
在这种情况下,scanf
将转换最多19个字符并忽略
休息。为什么19而不是20?你必须使用19,因为C中的字符串是
'\0'
- 已终止,因此数组中的最后一个空格应该用于
'\0'
- 终止字节,因此为19。
答案 1 :(得分:0)
每当你输入来自用户的输入,其中输入有序列作为第一个是任何其他数据类型,然后字符或字符数组,如你的情况序列是整数,然后是字符。首先你输入21岁的学生年龄,当你按'输入键'时,这个'输入'被作为下一个字符输入的输入。然后你的输入将如下所示:
age=21
name='enter' (enter key that you pressed)
现在我们可以使用fflush(stdin)函数,这将刷新输入键并允许您输入名称。这段代码可行:
void enterStudents()
{
printf("How many students do you want to enter? \n");
scanf("%d", &n);
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
scanf("%d", &list[i].age);
//enter this line after your first input
fflush(stdin);
printf("Enter student number %d's name: ", i+1);
scanf(" %s", list[i].name);
}
listSort(list);
}