如何在循环中结合使用 scanf(对于非字符或字符串)获取单个字符

How to get a single character in conjunction with using scanf (for non-characters or Strings) in a loop

这是我的代码:

struct Patient{
   char name[50];
   char gender ; // M:male , F:female
   unsigned age ;
   unsigned Systole;
   unsigned Diastole;
};
//blah blah blah
struct Patient P[3];
for(i=0 ; i<3 ; i++){
   printf("\nPATIENT%d\n",i+1);
   printf("Name:");
   gets(P[i].name);
   printf("Gender(F=female , M=male):");
   scanf("%c",&(P[i].gender));
   printf("Systole:");
   scanf("%u",&(P[i].Systole));
   printf("Diastole:");
   scanf("%u",&(P[i].Diastole));
   printf("\n%s %c %u %u\n", P[i].name, P[i].gender, P[i].Systole, P[i].Diastole);
   }

这是我的输出:

PATIENT1
Name:Samantha
Gender(F=female , M=male):F
Systole:120
Diastole:90

Samantha F 120 90

PATIENT2
Name:Gender(F=female , M=male):Jack
Systole:Diastole:
 J 4718656 131072

PATIENT3
Name:Gender(F=female , M=male):Michael
Systole:Diastole:
ack M 16454 2
Normal:0

如您所见(我在获取每个结构索引数据后打印)我在获取用户输入时遇到问题。有什么问题吗?

编辑。 我将代码(由于建议)更改为:

for(i=0 ; i<3 ; i++){
   printf("\nPATIENT%d\n",i+1);
   printf("Name:");
   scanf("%s", &(P[i].name));
   printf("Gender(F=female , M=male):");
   scanf("%c",&(P[i].gender));
   printf("Systole:");
   scanf("%u",&(P[i].Systole));
   printf("Diastole:");
   scanf("%u",&(P[i].Diastole));
   printf("\n%s %c %u %u\n", P[i].name, P[i].gender, P[i].Systole, P[i].Diastole);
        }

但输出仍然失真:

PATIENT1
Name:Alison
Gender(F=female , M=male):Systole:F
Diastole:
Alison
 436170816 4044120064

PATIENT2
Name:Gender(F=female , M=male):Systole:Jack
Diastole:
F
 4456512 131072

PATIENT3
Name:Gender(F=female , M=male):Systole:Sandy
Diastole:
Jack

函数gets不存储换行符,所以你必须使用:

scanf(" %c", &(P[i].gender))

注意 space 将跳过空白 space 包括换行符 你应该避免使用 gets 函数,尽量只使用 scanf 这应该是:

scanf(" %49[^\n]%*c", P[i].name)

有关 scanf 如何工作的更多信息,请参阅此 post

将所有工作代码放在一起是:

for(i=0 ; i<3 ; i++){
   printf("\nPATIENT%d\n",i+1);
   printf("Name:");
   scanf(" %49[^\n]%*c", P[i].name);
   printf("Gender(F=female , M=male):");
   scanf(" %c",&(P[i].gender));
   printf("Systole:");
   scanf("%u",&(P[i].Systole));
   printf("Diastole:");
   scanf("%u",&(P[i].Diastole));
   printf("\n%s %c %u %u\n", P[i].name, P[i].gender, P[i].Systole,   P[i].Diastole);
}

第一个 scanf 现在也消耗上一次迭代中的任何换行符。

你的主要问题是这条语句:

scanf("%c",&(P[i].gender));

c 转换说明符不会跳过输入流中的任何前导白色space(例如前一个条目后面的换行符,gets 不会consume),所以你选择了性别的换行符,这就抛弃了后面的所有内容。

要解决此问题,请在 %c:

之前放置一个空白 space
scanf(" %c",&(P[i].gender));

空白 space 告诉 scanf 消耗所有领先的白色 space。

此外,请勿使用 gets - 它已在 C99 TC3 中弃用,并已从 C2011 规范中完全删除。它 在您的代码中引入一个故障点。使用 fgets 代替:

fgets( P[i].name, sizeof P[i].name, stdin );

gets 不同,如果有空间,fgets 将使用换行符并将其存储到目标缓冲区中,因此您需要检查并删除它,如下所示:

char *newline = strchr( P[i].name, '\n' );
if ( newline )
  *newline = 0;

scanf("%u",&(P[i].Diastole));得到一个整数,但留下一个新行(从用户输入数字并按回车)

在循环的第二次迭代中,gets(P[i].name);读取剩下的换行符并将其他所有内容从该点开始。

您需要处理读取最后一个换行符(或可能 \r\n),或者您可以使用 gets 或更好的 fgets 读取每一行输入并使用 sscanf 或 atoi 等获取值来自它(当需要一个数字时)。

我终于得到了真实而简洁的答案:

The scanf function removes whitespace automatically before trying to parse things other than characters. The character formats (primarily %c) are the exception; they don't remove whitespace.

自从我得到一个性别字符后,它就引起了问题。最后我意识到使用 getch() 是最好的解决方案,因为它不会立即将任何内容放入缓冲区和 returns。另外 getch() 是 non-standard,但它存在于我的案例中。
所以最后这是我的代码:

for(int i=0 ; i<3 ; i++){
        printf("\nPatient%d",i+1);
        printf("\nName:");
        scanf("%s", P[i].name);
        printf("Age:");
        scanf("%u", &(P[i].age));
        printf("Gender(F=female , M=male):");
        P[i].gender = getchar();
        printf("\nSystole:");
        scanf("%u",&(P[i].Systole));
        printf("Diastole:");
        scanf("%u",&(P[i].Diastole));
    }

我还编辑了问题标题,因为它具有误导性。谢谢大家的回答努力。