27 C 语言标准库 <stdio.h> 中的两个字符串函数:sprintf、sscanf,不同编码方式的中文字符长度

目录

1 sprintf

1.1 函数原型

1.2 功能说明

1.3 案例演示

1.4 注意事项

2 sscanf

2.1 函数原型

2.2 功能说明

2.3 案例演示

2.4 使用 %s 解析字符串的易错点

2.4.1 空白符问题

2.4.2 顺序问题

2.4.3 中文字符长度问题

2.5 注意事项


1 sprintf

1.1 函数原型

        sprintf 函数是 C 语言标准库中的一个函数,用于将格式化的数据写入字符串。其函数原型定义在 <stdio.h> 头文件中。

#include <stdio.h>  
int sprintf(char *str, const char *format, ...);
  • 参数:
    • char *str:指向一个字符数组的指针,该数组足够大以存储生成的格式化字符串。这个数组必须已经分配了足够的空间来容纳结果字符串,包括结尾的空字符(\0)。
    • const char *format:一个格式字符串,用于指定后续参数如何被格式化和插入到结果字符串中。这个字符串可以包含文本、格式说明符(如 %d、%s、%f 等),以及转义序列(如 \n、\t 等),同 printf 函数的使用。
    • ...:可变数量的参数,其类型和数量由 format 字符串中的格式说明符决定,同 printf 函数的使用。这些参数将被格式化为字符串,并插入到 str 指向的数组中。
  • 返回值:成功时,sprintf 返回写入的字符数(不包括结尾的空字符)。如果发生错误,则可能返回负值,但这种情况在实际应用中较为罕见。

1.2 功能说明

        sprintf 函数的主要功能是将格式化的数据写入到字符串中,而不是像 printf 那样输出到标准输出设备(通常是屏幕)。这使得 sprintf 非常适用于需要生成格式化字符串并存储在变量中的场景。

        与 printf 相比,sprintf 多了一个参数,即第一个参数是要写入的目标字符串,而后面的参数与 printf 保持一致

        简而言之,sprintf 是将内容写入字符串而不是直接输出

1.3 案例演示

#include <stdio.h>int main()
{char buffer[256]; // 分配一个足够大的缓冲区来存储结果字符串int num1 = 123;float num2 = 456.78f;char ch = 'A';char str[] = "Hello, World!";int result;// 使用 sprintf 将格式化的数据写入 buffer// 注意:返回值是写入的字符数(不包括'\0')result = sprintf(buffer, "Integer: %d, Float: %.2f, Character: %c, String: %s.\n", num1, num2, ch, str);// 输出生成的字符串printf("使用 sprintf 生成的字符串:\n%s", buffer);// 输出 sprintf 的返回值printf("sprintf 的返回值(一般不适用它): %d\n", result);return 0;
}

        输出结果如下所示:

1.4 注意事项

        缓冲区溢出:在使用 sprintf 时,必须确保目标字符串数组 str 有足够的空间来存储生成的字符串,包括末尾的空字符 '\0'。否则,可能会导致缓冲区溢出,这是一个严重的安全问题。

        返回值检查:虽然 sprintf 的返回值(写入的字符数)在大多数情况下可能不是必需的,但在某些情况下,检查返回值可以帮助识别潜在的错误或溢出情况。

        性能考虑:在性能敏感的应用中,频繁使用 sprintf 可能会引入不必要的开销,因为它涉及到字符串的复制和格式化操作。在这种情况下,可能需要考虑使用更高效的字符串处理函数或方法。


2 sscanf

2.1 函数原型

        sscanf 函数是 C 语言标准库中的一个函数,用于从字符串中读取格式化的输入。它的函数原型定义在 <stdio.h> 头文件中。函数原型如下:

#include <stdio.h>  
int sscanf(const char *str, const char *format, ...);
  • 参数:
    • const char *str:指向要扫描的字符串的指针
    • const char *format:一个格式字符串,指定了后续参数应该如何从 str 中被解析这个字符串可以包含文本、格式说明符(如 %d、%s、%f 等)以及空白符(空格、制表符等),用于分隔输入项
    • ...:可变数量的参数,这些参数指向变量的地址sscanf 将根据 format 字符串中的格式说明符,从 str 中解析出数据,并存储到这些变量中
  • 返回值:
    • 成功时,sscanf 返回成功匹配并赋值的输入项的数量
    • 如果遇到输入结束或遇到格式错误前没有匹配任何输入项,则返回 0
    • 如果发生读取错误,则返回 EOF

