前言

  今天看到博友发了个有关scanf的使用的注意事项,就是讨论缓冲区残存数据的问题,用简单的代码示例复述一下:

#define _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>
#include <stdio.h> int main(int argc, char *argv[])
{
int a;
char b;
scanf("%d", &a);
scanf("%c", &b);
printf("a = %d , b = %d\n", a, b);
system("pause");
return 0;
}

  你或许碰到这个输出:

5
a = 5 , b = 10
请按任意键继续. . .

  我明明想输入个5,然后回车输入下一个字符,但是,回车符也是个字符,会被scanf进去,绝大多数人的解决方案就是提前把这个字符读取走,但是如果缓冲区的东西太多的话,需要加个循环,才能处理,下面我来介绍scanf的高级用法,之间研究过,忘记在哪里看到的,这个是我总结的,那些基础用法自己看看书就行了。

清空缓存区

  我先把清空缓冲区的代码放上,因为后面的代码都会用到,至于为什么后面会有详细介绍:

scanf("%*[^\n]"); //清除到回车符的所有字符
scanf("%*c"); //清除回车符

指定输入长度

  我们都知道scanf可以指定小数位数和长度,如下是代码示例:

#define _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>
#include <stdio.h> int main(int argc, char *argv[])
{
int n;
float f;
char str1[23];
scanf("%2d", &n);
//清空缓冲区代码{
scanf("%*[^\n]");
scanf("%*c");
//}
scanf("%5f", &f);
//清空缓冲区代码{
scanf("%*[^\n]");
scanf("%*c");
//}
scanf("%5s", str1);
puts("执行后:");
printf("n=%d, f=%g, str=%s\n", n, f, str1); system("pause");
return 0;
}

  如下是输入和输出结果:

5653 12
2.56458452 2356.9999
helloworld
执行后:
n=56, f=2.564, str=hello
请按任意键继续. . .

  看到没,清空缓冲区的代码有效果了,如果没有这行清空缓冲区的代码,就会成这样子:

5653 12
执行后:
n=56, f=53, str=12
请按任意键继续. . .

  这就是清除缓冲区的作用。

单范围匹配

  不要惊讶,scanf也是支持类似正则表达式的功能的,我们用如下代码进行演示:

#define _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>
#include <stdio.h> int main(int argc, char *argv[])
{
char str2[30];
scanf("%[abcd]", str2); //%[abcd]表示只要字符串只有 a,b,c,d 范围内就匹配
puts("执行后:");
printf("%s\n", str2);
system("pause");
return 0;
}

  如下是输入和输出结果:

babccbaxyz
执行后:
babccba
请按任意键继续. . .

  代码中的注释可能说的不明白,这里我长篇大论一下:字符串从开头开始匹配,必须字符串只有abcd中这四个字符任意一个才有效,如果开头没有这四个字符,则匹配为空。

多范围匹配

  既然支持单范围了,肯定也支持多范围,什么是多范围匹配可以先看看一些基础示例,如果会正则表达式的话很容易懂:

  • %[a-z]表示读取 abc...xyz 范围内的字符,也即小写字母;
  • %[A-Z]表示读取 ABC...XYZ 范围内的字符,也即大写字母;
  • %[0-9]表示读取 012...789 范围内的字符,也即十进制数字;
  • %[a-zA-Z]表示读取大写字母和小写字母,也即所有英文字母;
  • %[a-z-A-Z0-9]表示读取所有的英文字母和十进制数字;
  • %[0-9a-f]表示读取十六进制数字

  如果经常使用的话也就这些类型,如下是代码示例:

#define _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>
#include <stdio.h> int main(int argc, char *argv[])
{
char str3[30];
scanf("%[a-zA-Z]", str3); //只读取字母
puts("执行后:");
printf("%s\n", str3);
system("pause");
return 0;
}

  如下是输入和输出结果:

abcXYZ123abcXYZ123
执行后:
abcXYZ
请按任意键继续. . .

不匹配某些字符

  既然有匹配的字符,肯定有不想匹配的字符。对于不匹配某些字符,scanf允许我们在%[ ]中直接指定某些不能匹配的字符,具体方法就是在不匹配的字符前面加上^,给几个例子:

  • %[^\n]表示匹配除换行符以外的所有字符,遇到换行符就停止读取;
  • %[^0-9]表示匹配除十进制数字以外的所有字符,遇到十进制数字就停止读取。

  如下是代码示例:

#define _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>
#include <stdio.h> int main(int argc, char *argv[])
{
char str11[30], str12[30];
scanf("%[^0-9]", str11); scanf("%*[^\n]");
scanf("%*c"); //清空缓冲区 scanf("%[^\n]", str12); //等效为gets()
puts("执行后:");
printf("str1=%s \nstr2=%s\n", str11, str12);
system("pause");
return 0;
}

  如下是输入和输出结果:

