C语言 fgets语句不被执行



这是我用C编写的一个简单程序的代码,用于在结构体中存储学生的详细信息。我遇到的问题是,用于接受名称字符串的fgets语句没有得到执行,而是直接打印我的下一个printf语句,错误行被标记。另外,其余的代码也可以完美地工作。现在我已经尝试了相同的代码,将'fgets'更改为'gets'和'scanf'/'scanf_s',但我有相同的结果。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Students
{
char name[30];
int age;
int roll_number;
char address[30];
}std[3];
void names(struct Students std[], int n)
{
int i = 0;
printf("Here are the names of students whose age is 14");
while (i < n)
{
if (std[i].age == 14)
{
printf("%s", std[i].name);
}
i++;
}
}
void everoll(struct Students std[], int n)
{
int i = 0;
printf("Here are the names of students whose age is 14");
while (i < n)
{
if (std[i].roll_number % 2 == 0)
{
printf("%s", std[i].name);
}
i++;
}
}
void details(struct Students std[], int n, int a)
{
int i = 0;
while (i < n)
{
if (std[i].roll_number == a)
{
printf("Here are the detailsn");
printf("The name is : %snThe address is : %snThe age is : %d", std[i].name, std[i].address, std[i].age);
}
i++;
}
}
int main()
{
printf("Enter the details of the students:nn");
for (int i = 0; i < 3; i++)
{
printf("Enter the roll number of the student:n");
scanf_s("%d", &std[i].roll_number);
printf("Enter the age of the student:n");
scanf_s("%d", &std[i].age);
printf("Enter the name of the student:n");  
fgets(std[i].name, 30, stdin);                      //error line
printf("Enter the address of the student:n");      //This line gets executed dirctly
fgets(std[i].address, 30, stdin);                  //This fgets works fine
}
eve:
printf("Which operation do you want to perform n1) finding students with age 14n2) Printing names of students with even roll numbern3) Finding details by enetering the roll numbern");
int d;
scanf_s("%d", &d);
int b;
switch (d)
{
case 1:
names(std, 3);
break;
case 2:
everoll(std, 3);
break;
case 3:
printf("Enter the roll number:n");
scanf_s("%d", &b);
details(std, 3, b);
break;
default:
printf("Wrong number entered");
goto eve;
}
return 0;
}

函数scanfscanf_s通常不会消耗一整行输入,除非您显式地指示它。

例如,如果用户输入

5n
20n
John Doen
200 Main Streetn

其中n是用户按ENTER键时产生的换行符,然后函数调用

scanf_s("%d", &std[i].roll_number);

将匹配并只使用字符5,但在输入流中保留换行符。

函数调用

scanf_s("%d", &std[i].age);

然后将使用所有前导空白字符,因此它将使用第一行的换行字符,然后匹配并使用第二行中的20。它不会使用第二行上的换行符。

函数调用

fgets(std[i].name, 30, stdin);

现在将读取输入流中的所有内容,直到并包括下一个换行符。由于下一个字符是第二行(scanf_s留下的)的换行字符,这就是这个函数调用将从输入流中读取的全部内容,并将该字符写入std[i].name。因此,这个函数调用将不会从第三行读取任何内容。

函数调用

fgets(std[i].address, 30, stdin);

现在将再次读取输入流上的所有内容,直到并包括下一个换行符。因此,它将把输入的第3行(即John Doe)的全部内容读入std[i].address,包括换行符。

所以,总结一下,你的程序有以下问题:

第二次调用scanf_s将不使用换行符,因此第一次调用fgets将只从第2行读取换行符,尽管您希望它读取整个第3行。因此,第3行被第二个fgets函数调用读取,尽管您希望它被第一个fgets调用读取。

因此,解决这个问题的最简单的方法是在第二个scanf_s语句之后,在第一个fgets语句之前,使用该行的剩余部分(包括换行符)。

实现这一目的的一种方法是使用以下循环:
int c;
do
{
c = getchar();
} while ( c != EOF && c != 'n' );

更简洁的写法是:

for ( int c; ( c = getchar() ) != EOF && c != 'n' )
;

您也可以使用scanf用于此目的:

//consume and discard everything up to the next newline character
scanf( "%*[^n]" );
//consume and discard the newline character
scanf( "%*c" );

但是,与其使用scanfscanf_s读取部分行,不如总是读取一整行输入,这样更直观,更不容易出错。因此,我建议使用fgets来读取所有4行输入。然后可以使用strtol函数将字符串转换为整数:

char line[500];
printf("Enter the roll number of the student:n");
fgets( line, sizeof line, stdin );
std[i].roll_number = strtol( line, NULL, 10 );
printf("Enter the age of the student:n");
fgets( line, sizeof line, stdin );
std[i].age = strtol( line, NULL, 10 );
printf( "Enter the name of the student:n" );
fgets( std[i].name, sizeof std[i].name, stdin );
printf("Enter the address of the student:n" );
fgets( std[i].address, sizeof std[i].address, stdin );

最新更新