c语言中比较特殊的输入格式

news2024/9/22 15:43:50

目录

一.%[ ] 格式说明符

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-zA-Z0-9 这些范围表示法必须是有效的字符序列。a-z表示小写字母从az的所有字符A-Z表示大写字母从AZ的所有字符0-9表示所有数字字符

错误的表示: z-a9-0 这样的表示是无效的,会导致意外的行为。

char str[100];
scanf("%[z-a]", str);  // 无效:z-a不是有效范围

(2). 避免字符集中的特殊字符冲突

连字符 - 的使用:连字符 - 用于指定范围,但如果它被放置在错误的位置,可能会引起解析错误或未定义行为。

  • 正确: [a-z][0-9A-F]
  • 错误: [-z](这里连字符和z之间没有起始字符,这种用法可能会导致未定义行为)。

特殊用法:

  • 开始位置: 如果要包含 - 本身,可以把它放在范围的起始位置,如 [-a-z],表示 -az 的所有字符。
  • 结束位置: 如果连字符在字符集的末尾,如 [a-z-],它表示az的所有字符和-字符。
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。这可能会导致在之后的 scanfgetchar 调用中,直接读取到换行符。如果需要处理换行符,可以在之后使用 getchar() 来消耗这个换行符。

可能大伙还是不懂,继续往下看:
假设你有以下代码:

char str[100];
scanf("%[a-zA-Z]", str);
  • 输入: hello\nworld
    • scanf("%[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格式说明符

  1. 不消耗输入: %n本身不消耗输入字符。它只是在内部计算并存储从输入流中已经读取的字符数。

  2. 存储读取字符的数量: %n会将到达它的位置为止读取的总字符数存储在其对应的参数中。这个参数必须是指向int类型的指针。

  3. 多个%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之后,scanf12345存储在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。所以,即使%nscanf中使用,它也不会影响scanf的返回值。

  • 与其他格式说明符的组合: scanf会按照顺序解析格式说明符,如果在使用%n之前的格式说明符解析失败,%n就不会被执行。

  • 可能的用途:

    • 输入格式检查: 可以通过检查读取的字符数来确保输入符合预期格式。
    • 精确输入解析: 当你需要知道输入的精确位置(如进行复杂的文本处理)时,可以使用%n

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2042092.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++竞赛初阶L1-11-第五单元-for循环(25~26课)510: T454422 均值

题目内容 给出一组样本数据&#xff0c;计算其均值。 输入格式 输入有两行&#xff0c;第一行包含一个整数&#xff0c;表示样本容量 n。 第二行包含 n 个浮点数 ai​&#xff0c;代表各个样本数据。 输出格式 输出一行&#xff0c;包含一个浮点数&#xff0c;表示均值。 …

TikTok爆款盘点-哪些产品会更受欢迎

海外短视频兴起&#xff0c;TikTok成为了国内企业出海最成功的APP。TikTok现在不仅是一个娱乐社交平台&#xff0c;也是一个强大的电商平台。如果出海卖家在选品上好好下功夫&#xff0c;利用TikTok这个营销工具&#xff0c;在海外也能获得不小的收益。 那么&#xff0c;TikTok…

网络协议十 应用层 SPDY / HTTP2 / QUIC / HTTP3

一 HTTP1.1 的不足 二 SPDY 协议 三 HTTP2 也只是需要在 server 端配置&#xff0c;不需要改动 服务器的代码。 HTTP2 可以看成是 将 SPDY 和 HTTP 融合在一起的改动 上面image sprites 的概念 HTTP2的问题--对头阻塞 和 握手延迟问题 引出的 QUIC 技术 由于传输层用的 TC…

node20+版本下hexo部署报错失败的解决办法

最近升级了node.js的版本&#xff0c;升到了最新的稳定版本v20.16.0&#xff0c;结果发现在该版本下hexo部署报错失败。本文记录了node20版本下hexo部署报错失败的解决办法。 一、报错信息 执行hexo的deploy部署命令 hexo d具体报错信息如下 INFO Deploying: git INFO Cl…

【大模型系列】更像人类行为的爬虫框架

随着大规模模型技术的兴起&#xff0c;我们可以看到百模大战、各种智能体、百花齐放的应用场景&#xff0c;那么作为一名前端开发者&#xff0c;以前端的视角&#xff0c;我们应当如何积极做好技术储备&#xff0c;开拓技术视野&#xff0c;在智能体时代保持一定的竞争力呢&…

webpack打包可视化分析之--webpack-bundle-analyzer

在开发一些项目的时候&#xff0c;有时候有些旧的框架项目用的webpacke打包慢&#xff0c;打包出来的包文件大&#xff0c;然而我们想要对它进行优化分析&#xff0c;有些旧的项目可能在不断迭代的过程中&#xff0c;有些模块功能改造或者有些需求变化&#xff0c;有些新需求模…

python的warnings.filterwarnings(“ignore“)

在python中运行代码经常会遇到的情况是——代码可以正常运行但是会提示警告&#xff0c;如果想要去掉这些警告&#xff0c;可以使用python的warnings.filterwarnings(“ignore”)函数。 代码&#xff1a; import warnings warnings.filterwarnings(ignore)看一下这个函数&…

【学习笔记】数据结构(五)

多维数组和广义表 文章目录 多维数组和广义表5.1 数组的定义5.2 数组的顺序表示和实现5.3 矩阵的压缩存储5.3.1 特殊矩阵5.3.2 稀疏矩阵三元组顺序表 (Triplet Representation) - 有序的双下标法行逻辑链接的顺序表十字链表法 5.4 广义表的定义5.5 广义表的存储结构5.6 m元多项…

mysql与Python交互

mysql数据库基本操作&#xff1a; [rootm ~]# tar -xf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz 解压压缩包 [rootm ~]# ls anaconda-ks.cfg mysql-5.7.44-linux-glibc2.12-x86_64 mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz [rootm ~]# cp -r mysql-5.7.44-linu…

【myz_tools】Python库 myz_tools:Python算法及文档自动化生成工具

写在前面 本来最开始只是单纯的想整理一下常用到的各类算法&#xff0c;还有一些辅助类的函数&#xff0c;方便时间短的情况下快速开发。后来发现整理成库更方便些&#xff0c;索性做成库&#xff0c;通过pip install 直接可以安装使用 关于库 平时见到的各类算法大多数还是…

volatile 浅谈

在Java中&#xff0c;volatile 关键字是一种轻量级的同步机制&#xff0c;它用于确保变量的可见性和有序性&#xff0c;但不保证原子性。当我们说 volatile 屏障时&#xff0c;我们实际上是在讨论 volatile 变量如何影响Java内存模型&#xff08;JMM&#xff09;中的操作重排序…

Vue3+vite+ts 项目使用mockjs

1、安装mockjs npm i mockjs 2、安装vite-plugin-mock npm i vite-plugin-mock -D 3、安装axios npm i axios 4.在src目录下创建mock文件夹,在文件夹内创建login.ts等文件&#xff0c;并在文件夹内放置以下内容&#xff08;注&#xff1a;URL要和真实请求地址保持一致&am…

使用html+css+js实现完整的登录注册页面

在这篇博客中&#xff0c;我们将讨论如何使用简单的 HTML 和 CSS 构建一个登录与注册页面。这个页面包含两个主要部分&#xff1a;登录界面和注册界面。我们还会展示如何通过 JavaScript 切换这两个部分的显示状态。 页面结构 我们将创建一个页面&#xff0c;其中包含两个主要…

DALL-E 2:重新定义图像生成的人工智能

DALL-E 2是一款先进的人工智能模型&#xff0c;它在图像生成领域取得了突破性进展。与前一代DALL-E相比&#xff0c;DALL-E 2能够以更高的分辨率和更精细的细节生成图像&#xff0c;同时还能更好地理解并处理复杂的文本描述。这意味着&#xff0c;用户可以通过输入描述性的文本…

⌈ 传知代码 ⌋ Visual SLAM函数

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

【扩散模型入门教程】

DDPM 从零实现代码&#xff1a;https://huggingface.co/blog/annotated-diffusion improved-diffusion&#xff0c;openai代码&#xff1a;https://github.com/openai/improved-diffusion diffusion_tutorial&#xff1a;https://github.com/sunlin-ai/diffusion_tutorial St…

RCE多种绕过技巧+贷齐乐漏洞复现

文章目录 1、RCE绕过2、贷齐乐的漏洞复现3、函数绕过 1、RCE绕过 <?php if(isset($_GET[code])){$code $_GET[code];if(strlen($code)>35){die("Long.");}if(preg_match("/[A-Za-z0-9_$]/",$code)){die("NO.");}eval($code); }else{hig…

医疗挂号管理系统

TOC springboot203医疗挂号管理系统 第一章 绪论 1.1 选题背景 目前整个社会发展的速度&#xff0c;严重依赖于互联网&#xff0c;如果没有了互联网的存在&#xff0c;市场可能会一蹶不振&#xff0c;严重影响经济的发展水平&#xff0c;影响人们的生活质量。计算机的发展&…

51单片机-LCD1602显示屏

简介 是一个液晶显示屏&#xff0c;通过电压对显示区域进行控制&#xff0c;有电就显示。 能够同时显示32个字符&#xff0c;分为两行&#xff0c;一行显示16个字符。可以显示的内容只能是字母、数字或者一些特殊符号。 使用ASCII码来让LCD1602来显示对应的字符。 电路图 …

HarmonyOS应用三之组件生命周期和参数传递

目录&#xff1a; 1、生命周期的执行顺序2、页面数据传递3、图片的读取4、数据的备份和恢复5、轮播图6、页面布局图 1、生命周期的执行顺序 /** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* yo…