scanf类函数的使用

sscanf函数

#include <stdio.h>

sscanf()函数用于从字符串中读取指定格式的数据,其原型如下:

int sscanf (char *str, char * format [, argument, ...]);

【参数】参数str为要读取数据的字符串;format为用户指定的格式;argument为变量,用来保存读取到的数据。 【返回值】成功则返回参数数目,失败则返回-1,错误原因存于errno 中。 sscanf()会将参数str 的字符串根据参数format(格式化字符串)来转换并格式化数据(格式化字符串请参考scanf()), 转换后的结果存于对应的变量中。 sscanf()与scanf()类似,都是用于输入的,只是scanf()以键盘(stdin)为输入源,sscanf()以固定字符串为输入源。

如果想要实现某一种用法,直接百度一下就行了。但是如果想随心所用,咱们看下原理。 先看下原理,和scanf()一样。 scanf默认从第一个非空格的可显示字符开始读,读到下一个空格分解符为止,enter键结束输入。 例子说明: #include <stdio.h> #include <string.h> #include <stdlib.h>

void main() { printf("plz enter:\n"); char buf[64] = {0}; scanf("%s",buf); printf("%s",buf); } /* 输入:[空格]test[空格]123[回车] 输出:test 输入:[tab]test[tab]123[回车] 输出:test / 改一下 变成同时录入两个字符串 void main() { printf("plz enter:\n"); char buf[64] = {0}; char buf1[64] = {0}; scanf("%s%s",buf,buf1); printf("%s%s",buf,buf1); } /* 输入:[空格]test[空格]123[回车] 输出:test123 输入:[tab]test[tab]123[回车] 输出:test123 / 这就说明,scanf类函数的默认操作就是以空白符做分界线,然后读取其中的个字段。这里拿的是scanf举例,如果验证sscanf其实原理一样,改个输入就好,比如上面例子验证sscanf就可以写为: void main() { const char enter[128] = " test 123"; //输入从键盘换成字符串,用来验证sscanf printf("plz enter:\n"); char buf[64] = {0}; char buf1[64] = {0}; sscanf(enter,"%s%s",buf,buf1); printf("%s%s",buf,buf1); }

不禁想到如果要使用其他定界符,那处理字符串不就更方便了么?!

下面开始进阶: 进阶的主要内容就是 %[] 下面的操作都需要由它来实现,这个%[]就是一个字符集的意思。

sscanf("123abcABC456defDEF","%[123acA]",str); 这个得到 str: 123a

%[] 我个人理解,他已经隐含了有%s的意思,就是说取[]之内的字符集的字符串,一旦有字符在字符集之外就停止。 所以上面例子中,在"123abcABC456defDEF"中从字符串首端开始取字符集"%[123acA]中的内容,当取到‘b’字母时为非字符集中字符,就停止操作。所以str中就是123a。 按照这个逻辑,现在去取多个字串: sscanf("123abcABC456defDEF","%[123acA]%[bcAC]",str1,str2); 在运行之前,可以估计到,str1取到‘b’时超出字符集%[123acA]范围,str1为"123a"。 接着会取str2,如果从‘b’开始取,取到‘B’时超出字符集%[bcAC]范围,那么str2就是"bcA" 使用实例代码验证,结果和预期相同。 另外: 如果sscanf("123abcABC456defDEF","%[23abcABC456defDEF]",str); 结果是str为空。 因为字符串开始的第一个字符‘1’不在集合%[23abcABC456defDEF]中,str什么都取不到

和处理其他集合一样,%[]也有取反或者叫取补集的操作, 就是%[^]。 同样是上面的例子,加个^ 如果sscanf("123abcABC456defDEF","%[^23abcABC456defDEF]",str); 结果是str为 “1” 意思是,在字符串"123abcABC456defDEF"中,取“23abcABC456defDEF”之外的字符,一旦遇到不是“23abcABC456defDEF”之外的字符就停止。 换句话说,加了^过后,“23abcABC456defDEF“就成了定界符了,只要遇到定界符中的一个就停止。 默认情况的sscanf(in_str,"%s",out_str) 和sscanf(in_str,"%[^ \n\t]",out_str) //注意^后面有个空格,表示分界符为空格 制表符 回车中的一个 是等价的。 但是sscanf(in_str,"%s%s",out_str1,out_str2) 和sscanf(in_str,"%[^ \n\t]%[^ \n\t]",out_str1,out_str2)不是等价的,请自行琢磨。 类似的可以自行实现读取int char等类型的scanf原型。

如果看到%[a-zA-Z1-9],表示字符集为所有小写字母,所有大写字母,所有数字。‘:’就剩这些符号了。可以拆开为%[1-9]单独使用。

对定界符的说明就到这里,下面再说明一下,匹配格式的一些操作。 sscanf (char *str, char * format [, argument, ...]);就是这里面的format 比如sscanf("123 +456","%s+%s",str1,str2); 结果就是str1 = 123 str2 = 456 逻辑就是:开始检查"123 +456",使用默认空格结束符,匹配到123赋值给str1,然后指针跳到空格后,开始从+456 开始匹配,然后匹配到"%s+%s"中的+号,指针跳到加号后,赋值最后的456给str2。 如果sscanf("123 +456","%s-%s",str1,str2); str1=123 str2=空。原因是-号没匹配到。

再一个是%*,%*可以跳过这个数据不读。比如 如果sscanf("123 +456","%s%*c%s",str1,str2); str1= 123 str2=456 中间的+被%*c跳过。 %*c表示跳过一个字符不读。

有了上面的基础,下面来处理一条复杂的字符串: Line 1820: { "parameter": "InternetGateway", "fault_code": "9005", "value": "", "type": "xsd:string" } 目标,读取parameter的值,也就是InternetGateway,假设这个值是会变化的,也就是说你无法预知这个InternetGateway具体是什么字符串。现在来编写,format 首先以‘:’和‘,’作为定界符 就可以写成%[^:,] 以什么为定界符,就以%[^]的形式写。 然后我们需要的数据在第三节,注意定界符本身也需要处理 就可以写成,sscanf(in_str,"%[^:]:%[^:]: %[^,]",out_str); 说明一下: 第一个%*[^:,] 表示,处理到字符串的“Line 1820”,号表示跳过它 然后‘:’处理掉“Line 1820:”中的‘:’ 第二个[^:] 同理处理到”Line 1820: { "parameter"“ 并跳过它 然后: 处理到 Line 1820: { "parameter": 第三个%[^,]就以InternetGateway,最后的,为定界符,并把中间的值存下来。 结果"InternetGateway"

最后sscanf有一个不安全的地方就是 sscanf(in_str,"%s",out_str); 如果in_str的长度,大于out_str的长度就容易内存溢出。 这个时候可以使用%+长度的方式限制。 in_str[1024]; out_str[512 比如sscanf(in_str,"%512s",&out_str); 再或者使用sscanf_s安全函数。

转载于:https://my.oschina.net/u/3426905/blog/1595090

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值