2.2 功能说明

        sscanf 函数模仿了 scanf 的行为,不过它是从字符串而非标准输入中读取数据,这使其特别适合解析具有特定格式的字符串内容。sscanf 支持多种数据类型,例如整数、浮点数和字符串,通过格式化字符串来指导数据的解析方式

        相较于 scanf,sscanf 额外需要一个参数,即要从中提取数据的字符串,而其余参数则与 scanf 相同。

        简而言之,sscanf 的功能是从字符串中按照指定格式提取数据

2.3 案例演示

#include <stdio.h>int main()
{char input[] = "整数:123,浮点数:456.78,字符串:Hello,World!";int intValue;float floatValue;char stringValue[50];// 尝试从 input 中解析一个整数、一个浮点数和一个字符串// 如果使用下面这行代码,sscanf 不会成功读取,因为指定格式不对!!!// int numItemsRead = sscanf(input, "%d %f %s", &intValue, &floatValue, stringValue);// 格式要严格匹配!!!int numItemsRead = sscanf(input, "整数:%d,浮点数:%f,字符串:%s", &intValue, &floatValue, stringValue);// 检查是否成功读取了三个项if (numItemsRead == 3){printf("成功解析:\n");printf("整数: %d\n", intValue);printf("浮点数: %.2f\n", floatValue);printf("字符串: %s\n", stringValue);}else{// 如果未成功读取三个项,则输出错误信息printf("解析失败或格式不匹配,读取的项数: %d\n", numItemsRead);}return 0;
}

        输出结果如下所示:

2.4 使用 %s 解析字符串的易错点

2.4.1 空白符问题

         在 C 语言中使用 sscanf 函数解析字符串时,%s 格式化符会读取直到遇到第一个空白字符(如空格、制表符、换行符等)为止的字符序列,并将其存储到指定的字符数组中。因此所解析的字符串中不能含有空白符,不然只会读取到第一个空白符之前的数据,如下所示:

#include <stdio.h>int main()
{char input[] = "整数:123,浮点数:456.78,字符串:Hello    World!";int intValue;float floatValue;char stringValue[50];// 尝试从 input 中解析一个整数、一个浮点数和一个字符串// 注意,这里的字符串中有空白符:Hello    World!int numItemsRead = sscanf(input, "整数:%d,浮点数:%f,字符串:%s", &intValue, &floatValue, stringValue);// 检查是否成功读取了三个项if (numItemsRead == 3){printf("成功解析:\n");printf("整数: %d\n", intValue);printf("浮点数: %.2f\n", floatValue);printf("字符串: %s\n", stringValue);}else{// 如果未成功读取三个项,则输出错误信息printf("解析失败或格式不匹配,读取的项数: %d\n", numItemsRead);}return 0;
}

        输出结果如下所示:

2.4.2 顺序问题

        由于 %s 格式化符会读取直到遇到第一个空白字符(如空格、制表符、换行符等)为止的字符序列,并将其存储到指定的字符数组中。这可能导致在解析后续数据(如整数和浮点数)时出现问题,直接将后面所有的(第一个空白符之前)的数据当做一个字符串整体。

#include <stdio.h>int main()
{char input[] = "字符串:Hello,World!,整数:123,浮点数:456.78";int intValue;float floatValue;char stringValue[50];// 尝试从 input 中先解析一个字符串,再解析一个整数和一个浮点数// 注意,这里首先解析的是字符串,%s 会把后面所有的(第一个空白符之前)的数据当做一个字符串整体int numItemsRead = sscanf(input, "字符串:%s,整数:%d,浮点数:%f", stringValue, &intValue, &floatValue);// 检查是否成功读取了三个项if (numItemsRead == 3){printf("成功解析:\n");printf("整数: %d\n", intValue);printf("浮点数: %.2f\n", floatValue);printf("字符串: %s\n", stringValue);}else{// 如果未成功读取三个项,则输出错误信息printf("解析失败或格式不匹配,读取的项数: %d\n", numItemsRead);printf("读取到的字符串是:%s\n", stringValue);}return 0;
}

        输出结果如下所示: 

解决办法:   

        如果知道字符串的最大可能长度,可以使用指定宽度的 %s 读取固定数量的字符。但是,这要求确切知道字符串的最大长度(但是,1 个中文字符所占大小不是 1 个字节),并且输入数据不会超过这个长度。 

