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

时间:2016-06-21 21:02:13

标签: c scanf getchar getch

这是我的代码:

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

4 个答案:

答案 0 :(得分:1)

scanf(“%u”,&amp;(P [i] .Diastole));获取一个整数,但保留一个新行(从用户输入数字并按Enter键)

在循环的第二次迭代中,得到(P [i] .name);读取留在换行符上并从那一点开始放弃其他所有内容。

你需要处理读取最后一个新行字符(或者可能是\ r \ n),或者你可以使用获取或更好的fgets读取每行输入并使用sscanf或atoi等从中获取值(当需要一个数字时。)

答案 1 :(得分:0)

函数gets不存储换行符,因此您必须使用:

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

请注意跳过空格的空格,包括换行符 您应该避免使用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现在也消耗了上一次迭代中的任何换行符。

答案 2 :(得分:0)

你的主要问题是这句话:

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

c转换说明符不会跳过输入流中的任何前导空格(例如前一个条目后面的换行符,gets不会消耗),这样你就可以获取性别的换行符,而这会丢掉所有其他内容。

要解决此问题,请在%c

之前加上空格
scanf(" %c",&(P[i].gender));

空格告诉scanf使用所有前导空格。

此外,请勿使用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;

答案 3 :(得分:0)

最后,我得到了真实而又整洁的答案:

  

scanf函数在尝试解析字符以外的内容之前会自动删除空格。字符格式(主要是%c)是例外;他们不会删除空格。

因为我收到性别问题,所以它引起了问题。最后我意识到使用getch()是最好的解决方案,因为它不会将任何内容放入缓冲区并立即返回。同样getch()是非标准的,但它出现在我的案例中 所以最后这是我的代码:

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));
    }

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