abcXYZ@#87edf
Cnblog_wingsummer
执行后:
str1=abcXYZ@#
str2=Cnblog_wingsummer
请按任意键继续. . .

丢弃数据

  scanf还允许把读取到的数据直接丢弃,不往变量中存放,具体方法就是在%后面加一个*,如下是代码示例:

#define _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>
#include <stdio.h> int main(int argc, char *argv[])
{
int nn;
char str[30];
scanf("%*d %d", &nn);
scanf("%*[a-z]");
scanf("%[^\n]", str);
puts("执行后:");
printf("n=%d, str=%s\n", nn, str);
system("pause");
return 0;
}

  如下是输入和输出结果:

100 999abcxyzABCXYZ
执行后:
n=999, str=ABCXYZ
请按任意键继续. . .

羽夏闲谈—— C 的 scanf 的高级用法的更多相关文章

  1. 羽夏闲谈——VSCode 配置 C/C++环境

    前言   VSCode是微软发布一款跨平台的源代码编辑器,其拥有强大的功能和丰富的扩展,使之能适合编写许多语言.我的环境是64位Win10,如果是其他系统请自行判断调整.本人根据网上的配置方法在结合本 ...

  2. 羽夏闲谈—— C 语言入门之问

    前言   最近加入了一个QQ频道,有很多想学C的纯小白.为什么这么说呢?因为他们会问一些环境用啥?为啥我配置不行?看了教程配置环境我也不会,咋配置?为啥这里代码这里有错误?啥语言好不好?诸如此类的问题 ...

  3. 羽夏看Win系统内核—— VT 入门番外篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  4. 羽夏 Bash 简明教程(上)

    写在前面   该文章根据 the unix workbench 中的 Bash Programming 进行汉化处理并作出自己的整理,并参考 Bash 脚本教程 和 BashPitfalls 相关内容 ...

  5. 跟羽夏学 Ghidra ——工具

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...

  6. (五)羽夏看C语言——结构体与类

    写在前面   由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...

  7. (四)羽夏看C语言——循环与跳转

    写在前面   由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...

  8. (三)羽夏看C语言——进制

    写在前面   由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...

  9. (二)羽夏看C语言——容器

    写在前面   由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...

随机推荐

  1. Redis 实现了自己的 VM

    Redis的VM(虚拟内存)机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据). Redis提高数据库容量的办法有两种: 1.一种是可以 ...

  2. LT7211替代芯片|低BOM成本替代LT7211 EDP转LVDS转换设计芯片CS5211

    LT7211B是一种用于虚拟现实/显示应用的TYPE-C/DP1.2转LVDS转换芯片.LT7211B 对于DP1.2输入,LT7211B可以配置为1.2.4车道,还支持车道交换功能.自适应均衡使其适 ...

  3. Android物联网应用程序开发(智慧城市)—— 火焰监控界面开发

    效果: 布局代码: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns: ...

  4. 如何使用NiFi等构建IIoT系统

    您认为构建一个先进的工业物联网原型需要多长时间: 从传感器收集数据到每个工厂的网关 将传感器数据从一个或多个工厂移至云或数据中心 自动热部署新配置到所有边缘设备 支持大规模数据量和端到端安全性 使用正 ...

  5. 造轮子-strace(二)实现

    这一篇文章会介绍strace如何工作,再稍微深入介绍一下什么是system call.再介绍一下ptrace.wait(strace依赖的system call).最后再一起来造个轮子,动手用代码实现 ...

  6. BOM 点击触发 倒计时发送验证码案例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. shell 之 循环执行某操作

    需求: 按月执行201904到202010的py脚本. 代码如下: #!/bin/bash i=201904 # 定义开始月份 while [ $i -le 202010 ] # 当i小于等于2020 ...

  8. 前后端分离 导致的 静态页面 加载 <script type="module" > 报CORS 跨域错误,提示 blocked by CORS policy

    1.前言 静态页面 加载 <script type="module" > 报CORS 跨域错误,提示Access to script at ftp:///xxx.js ...

  9. RabbitMQ --- 直连交换机 【 有回调方法,获取消费结果 】

    1.前言 上一随笔详细记录了直连交换机的方法,发送的消息是异步的,如果消息未被消费者消费,那么可以一直存在消息队列中. 那么有没有办法做一个回调,当消息被消费后,被通知消息成功被消费者消费啦? 答案是 ...

  10. Python操作数据库实战

    pymysql # -*- coding: utf-8 -*- """ @Datetime: 2018/12/26 @Author: Zhang Yafei " ...