#include <stdio.h>int main()
{char input[] = "字符串:Hello,World!,整数:123,浮点数:456.78";int intValue;float floatValue;char stringValue[50];// 尝试从 input 中先解析一个字符串,再解析一个整数和一个浮点数// 注意,这里首先解析的是字符串,%s 会把后面所有的(第一个空白符之前)的数据当做一个字符串整体// 解决办法:如果知道字符串的最大可能长度,可以使用指定宽度的 %s 读取固定数量的字符,如下面:%12sint numItemsRead = sscanf(input, "字符串:%12s,整数:%d,浮点数:%f", stringValue, &intValue, &floatValue);// 检查是否成功读取了三个项if (numItemsRead == 3){printf("成功解析:\n");printf("整数: %d\n", intValue);printf("浮点数: %.2f\n", floatValue);printf("字符串: %s\n", stringValue);}else{// 如果未成功读取三个项,则输出错误信息printf("解析失败或格式不匹配,读取的项数: %d\n", numItemsRead);printf("读取到的字符串是:%s\n", stringValue);}return 0;
}

        输出结果如下所示:

2.4.3 中文字符长度问题

        GBK 编码是在 GB2312 编码的基础上扩展而来的,它包含了 GB2312 字符集中的全部 6763 个汉字,并增加了 14240 个汉字、生僻字等,总共包含了 21886 个字符。由于这些字符的数量仍然远小于 2^16(即 65536),因此 GBK 编码采用两个字节来表示一个中文字符

        然而,在 UTF-8 编码中,一个中文字符的字节数并不是固定的。UTF-8 是一种针对 Unicode 的可变长度字符编码,它可以用 1 到 4 个字节表示一个符号,根据不同的符号而变化字节长度。对于常用的汉字,UTF-8 编码通常使用 3 个字节来表示,但也有一些扩展区的汉字可能需要 4 个字节。具体来说,UTF-8 编码中的汉字字节数取决于该汉字在 Unicode 编码中的位置。

        在 VS Code 中,我们可以通过,将对应的中文字符串存放到字符数组中,然后使用 strlen 方法计算其长度(不包括空字符),或者通过鼠标悬浮的方式直接查看字符串字节数(字符串长度 + 1),如下所示:

        知道了字符串的长度,就可以通过 %s 指定宽度,进行字符串的解析:

#include <stdio.h>
#include <string.h>int main()
{char input[] = "字符串:第一个解析字符串,但是不知道我的长度大小!,整数:123,浮点数:456.78";int intValue;float floatValue;char stringValue[100];char chinese[] = "第一个解析字符串,但是不知道我的长度大小!";int chineseLen = strlen(chinese);printf("这个中文字符串的长度为:%d\n", chineseLen); // 59(不包括结尾的空字符)char chinese2[] = "鼠标悬浮看我多长";// 尝试从 input 中先解析一个字符串,再解析一个整数和一个浮点数// 注意,这里首先解析的是字符串,%s 会把后面所有的(第一个空白符之前)的数据当做一个字符串整体// 解决办法:如果知道字符串的最大可能长度,可以使用指定宽度的 %s 读取固定数量的字符,如下面:%59sint numItemsRead = sscanf(input, "字符串:%59s,整数:%d,浮点数:%f", stringValue, &intValue, &floatValue);// 检查是否成功读取了三个项if (numItemsRead == 3){printf("成功解析:\n");printf("整数: %d\n", intValue);printf("浮点数: %.2f\n", floatValue);printf("字符串: %s\n", stringValue);}else{// 如果未成功读取三个项,则输出错误信息printf("解析失败或格式不匹配,读取的项数: %d\n", numItemsRead);printf("读取到的字符串是:%s\n", stringValue);}return 0;
}

         输出结果如下所示:

2.5 注意事项

        缓冲区溢出:与 scanf 类似,sscanf 不会检查目标变量的大小,可能会导致缓冲区溢出。因此,在使用时应当确保目标变量有足够的空间来存储解析的数据

        格式匹配sscanf 严格根据格式字符串进行匹配。如果格式字符串与输入字符串不匹配,sscanf 可能无法正确解析数据

        字符串的解析问题注意空白符、字符串的读取顺序、中文字符长度等问题

        返回值检查:始终检查 sscanf 的返回值,以确保正确读取了预期数量的输入项。如果返回值小于预期,可能表示输入数据不符合预期格式。

        灵活性:虽然 sscanf 提供了从字符串中解析数据的灵活性,但在处理复杂或不规则的输入格式时,可能需要结合使用其他字符串处理函数(如 strtok、strchr 等)来辅助解析。

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

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

