gpt4 book ai didi

c - 在 for 循环的第一次迭代后跳过 Scanf

转载 作者:太空宇宙 更新时间:2023-11-04 03:18:21 26 4
gpt4 key购买 nike

当 for 循环第一次运行时,程序会等待用户输入。但是在第一次之后,两条 scanf 行似乎被跳过了。

我已经注释掉了杂项代码:

#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();

}

最佳答案

初学者使用scanf 时经常忽略的一个问题是,如果转换失败或转换转换的字符少于用户输入的字符(例如例如使用 %c 而不是 %s),然后 scanf 留下未转换的输入缓冲区中的字符。 scanf 的后续调用将首先尝试在再次读取之前转换输入缓冲区中的那些字符来自用户。

在您的情况下,您使用了 %c 但用户输入的内容比 a 长单个字符。转换中仅使用了 1 个字符,其余字符保留在输入缓冲区中。在接下来的 for 迭代中 scanf("%d") 尝试转换留在输入缓冲区中的字符,并且由于用户输入的名称不是数字,scanf 失败,下一个 scanf 仅读取第一个字符和将其余部分留在后面,等等。这就是为什么 scanf 会跳过调用的原因。

你应该检查scanf的返回值,它返回了它进行了成功的转换。这是很好的信息,如果你得到的更少转换次数超过预期,那么您就知道 scanf 调用失败了,您可以对此使用react。如果您正在读取字符串,您也可以清理缓冲区,空格后的换行符和单词留在缓冲区中,这可能会导致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,而阅读成功的学生人数,因此调用者可以知道出了什么问题并得到同时的学生人数。一般来说,为了让你的代码更稳健,你不应该永远信任用户并且你应该仔细检查用户输入。您必须检查用户没有输入负数学生人数。 “正确”的心态是“用户试图破坏你的通过输入不正确的数据来编写代码,我必须处理这个问题。我知道,代码变得稍微大一点,但它更坚固,如果出现故障,你可以更快地缩小范围(根据错误消息)发生的事情错误的。在您的代码中,当出现故障时,您真的不知道它在哪里可能发生了。

另请注意,在名称扫描中,我使用了 scanf("%19s", ..) 而不是 %s。这原因是如果名称较长,使用 %s 可能会溢出缓冲区比缓冲区可以容纳。如果名称超过 19 个字符,它将缓冲区溢出。使用 "%19s" 可以限制字符数被读取,在这种情况下 scanf 将最多转换 19 个字符并忽略休息。为什么是 19 而不是 20?你必须使用 19,因为 C 中的字符串是'\0'-终止,所以数组中的最后一个空间应该用于'\0' - 终止字节,因此为 19。

关于c - 在 for 循环的第一次迭代后跳过 Scanf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49183894/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com