用scanf阅读完整的句子

如何解决用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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-