c语言中比较特殊的输入格式
目录
一.%[ ] 格式说明符
1.基本用法
(1)读取字母字符:
(2)读取数字字符:
(3)读取所有字符直到遇到空格:
(4)读取直到换行符:
2.使用范围和组合:
3.^ 取反操作
4.注意事项
(1). 字符范围的正确表示
(2). 避免字符集中的特殊字符冲突
(3).避免空字符集
(4). 输入长度的控制
(5). 换行符和空格的处理
解决方法
修改后的代码
(6). 字符集的顺序和位置
(7). 检查返回值
二.%*抑制符
1.基本用法
用途
(1).跳过某些数据
(2).跳过特定格式的数据
(3).跳过特定字符
2.注意事项
三.%n 格式说明符
1.基本用法
(1)简单用法
(2)跟踪多个输入
(3)复杂输入的验证
2.注意事项
一.%[ ] 格式说明符
在C语言中,
scanf函数中的%[ ]格式说明符是一种非常灵活的方式,可以用来读取满足特定条件的一系列字符。%[ ]格式说明符允许程序员定义一个字符集,scanf会连续读取输入流中的字符,直到遇到不属于该字符集的字符为止。
ps:通常情况下,scanf会自动跳过空白字符(包括换行符),但是%[ ]这种格式说明符是一个例外。
1.基本用法
scanf("%[character_set]", string);
character_set: 这是一个字符集,它可以是特定字符或字符范围。string: 这是一个字符数组(字符串),用来存储读取到的字符。
举例说明:
(1)读取字母字符:
char str[100];
scanf("%[a-zA-Z]", str); // 只读取字母字符 (大小写)
printf("读取到的字母是: %s\n", str);
输入: abc123
输出: 读取到的字母是: abc
解释: scanf 会从输入流中读取所有属于 a-zA-Z 的字符,一旦遇到不属于该范围的字符(如数字 1),它将停止读取。
(2)读取数字字符:
char numStr[100];
scanf("%[0-9]", numStr); // 只读取数字字符
printf("读取到的数字是: %s\n", numStr);
输入: 123abc
输出: 读取到的数字是: 123
解释: 这里 scanf 只会读取数字字符(0到9),直到遇到非数字字符。
(3)读取所有字符直到遇到空格:
char str[100];
scanf("%[^ ]", str); // 读取所有字符直到遇到空格
printf("读取到的内容是: %s\n", str);
输入: hello world
输出: 读取到的内容是: hello
解释: scanf 会读取所有字符,直到遇到空格( )为止。^ 表示“除指定字符之外的所有字符”。
(4)读取直到换行符:
char line[100];
scanf("%[^\n]", line); // 读取一整行,直到换行符
printf("读取到的行是: %s\n", line);
输入: Hello, world!
输出: 读取到的行是: Hello, world!
解释: scanf 会读取所有字符,直到遇到换行符 \n 为止。即回车
2.使用范围和组合:
- 范围: 可以通过
-来表示一个字符范围,例如[a-z]表示所有小写字母。- 多个范围和字符: 你可以结合多个字符集或字符范围,例如
"[a-zA-Z0-9]"会匹配所有字母和数字。
char str[100];
scanf("%[a-zA-Z0-9]", str); // 读取字母和数字
printf("读取到的内容是: %s\n", str);
输入: abc123!@#
输出: 读取到的内容是: abc123
解释: 这里 scanf 读取了字母和数字,直到遇到非字母非数字字符。
3.^ 取反操作
取反: 在字符集的开头加上
^符号表示取反,即读取不属于该字符集的字符。
char str[100];
scanf("%[^,]", str); // 读取直到遇到逗号
printf("读取到的内容是: %s\n", str);
输入: Hello,world
输出: 读取到的内容是: Hello
解释: 这里 scanf 读取了所有字符,直到遇到逗号 , 为止,因为 [^,] 表示“除逗号之外的所有字符”。
4.注意事项
(1). 字符范围的正确表示
范围表示法:
a-z、A-Z、0-9这些范围表示法必须是有效的字符序列。a-z表示小写字母从a到z的所有字符,A-Z表示大写字母从A到Z的所有字符,0-9表示所有数字字符。错误的表示:
z-a、9-0这样的表示是无效的,会导致意外的行为。
char str[100];
scanf("%[z-a]", str); // 无效:z-a不是有效范围
(2). 避免字符集中的特殊字符冲突
连字符
-的使用:连字符-用于指定范围,但如果它被放置在错误的位置,可能会引起解析错误或未定义行为。
- 正确:
[a-z],[0-9A-F]。- 错误:
[-z](这里连字符和z之间没有起始字符,这种用法可能会导致未定义行为)。特殊用法:
- 开始位置: 如果要包含
-本身,可以把它放在范围的起始位置,如[-a-z],表示-和a到z的所有字符。- 结束位置: 如果连字符在字符集的末尾,如
[a-z-],它表示a到z的所有字符和-字符。
char str[100];
scanf("%[-a-zA-Z]", str); // 读取`-`或字母
(3).避免空字符集
空字符集:
scanf的%[ ]如果是空字符集,scanf会直接返回而不做任何操作,因此要确保字符集内包含有效内容。错误:
char str[100];
scanf("%[]", str); // 空字符集,`scanf`什么都不会读取
(4). 输入长度的控制
缓冲区溢出:
scanf使用%[ ]时没有自动限制读取的字符数。如果输入的字符超过了数组的容量,可能会导致缓冲区溢出。因此,建议使用宽度限定符来限制读取的最大字符数。
char str[100];
scanf("%99[a-zA-Z0-9]", str); // 最多读取99个字符,保留1个字符给结束符`'\0'`
(5). 换行符和空格的处理
换行符问题:
%[ ]读取字符时不会消耗换行符\n。这可能会导致在之后的scanf或getchar调用中,直接读取到换行符。如果需要处理换行符,可以在之后使用getchar()来消耗这个换行符。
可能大伙还是不懂,继续往下看:
假设你有以下代码:
char str[100];
scanf("%[a-zA-Z]", str);
- 输入:
hello\nworldscanf("%[a-zA-Z]", str)会读取并存储字符串"hello",但它不会读取或消耗换行符\n。- 换行符
\n仍然留在输入流中,等待下一次scanf或其他输入函数处理。
如果你随后调用scanf来读取另一个输入:
scanf("%d", &num);
- 因为之前的换行符
\n还在输入流中,scanf("%d", &num)会遇到这个换行符,并立即返回,通常会导致输入错误或跳过输入。
解决方法
为了避免这个问题,可以在调用scanf("%[ ]", ...)后手动读取并消耗掉换行符,通常通过getchar()来实现。
修改后的代码
char str[100];
scanf("%[a-zA-Z]", str);
getchar(); // 手动读取并消耗掉换行符
解释: 在读取完字符串后,getchar()将读取并消耗掉输入流中的换行符,使得后续的scanf调用不会受到影响。
空白字符的忽略:
scanf的%[ ]不会自动跳过空白字符(如空格、制表符、换行符等),除非在字符集中明确包含这些字符
char str[100];
scanf("%[a-zA-Z0-9 ]", str); // 允许读取空格字符
(6). 字符集的顺序和位置
顺序影响: 字符集的顺序不会影响
scanf的行为,但是清晰的字符集顺序更易于理解和维护代码。例如[a-zA-Z0-9]比[z-aZ-A9-0]更易读。排除特殊字符: 如果你想排除特定字符集中的某些字符,可以使用
[^ ],如[^a-zA-Z0-9]来读取非字母、数字的字符。
(7). 检查返回值
scanf的返回值:scanf返回成功读取的项目数。可以通过检查返回值来判断输入是否成功匹配。
char str[100];
int n = scanf("%99[a-zA-Z0-9]", str);
if (n == 1) {printf("读取成功: %s\n", str);
} else {printf("输入格式不匹配或读取失败\n");
}
ps:在scanf的语境中,"项目"通常指的是一个成功读取并存储到对应变量中的数据单元。因此,str在这个上下文中确实被视为一个项目。
二.%*抑制符
在C语言的
scanf函数中,%*被称为“抑制符”(或者“跳过符”)。它的作用是告诉scanf函数读取数据但不存储它。换句话说,scanf会解析输入数据并跳过该数据,而不将其赋值给任何变量。
1.基本用法
scanf("%*d"); // 读取并跳过一个整数
在这个例子中,scanf会从输入中读取一个整数,但不会将其存储在任何变量中。%*与任何有效的格式说明符结合使用,都会导致该数据被读取但不会存储。
用途
-
跳过不需要的数据:有时候你可能只需要读取输入中的部分数据,而对其他部分的数据不感兴趣。这时候可以使用
%*来跳过不需要的数据。 -
处理复杂的输入:如果输入数据格式比较复杂,你可以通过
%*来跳过一些无关的部分,只提取你感兴趣的数据。
示例
(1).跳过某些数据
#include <stdio.h>int main() {int a, c;scanf("%d %*d %d", &a, &c);printf("a = %d, c = %d\n", a, c);return 0;
}
输入: 1 2 3
输出: a = 1, c = 3
解释: 这个程序通过%d读取了第一个整数1并将其存储在a中,然后通过%*d读取了第二个整数2但没有存储它,最后通过%d读取了第三个整数3并将其存储在c中。
(2).跳过特定格式的数据
#include <stdio.h>int main() {char name[50];int age;scanf("%*s %d", &age);printf("Age: %d\n", age);return 0;
}
输入: John 25
输出: Age: 25
解释: 这里%*s会跳过输入的第一个字符串(John),然后%d读取第二个整数(25)并将其存储在age中。
*的多种组合使用
*可以与任何scanf的格式说明符结合使用,例如:
%*c: 读取并跳过一个字符。%*f: 读取并跳过一个浮点数。%*s: 读取并跳过一个字符串。%*[]: 读取并跳过一组符合特定字符集的字符。
(3).跳过特定字符
#include <stdio.h>int main() {int year, month, day;scanf("%d-%*d-%d", &year, &day);printf("Year: %d, Day: %d\n", year, day);return 0;
}
输入: 2024-08-13
输出: Year: 2024, Day: 13
解释: 这里%d读取年份2024,%*d跳过月份08,然后%d读取日期13。
2.注意事项
不会增加返回的项目数: 被
%*抑制符忽略的数据不会被计入scanf返回的成功读取项目数。例如,如果scanf成功读取两个变量而跳过一个数据,它的返回值是2,而不是3。格式匹配问题:
scanf依然会验证被跳过的数据是否符合指定格式,如果输入数据不符合指定的格式,scanf会停止读取。输入缓冲区影响: 即使数据被跳过,输入缓冲区中的数据仍然会被消耗掉,因此后续的
scanf调用不会再看到这些数据。
三.%n 格式说明符
%n是C语言中scanf函数的一种特殊格式说明符。它用于将到目前为止已经读取的字符数存储到一个整数变量中。与其他格式说明符不同,%n并不会从输入中读取数据并与其对应的数据类型匹配,而是直接记录scanf已经成功处理的字符数量。
1.基本用法
scanf("%d%n", &value, &num_chars);
在这个例子中,scanf会读取一个整数并将其存储在value中,接着,它会把读取到该整数为止所消耗的字符数存储在num_chars中。
scanf中的%n格式说明符
-
不消耗输入:
%n本身不消耗输入字符。它只是在内部计算并存储从输入流中已经读取的字符数。 -
存储读取字符的数量:
%n会将到达它的位置为止读取的总字符数存储在其对应的参数中。这个参数必须是指向int类型的指针。 -
多个
%n: 如果在一个scanf调用中出现多个%n,每个%n都会记录到目前为止从输入流中读取的字符数。因此可以用它来跟踪输入过程中的不同点。
示例
(1)简单用法
#include <stdio.h>int main() {int value, num_chars;scanf("%d%n", &value, &num_chars);printf("Value: %d, Characters read: %d\n", value, num_chars);return 0;
}
输入: 12345
输出: Value: 12345, Characters read: 5
解释: 在输入12345之后,scanf将12345存储在value中,而%n记录并存储了读取字符的数量(5个字符)。
(2)跟踪多个输入
#include <stdio.h>int main() {int a, b;int num_chars1, num_chars2;scanf("%d%n %d%n", &a, &num_chars1, &b, &num_chars2);printf("a = %d, b = %d\n", a, b);printf("Characters read for a: %d, total characters read: %d\n", num_chars1, num_chars2);return 0;
}
输入: 12 34
输出:a = 12, b = 34
Characters read for a: 2, total characters read: 5
解释:
- 在读取完第一个整数
12后,num_chars1存储了已经读取的字符数(2个字符)。 - 在读取完第二个整数
34后,num_chars2存储了总的字符数(5个字符,包括中间的空格)。
(3)复杂输入的验证
#include <stdio.h>int main() {int day, month, year;int chars_read;scanf("%2d/%2d/%4d%n", &day, &month, &year, &chars_read);if (chars_read == 10) {printf("Valid date: %02d/%02d/%04d\n", day, month, year);} else {printf("Invalid date format.\n");}return 0;
}
输入: 15/08/2024
输出: Valid date: 15/08/2024
解释:
- 这个程序读取日期并确保输入格式为
dd/mm/yyyy(总共10个字符)。 - 如果读取的字符数正好是10个字符,那么输入是有效的,否则输出无效格式。
2.注意事项
安全性问题: 使用
%n时,确保对应的参数是有效的int*指针,否则会导致未定义行为。这也是它不常用于现代C编程的原因之一,因为如果误用会导致潜在的安全漏洞。
scanf返回值不包含%n:scanf返回的成功读取项目数不包括%n。所以,即使%n在scanf中使用,它也不会影响scanf的返回值。与其他格式说明符的组合:
scanf会按照顺序解析格式说明符,如果在使用%n之前的格式说明符解析失败,%n就不会被执行。可能的用途:
- 输入格式检查: 可以通过检查读取的字符数来确保输入符合预期格式。
- 精确输入解析: 当你需要知道输入的精确位置(如进行复杂的文本处理)时,可以使用
%n。
完

