如何解决用scanf阅读完整的句子
我具有以下功能:
Customer_Account new_acc(){
Customer_Account new_account;
new_account.account_id = account_id;
account_id++;
printf("\nEnter your name: ");
scanf("%s",new_account.name);
printf("Enter your date of birth (DD.MM.YYYY): ");
scanf("%d.%d.%d",&new_account.birth_date.day,&new_account.birth_date.month,&new_account.birth_date.year);
printf("\nEnter your ID number: ");
scanf("%lf",&new_account.tc_ID_number);
printf("\nEnter your address: ");
scanf("%s",new_account.adress);
printf("\nEnter your phone number: ");
scanf("%lf",&new_account.phone);
printf("\nEnter the amount you would like to deposit: ");
scanf("%lf",&new_account.amount);
printf("\n\033[1;32m Account successfully created\033[0m\n\n");
sleep(1);
}
但是当我运行它并输入一个名称和一个姓氏时,它将给出以下输出:
Enter your name: name surname
Enter your date of birth (DD.MM.YYYY):
Enter your ID number:
Enter your address:
Enter your phone number:
如果我没记错的话,“ \ n”留在缓冲区中,因此它跳过下一个scanf()。我查找了一些解决方案,但它们也不起作用。当我只输入一个单词时,我不会遇到任何问题。如何阅读完整的句子而不遇到这个问题?
解决方法
对于新的C程序员,使用scanf()
充满了陷阱。特别是因为不同的转化说明符对前导空白的处理方式不同。除%c
,%[…]
(扫描集)和%n
以外的所有内容都将忽略前导空格。此外,输入缓冲区中留下的任何(表示ANY)杂散非空格字符都会导致 matching-failure ,或者如果偶然碰巧与下一个转换说明符匹配,它将被当作您的输入而不是您的预期。
此外,除非您 检查返回结果 以验证输入和转换是成功还是失败,否则您将无法可靠地正确使用任何用户输入函数。
要消除与使用scanf()
进行用户输入相关的所有陷阱,建议您使用类似fgets()
(或POSIX {{1})的面向 line 的输入函数。 })一次读取整行输入。所有面向行的输入函数都读取并在其填充的缓冲区中包含结尾的getline()
。如果您需要从行中解析值,只需将缓冲区传递到'\n'
并像使用sscanf()
一样提取值,除了从填充的缓冲区(而不是scanf()
)中读取数据。这样,无论转换是成功还是失败,都不会影响您下一次尝试的输入-您用stdin
消耗了整行输入。
如果您需要将读取的内容存储到缓冲区(字符数组)中,只需使用fgets()
修剪尾随'\n'
,例如
strcspn()
仅此而已,用户输入将不会有任何问题。
在函数中进行输入时,必须提供有意义的返回类型,该类型可以指示用户输入是成功还是失败。返回结构不会提供任何输入是否成功的指示。相反,将返回类型设置为可以区分成功/失败的任何类型,然后将一个指针作为参数传递给要填充的结构。返回类型为#define MAXC 1024
...
char buf[MAXC];
fputs ("enter some string: ",stdout);
if (fgets (buf,MAXC,stdin) == NULL) { /* validate EVERY input */
fputs ("(user canceled input with manual EOF)\n",stdout);
return 1;
}
buf[strcspn (buf,"\n")] = 0; /* trim \n by overwriting with \0 */
很好,返回类型为int
表示失败,返回类型0
表示成功(或者您想要这样做-保持一致)。
用户输入可能看起来很无聊和多余,但是您不是在创建Art,而是在创建一个输入例程,该例程可以处理用户提供的任何输入(或踩在键盘上的猫),并且仍会产生正确的(定义的)结果在您的代码中。
请记住,您可以将输入例程更改为使用1
,并执行以下操作:
fgets()
(注意:,我将删除出生日期#define MAXC 1024 /* if you need a constant,#define one (or more) */
/* pass pointer to account to fill so return can be used
* to indicate success or failure of input routine,* return 0 on error or manual EOF,1 on successful input.
*/
int new_acc (Customer_Account *new_account)
{
char buf[MAXC]; /* array to hold all user input */
new_account->account_id = account_id;
account_id++;
/* name */
fputs ("\nEnter your name: "); /* no conversion,printf not required */
if (fgets (buf,stdin) == NULL) { /* validate read with fgets */
fputs ("(user canceled input)\n",stderr);
return 0; /* return 0 on failure */
}
buf[strcspn (buf,"\n")] = 0; /* trim \n */
strcpy (new_account->name,buf); /* copy buf to new_account->name */
/* date of birth */
fputs ("Enter your date of birth (DD.MM.YYYY): ",stdout);
if (!fgets (buf,stdin)) { /* same validation -- just shorthand */
fputs ("(user canceled input)\n",stderr);
return 0; /* return 0 on failure */
}
if (sscanf (buf,"%d.%d.%d",&new_account->birth_date.day,&new_account->birth_date.month,&new_account->birth_date.year) != 3) {
fputs ("error: DOB - input or matching failure.\n",stderr);
return 0;
}
/* ID */
fputs ("\nEnter your ID number: ",stdin)) { /* ditto */
fputs ("(user canceled input)\n","%lf",&new_account->tc_ID_number) != 1) {
fputs ("error: ID - input or matching failure.\n",stderr);
return 0;
}
/* Address */
fputs ("\nEnter your adress: ","\n")] = 0; /* trim \n */
strcpy (new_account->address,buf); /* copy buf to new_account->name */
/* Phone Number */
fputs ("\nEnter your phone number: ");
if (!fgets (buf,&new_account->phone) != 1) {
fputs ("error: Phone - input or matching failure.\n",stderr);
return 0;
}
/* Amount */
fputs ("\nEnter the amount you would like to deposit: ",&new_account->amount) != 1) {
fputs ("error: Amount - input or matching failure.\n",stderr);
return 0;
}
return 1; /* return 1 indicating successful input */
}
之间的'.'
,因为除非用户输入"%d"
,否则匹配-会失败-这很可能是您的问题起源的地方
基本上每个输入都做相同的事情-很好。冗余-是的,稳定的-也是。
另一个警告,说明使用'.'
读取字符串。如果没有提供 field-width 修饰符以确保不超出数组界限,scanf()
并不比scanf()
更安全,请参阅Why gets() is so dangerous it should never be used!
您可以使用输入例程,方法是声明一个临时结构以填充调用函数并传递指向该函数的指针,例如
gets()
除了可以检查 for (;;) {
Customer_Account tmp;
if (!new_acc (&tmp))
break;
/* assign tmp to final storage here */
sleep (1);
}
的返回值之外,这与您的函数工作方式大致相同。我们知道输入是成功还是失败。
仔细检查一下,如果还有其他问题,请告诉我。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。