当前位置: 首页 > article >正文

【C语言】常见的scanf()接收异常及注意事项

问题简述

        作者在写链表的创建时突然发现一个玄学问题,scanf接收的值从第二个开始总是有问题:

while(flag=='s'){
    /*......*/
    scanf("a=%c",&x);
    /*......*/
    scanf("b=%c",&flag);
    /*......*/
}

 x接收是没有问题的,但到flag这里还没有输入就直接跳出循环了。

原因分析

跳出循环可能有两个原因

  1. 不满足循环条件
  2. 程序崩溃

        第一点说明是flag的值不是's';第二点程序直接崩溃结束的话后续代码不会执行,但实际上作者的后续代码是正常的。因此可以判断是其接收异常。

定位错误

        监控该变量,发现该变量的值是'\n'即为换行符。

        也就是说我们输入完第一个x之后的按下的换行被记录保存下来了。

        作者去查了一下源码及相关资料,发现是其缓冲区的问题。实际上,我们输入的过程中除了内容之外还有一个换行符,都储存在缓冲区了。

        scanf只是把缓存区的内容取走了,换行符却还在缓冲区中,因此下一次执行scanf时直接把换行符当输入取走了。

解决问题

       我们需要在输入之后清除这个换行符,我们可以用getchar()这个函数,getchar会从缓冲区取走一个字符。

while(flag=='s'){
    /*......*/
    scanf("%c",&x);
    getchar();//从缓存区取走一个字符
    /*......*/
    scanf("%c",&flag);
    getchar();//从缓存区取走一个字符
    /*......*/
}

 到这里我们这个问题就解决了,为了以后少犯错误接下来我们进一步去探究这个问题。

scanf函数

int scanf(const char *format, ...);
  • format:格式字符串,指定了输入数据的格式。
  • ...:可变参数列表,对应于格式字符串中的每个格式说明符,需要提供相应类型的指针以存储输入的数据

        可能很多朋友们不知道,scanf是有返回值的,scanf的返回值是读入成功的数据项数,既一个int值。

int num=scanf("%d %d",&a,&b);
  • 如果我输入 1和2 则num的值为2
  • 如果我输入 a和2 则num的值为1
  • 如果我输入 a和b 则num的值为0
常见的格式说明符
%d读入有符号十进制整数
%f读入有符号浮点数
%c读入单个字符,后续不会加空字节
%s读入字符串,后续会加空字节,遇到空白字符完成读取
%p读入指针值
    空白字符 

        指的是一些不可见字符,主要用于格式化文本,常见的空白字符有:

  1. 空格(' ')
  2. 水平制表符('\t')
  3. 换行符('\n')
  4. 垂直制表符('\v')
  5. 换页符('\f')
  6. 回车符('\r')

getchar函数

        函数原型:int getchar(void)

        这个函数的实际用法是接收一个字符,其返回值是ASCII表的码值

        因为其接收是从缓冲区中接收(scanf也是从缓冲区中接收),也常常被我们用来清除缓冲区残留的内容。

        如果缓冲区没有内容,则和scanf类似,需要我们键盘键入,但重要的是其输入只能是一个字符

fflush(stdin)函数

        清空缓冲区函数。

        该函数可以直接清空缓冲区。但其不够稳定所以用的较少。我们可以看到其输入是stdin,表示输入流,因为该行为没有标准定义,在不同编译器或者不同平台上可能出现不同行为。

        作者在DEV C++中使用是没有问题的,但不同编译器不确定,因此需要注意。

        如果要清空缓冲区可以用scanf或getchar去循环读取并丢弃字符,例如:

void clear_input_buffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

【注意】上述的scanf和getchar函数的返回值还有一个EOF,表示文件结束符,其值一般为-1.


http://www.kler.cn/a/443863.html

相关文章:

  • SpringBoot 启动类 SpringApplication 二 run方法
  • apache-tomcat-6.0.44.exe Win10
  • 彻底认识和理解探索分布式网络编程中的SSL安全通信机制
  • 杂七杂八的网络安全知识
  • 练习题 最小栈
  • 企业数字化转型和人工智能(AI)之间的关系
  • websocket的心跳检测和断线重连
  • 开源 AI 智能名片 S2B2C 商城小程序中运营与产品的关系剖析
  • PHP基于Google Authenticator双因素身份验证实现动态码验证
  • 江协科技 OLED库 OLED_Print( )函数自动换行
  • uniapp获取内容高度
  • UE5中实现Billboard公告板渲染
  • 使用脚手架搭建vue项目
  • 利用HashMap设计学生管理系统
  • 云原生是什么
  • 消息系统之 Kafka
  • 初始Python篇(10)—— 初识 类与对象
  • Flask入门:打造简易投票系统
  • 项目管理工具Maven(一)
  • 《深入浅出HTTPS​​​​​​​​​​​​​​​​​》读书笔记(20):口令和PEB算法
  • java list 和数组互相转换的一些方法
  • Envoy 进阶指南(下):深入探究Envoy服务和架构
  • iOS在项目中设置 Dev、Staging 和 Prod 三个不同的环境
  • 开发基于 Streamlit 和 OpenAI 大模型的 Chatbot App:支持图片的多模态输入项目代码结构优化分析
  • Redis篇-19--运维篇1-主从复制(主从复制,读写分离,配置实现,实战案例)
  • Latex+VsCode+Win10搭建