相关文章:
c语言中比较特殊的输入格式
目录 一.%[ ] 格式说明符 1.基本用法 (1)读取字母字符: (2)读取数字字符: (3)读取所有字符直到遇到空格: (4)读取直到换行符: 2.使用范围和组合: 3.^ 取反操作 4.注意事项 (1). 字符范围的正确表示 (2). 避免字符集中的特殊字符冲突 (3).避免空字符集 (4). 输入长…...
远程命令行控制SSH
第一次接触SSH是ROS小车作为服务端,通过ubuntu电脑客户端访问。因为机器人接键盘和屏幕操作起来不方便,所以使用SSH进行连接,方便对小车的操作。 1.服务端安装 打开终端查看ssh是否安装 sudo service ssh status 如果未安装 sudo apt upd…...
钢铁百科:A572Gr60和SA572Gr60材质分析、A572Gr60和SA572Gr60简介
A572Gr60和SA572Gr60是两种常用的结构钢板,它们在材质、执行标准、化学成分、力学性能、交货状态、应用范围和常用规格方面有所不同。 材质: A572Gr60:属于美国材料与试验协会(ASTM)标准下的A572系列高性能结构钢&…...
一次sql请求,返回分页数据和总条数
日常搬砖,总少不了需要获取分页数据和总行数。 一直以来的实践是编码两次sql请求,分别拉分页数据和totalCount。 最近我在思考: 常规实践为什么不是 在一次sql请求中中执行多次sql查询或多次更新,显而易见的优势: ① 能…...
2.5 pyautogui 实现微信自动回复
第四节:实战微信自动回复 课程目标 学习如何通过pyautogui完成微信自动回复 课程内容 编码实现 import pyautogui as pg import time from pyautogui import ImageNotFoundException import pyperclip from cnocr import CnOcr import random ocr CnOcr() msg…...
观存储历史,论数据未来
数据存储 这几天我反复观看了腾讯云社区的《中国数据库前世今生》纪录片,每次的感受都大相径庭。以下是我在这段时间里对纪录片的两个不同感想,希望感兴趣的小伙伴们也能去观看一番。 一个是关于国产数据库的发展趋势的探讨:https://blog.c…...
linux:对目录的操作
一、对目录操作 1,打开目标目录 2.读取目录,, 3.关闭目录 目录 当文件看,只不过操作函数和操作文件函数不一样。 *1.opendir DIR *opendir(const char *name); 功能:打开一个目录获得一个目录流指针 参数:name:目录名 返回值…...
详解Redis 高可用的方式 Redis Cluster
Redis 高可用方式 Redis 提供了多种高可用性方案,主要包括以下几种方式: 主从复制(Replication) 主从复制是最基本的高可用性方案,通过将数据从一个主节点复制到多个从节点来实现数据的冗余和读写分离。主节点负责所…...
$clog2(1)=0
项目场景: 写ip 时, 使用参数化的方式实现2w1r 时,出现计算读返回index 时,减下溢! 问题描述 verilog中会使用parameter 参数化,例如使用dpth 和$clog2(dpth)addr 。 常见的写法没有什么问题。 module …...
开发学习日记1
用这个系列博客记录下学习开发的一些小收获 git的使用: 说来惭愧,学到了大二,git的使用还是一团糟,记录一下如何使用git进行团队合作开发 当要加入其他人的项目时首先你要创建自己的分支(克隆一下其他分支ÿ…...
孙宇晨领航波场TRON:引领数字资产迈向崭新纪元
在风起云涌的数字资产领域,孙宇晨这个名字始终与创新、突破和引领紧密相连。作为波场TRON的创始人,他不仅是一位远见卓识的领导者,更是推动数字资产迈向新纪元的坚实力量。 自波场TRON诞生以来,孙宇晨便以其敏锐的洞察力…...
python运维(twenty-four day)
一、python基础 1、环境python2、python3 [rootpython ~]# yum list installed | grep python #检查是否有python包 [rootpython ~]# yum list installed | grep epel #检查是否有epel包 [rootpython ~]# yum -y install epel-release [rootpython ~]# yum -y instal…...
Eureka原理实践
1. 简介 1.1. 概述 Eureka是Netflix开源的一个服务注册与发现框架,它在微服务架构中扮演着至关重要的角色。 Eureka由两个核心组件组成: Eureka Server(服务注册中心):负责存储、管理和提供服务实例信息,如服务名、IP地址、端口号等。Eureka Server通常采用集群部署以保…...
Ant-Design-Vue快速上手指南+排坑
1. 简介 1.1. 概述 Ant-Design-Vue是由阿里巴巴开源的一个基于Vue.js框架的企业级UI设计语言。它旨在帮助开发者构建设计优雅、体验流畅的企业级应用。Ant-Design-Vue提供了一系列高质量的Vue组件,包括表单、表格、布局、导航、图标等,可以帮助开发者快速搭建应用程序界面。…...
mysql5.7安装
1.创建一个software文件 2.先下载mysql的repo源 wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 3安装源包 rpm -ivh mysql-community-release-el7-5.noarch.rpm 可能会报错 改成命令 rpm -ivh mysql-community-release-el7-5.noarch.rpm --nodeps…...
UE开发中的设计模式(三) —— 对象池模式
在FPS游戏中,射击会生成子弹,在命中敌人后子弹会被销毁,那么会导致子弹对象频繁地创建和销毁,会造成运行效率降低且会产生内存碎片问题,而对象池模式可以很好地解决这个问题。 文章目录 问题提出概述问题解决总结 问题…...
Mocha测试框架:JavaScript自动化测试的瑞士军刀
在JavaScript开发中,自动化测试是确保代码质量和可靠性的关键环节。Mocha是一个广泛使用的JavaScript测试框架,它支持多种断言库,允许开发者编写简洁、灵活的测试用例。Mocha特别适用于Node.js环境,但也可以在浏览器中运行。本文将…...
flask实现Streaming内容传输
当传输大量内存,以至于超出内存大小,一般http服务器会报500错误,这时可以使用Streaming流的方式来传输内容,类似ChatGPT和视频流那样的输出方式,flask里要用到生成器和直接响应。 from flask import stream_with_cont…...
seata的使用(SpringBoot项目整合seata)
文章目录 1、解压 seata-server-1.7.1.zip2、启动 双击 seata-server.bat3、启动 seata 控制台用户界面4、所有分布式事务相关数据库要有undo-log5、项目引入seata依赖6、项目添加seata配置7、代码实现: 1、解压 seata-server-1.7.1.zip 2、启动 双击 seata-server.…...
docker容器和宿主机网络不通
防火墙未开启,检查网络配置无异常 解决: [rootlocalhost ~]# vim /etc/sysctl.confnet.bridge.beidge-nf-call-iptables 1 net.bridge.beidge-nf-call-ip6tables 1[rootlocalhost ~]# sysctl -p [rootlocalhost ~]# systemctl restart docker 如果网…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...
