我的代码很快出现问题。请查看函数enter()。当我请求名称,并使用gets()时,它只是跳过它,好像什么都没有,并跳转到请求年龄。我做错了什么?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define RECORDS 30
#define LEN 20
/*Questions
Formatting display() - can we use spaces to format?
Is the patient structure supposed to be global or local in enter()?
Why doesn't printf("name: "); scanf("%s", name); require &name?
Make sure you account for first and last names, use getline or something
*/
void enter();
struct patient
{
char name[LEN];
int age;
double highBP, lowBP, riskFactor;
};
struct patient * db[RECORDS];
int counter = 0;
main()
{
int flag = 1;
while (flag == 1)
{
printf("---------------------------------------------------------\n");
printf("|\t(N)ew record\t(D)isplay db\t(U)pdate record |\n");
printf("|\t(L)oad disk\t(W)rite disk\t(E)mpty disk |\n");
printf("|\t(S)ort db\t(C)lear db\t(Q)uit |\n");
printf("---------------------------------------------------------\n");
printf("choose one: ");
char selection, selectionstr[3];
scanf("%s",selectionstr);
selection = selectionstr[0];
//printf("selection %c\n", selection);
if ((selection == 'n') || (selection == 'N'))
{
//New record
enter();
}
// Options omitted...
else
{
printf("not a vaild input\n");
}
}
}
void enter()
{
if (counter < 30)
{
FILE *fptr;
fptr = fopen("db.txt", "a");
char name[LEN];
int age;
double highBP, lowBP;
printf("name: "); //scanf("%s", name);
gets(name);
printf("age: "); scanf("%d", &age);
printf("high bp: "); scanf("%lf", &highBP);
printf("low bp: "); scanf("%lf", &lowBP);
struct patient temp;
strcpy(temp.name, name);
temp.age = age;
temp.highBP = highBP;
temp.lowBP = lowBP;
if ((highBP < 120) && (lowBP < 80))
temp.riskFactor = 0;
if (((highBP <= 120) && ((lowBP > 80) && (lowBP <= 90))) || ((highBP <= 80) && ((lowBP > 120) && (lowBP <= 130))))
temp.riskFactor = 1;
if (((highBP <= 120) && ((lowBP > 90) && (lowBP <= 100))) || ((highBP <= 80) && ((lowBP > 130) && (lowBP <= 140))))
temp.riskFactor = 4;
else
temp.riskFactor = 5;
if ((temp.riskFactor > 0) && (temp.age > 50))
temp.riskFactor += 0.5;
db[counter] = &temp;
//fprintf(fptr, "%s, %d, %f, %f, %f\n", db[counter]->name, db[counter]->age, db[counter]->highBP, db[counter]->lowBP, db[counter]->riskFactor);
printf("%s, %d, %f, %f, %f\n", db[counter]->name, db[counter]->age, db[counter]->highBP, db[counter]->lowBP, db[counter]->riskFactor);
counter++;
fclose(fptr);
}
else
printf("database full");
/*db[counter] = (struct patient *) malloc(sizeof(struct patient));
printf("name: "); scanf("%s", (*db[counter]).name);
printf("age: "); scanf("%d", (*db[counter]).age);
printf("high bp: "); scanf("%d", (*db[counter]).highBP);
printf("low bp: "); scanf("%d", (*db[counter]).lowBP);
//db[counter] = &temp;
printf("%d", sizeof(db[counter]));
//printf("%s", (db[counter])->name);
printf("%s, %d, %f, %f\n", db[counter]->name, db[counter]->age, db[counter]->highBP, db[counter]->lowBP);
counter++;*/
}
答案 0 :(得分:5)
你这样做:
scanf("%s",selectionstr); /* Leaves '\n' in the input buffer. */
然后你执行gets
gets(name); /* Encounters the leftover '\n'. */
问题是scanf
不消耗换行符,换行符保留在输入缓冲区中。当gets
出现时,它会遇到换行符并立即得到满足。
这个问题经常出现。它也是C FAQ。并且解释得很好here。
有些事情需要考虑:
有人会提出类似
的内容while((c = getchar()) != '\n' && c != EOF);
这也很麻烦
您最好的选择不是混淆scanf
和gets
。
作为旁注,您确实意识到您应该使用fgets
代替gets
,对吗?
答案 1 :(得分:4)
永远不要使用gets()
。甚至没有玩具程序。进入是一个坏习惯。它最终无法安全使用,因为您无法判断输入何时溢出您提供的缓冲区。
请改用fgets()
,并记住删除它留下的尾随换行符(gets()
删除的换行符。)
您的问题是以前使用scanf()
的输入未读取换行符,因此gets()
会读取第一个换行符 - 为您提供一个空字符串。你也会在下一次迭代中遇到同样的问题,因为你用scanf()
来读血压。
您不检查输入是否成功;始终检查scanf()
的返回值,以确保获得预期的输入。您将收到错误,因为该名称不能解释为数字。
你应养成编写用原型声明函数的代码的习惯;符号:
void enter();
说“有一个函数enter()
不返回任何值并且接受一个不确定的参数列表 - 任何一组参数都可以,但它不是一个变量参数列表函数”。相比之下:
void enter(void);
说“有一个函数enter()
没有返回值,也没有参数”。
此外,您应该将main()
的返回类型明确定义为int
。自C标准在所有函数定义上都需要显式返回类型以来,已有十多年了。
一旦您解决了数据扫描问题,您就会发现没有为您的记录正确分配空间。你的数组是:
struct patient *db[RECORDS];
在循环中,你有:
struct patient temp;
db[counter] = &temp;
麻烦是双重的。您正在为每个患者记录重复使用相同的空间,并且当enter()
退出时,您存储的指针超出范围。最简单的解决方法是将全局变量更改为:
struct patient db[RECORDS];
然后,您可以取消temp
变量,只需在db
中初始化相应的条目即可。或者,您可以保留temp
但是执行结构赋值而不是指针赋值:
db[counter] = temp;
答案 2 :(得分:1)
问题是在scanf调用之后,输入缓冲区中仍然存在“\ n”(或系统上的任何换行符),并且当您调用gets()时,它将获取换行符并返回。您需要做的是清除输入缓冲区。像这样,例如:
int c;
while ( ( c = getchar() ) != EOF && c != '\n' )
;
答案 3 :(得分:0)
过去是什么:
gets(str);
现在替换为:
int c;
while ( (c = getchar()) != EOF && c != '\n' )
;
fgets(str, sizeof(str), stdin);
str[strlen(str) - 1] = '\0';
我讨厌这个,但这似乎是做我需要的最小代码。这甚至假设用户点击进入&#39;在输入结束时。它不健壮!