相关文章

求恰好为k 的区间数量(滑动窗口进阶版)

前言&#xff1a;之前做的滑动窗口都是可以直接一遍过&#xff0c;然后每次右边确定了以后&#xff0c;左边不断缩小寻找最优解 但是这个题目呢我们不仅要保证我们的辅音字母的个数恰好为k&#xff0c;其他元音字母的个数只要每个都出现了就行&#xff0c;这个就导致我们不能用…

【IEEE PDF eXpress】格式不对

目录 一、问题二、解决方法 一、问题 word的文档&#xff0c;用IEEE PDF eXpress网站生成pdf后&#xff0c;提交论文出现错误&#xff1a; Document validation failed due to the following errors: Content exceeds IEEE template margins for its format (Page 1:Bottom).…

Java_TestNg

TestNg 前言支持特性 使用步骤1.引入库 常用注解Test注解BeforeSuite AfterSuiteAfterClass BeforeClassAfterTest BeforeTestAfterGroups BeforeGroupsBeforeMethod AfterMethodDataProviderFactoryListenersPatameters断言相等 不相等true/falsenull / !nullequals / !equals…

Leetcode 887. 鸡蛋掉落

1.题目基本信息 1.1.题目描述 给你 k 枚相同的鸡蛋&#xff0c;并可以使用一栋从第 1 层到第 n 层共有 n 层楼的建筑。 已知存在楼层 f &#xff0c;满足 0 < f < n &#xff0c;任何从 高于 f 的楼层落下的鸡蛋都会碎&#xff0c;从 f 楼层或比它低的楼层落下的鸡蛋都…

AIGC时代,大模型微调如何发挥最大作用?

人工智能的快速发展推动了大模型的广泛应用&#xff0c;它们在语言、视觉、语音等领域的应用效果已经越来越好。但是&#xff0c;训练一个大模型需要巨大的计算资源和时间&#xff0c;为了减少这种资源的浪费&#xff0c;微调已经成为一种流行的技术。微调是指在预训练模型的基…

DVWA | File Inclusion(文件包含)渗透测试

概念&#xff1a; 漏洞产生原因&#xff1a; 主要是由于开发人员没有对用户输入的文件路径进行严格的过滤和验证。例如&#xff0c;如果一个 Web 应用程序接受用户输入的文件路径&#xff0c;然后使用这个路径进行文件包含&#xff0c;而没有对用户输入进行任何检查&#xff0c…

【笔记】数据结构12

文章目录 2013年408应用题41方法一方法二 看到的社区的一个知识总结&#xff0c;这里记录一下。 知识点汇总 2013年408应用题41 解决方法&#xff1a; 方法一 &#xff08;1&#xff09;算法思想 算法的策略是从前向后扫描数组元素&#xff0c;标记出一个可能成为主元素的元…

【YOLO目标检测二维码数据集】共3112张、已标注txt格式、有训练好的yolov5的模型

目录 说明图片示例 说明 数据集格式&#xff1a;YOLO格式 图片数量&#xff1a;3112 标注数量(txt文件个数)&#xff1a;3112 标注类别数&#xff1a;1 标注类别名称&#xff1a;qrcode 数据集下载&#xff1a;二维码数据集 图片示例 数据集图片&#xff1a; 数据集…

yolov8/9/10模型在垃圾分类检测中的应用【代码+数据集+python环境+GUI系统】

yolov8/9/10模型在垃圾分类检测中的应用【代码数据集python环境GUI系统】 yolov8/9/10模型在垃圾分类检测中的应用【代码数据集python环境GUI系统】 背景意义 随着计算机视觉技术和深度学习算法的快速发展&#xff0c;图像识别、对象检测、图像分割等技术在各个领域得到了广泛…

C++类和对象(下) 初始化列表 、static成员、友元、内部类等等

1.再探构造函数 之前使用构造函数时都是在函数体内初始化成员变量&#xff0c;还有一种构造函数的用法&#xff0c;叫做初始化列表&#xff1b;那么怎么使用呢&#xff1f; 使用方法用冒号开始(" : ")要写多个就用逗号(" , ")隔开数据成队列每个成员变量后…

谷歌收录批量查询,如何批量查询谷歌收录以及提交网站进行收录的方法

在SEO优化过程中&#xff0c;了解并监控网站在谷歌搜索引擎中的收录情况至关重要。本文将详细介绍如何批量查询谷歌收录以及提交网站进行收录的方法&#xff0c;帮助网站管理员和SEO专家更有效地管理和优化网站。 一、谷歌收录批量查询方法 1.使用搜索引擎的site指令 …

前端考核总结

目录 JavaScript的基本数据类型有哪些&#xff1f;JavaScript中数据类型的检测方法JavaScript如何判断对象中的属性存在自身还是原型链上flex布局HTML5新标签Vue的基本概念Vue生命周期JavaScript中闭包的基本概念防抖节流双等号与三等号的区别显式转换 JavaScript的基本数据类型…

fastadmin搜索刷新列表,怎么限制用户频繁点击?

文章目录 fastadmin搜索刷新列表&#xff0c;怎么限制用户频繁点击&#xff1f;解决方案fastadmin事件方法实现完结 fastadmin搜索刷新列表&#xff0c;怎么限制用户频繁点击&#xff1f; fastadmin目前有个很致命的问题&#xff0c;就是用户可以频繁的点击搜索等按钮&#xf…

Qt --- 界面优化 --- QSS和绘图API

界面优化 》美化 一个程序的界面是否好看&#xff0c;是否重要呢。 有些面向专业领域的程序&#xff0c;界面好看与否&#xff0c;不是看关键&#xff0c;更关键的是实际的效果。有些面向普通用户领域的程序&#xff0c;界面好看&#xff0c;还是很大的加分项。 界面优化 Qt…

奖金高达 110 万元,Spatial Joy 2024 全球 AR 应用开发大赛启动

今年是AR应用开发大赛第三届&#xff0c;恰逢Rokid成立十周年&#xff0c;我们推出全新的大赛品牌“Spatial Joy”&#xff0c;引领开发者享受开发乐趣&#xff0c;为其打造充满挑战和惊喜的开发之旅&#xff0c;逐渐成为空间计算时代全球最大AR应用开发大赛。回顾大赛发展&…

PCB敷铜敷不了相同网络的线怎么办?

图片上的情况就是今天需要讲的内容&#xff0c;可以看出出来的线头是GND,敷的铜也是GND但是相同网络就是不能连在一起。 解释&#xff1a; 这是因为我们敷铜的时候属性选的是连接相同的net,如图所示&#xff1a; 解决办法&#xff1a; 只需要设置改为相同的Object就可以了&…

STM32+ADC+扫描模式

1 ADC简介 1 ADC(模拟到数字量的桥梁) 2 DAC(数字量到模拟的桥梁)&#xff0c;例如&#xff1a;PWM&#xff08;只有完全导通和断开的状态&#xff0c;无功率损耗的状态&#xff09; DAC主要用于波形生成&#xff08;信号发生器和音频解码器&#xff09; 3 模拟看门狗自动监…

高效的视频压缩标准H.264介绍,以及H.264在视频监控系统中的应用

目录 一、概述 二、 工作原理 三、技术特点与优势 1、高效压缩率 2、高质量视频 3、错误恢复能力 4、灵活性 四、编解码过程 1、编码过程 2、解码过程 五、帧类型与结构 1、I帧 2、P帧 3、B帧 六、应用与优势 1、节省存储空间和带宽 2、提高视频质量 3、适应…

2024大二上js高级+ES6学习9.29(深/浅拷贝,正则表达式,let/const,解构赋值,箭头函数,剩余参数)

9.29.2024 1.浅拷贝和深拷贝 Es6的语法糖&#xff1a;用assign将obj对象浅拷贝给o对象。 把数组写在前面是因为数组也是对象 2.正则表达式 创建和检测正则表达式 正则表达式的使用直接跳过&#xff0c;等要用时现查现用 3.ES6 4.let关键字 块级作用域是指在一个{}l里 变量提…

File 和 Blob两个对象有什么不同

Blob 在 JavaScript 中&#xff0c;Blob&#xff08;Binary Large Object&#xff09;对象用于表示不可变的、原始的二进制数据。它可以用来存储文件、图片、音频、视频、甚至是纯文本等各种类型的数据。Blob 提供了一种高效的方式来操作数据文件&#xff0c;而不需要将数据全…