Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 470|回复: 0

[默认分类] sscanf,sscanf_s及其相关用法

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-7-13 13:47:52 | 显示全部楼层 |阅读模式
    #include<stdio.h>
    定义函数 int sscanf (const char *str,const char * format,........);
    函数说明
    sscanf()会将参数str的字符串根据参数format字符串来转换并格式化数据。格式转换形式请参考scanf()。转换后的结果存于对应的参数内。
    返回值 成功则返回参数数目,失败则返回-1,错误原因存于errno中。 返回0表示失败    否则,表示正确格式化数据的个数    例如:sscanf(str,"%d%d%s", &i,&i2, &s);    如果三个变成都读入成功会返回3。    如果只读入了第一个整数到i则会返回1。证明无法从str读入第二个整数。
                main()
                {
                int i;
                unsigned int j;
                char input[ ]=”10 0x1b aaaaaaaa bbbbbbbb”;
                char s[5];
                sscanf(input,”%d %x %5[a-z] %*s %f”,&i,&j,s,s);
                printf(“%d %d %s ”,i,j,s);
                }
                执行 10 27 aaaaa
    大家都知道sscanf是一个很好用的函数,利用它可以从字符串中取出整数、浮点数和字符串等等。它的使用方法简单,特别对于整数和浮点数来说。但新手可能并不知道处理字符串时的一些高级用法,这里做个简要说明吧。
      1. 常见用法。
      charstr[512]={0};
      sscanf("123456","%s",str);
      printf("str=%s",str);
      2. 取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。
      sscanf("123456","%4s",str);
      printf("str=%s",str);
      3. 取到指定字符为止的字符串。如在下例中,取遇到空格为止字符串。
      sscanf("123456abcdedf","%[^]",str);
      printf("str=%s",str);
     4. 取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。
      sscanf("123456abcdedfBCDEF","%[1-9a-z]",str);
      printf("str=%s",str);
      5. 取到指定字符集为止的字符串。如在下例中,取遇到大写字母为止的字符串。
      sscanf("123456abcdedfBCDEF","%[^A-Z]",str);
      printf("str=%s",str);
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    可以用如下代码将字符串形式的ip地址转换为四个整数:


      char * inputIp  
      int ip[4];  
      sscanf_s(inputIp, "%d.%d.%d.%d", &ip[0], &ip[1],&ip[2],&ip[3]);  


          注意sscanf_s,当读入的类型是整数或其它长度可以确定的类型时,不能在类型后面跟上长度,但是对于字符串类型(char *)长度无法得知则必须在类型后面明确指出字符串的最大长度(即可以容纳的空间)。举例如下:


      // crt_sscanf_s.c  
      // This program uses sscanf_s to read data items  
      // from a string named tokenstring, then displays them.  
       
      #include <stdio.h>  
      #include <stdlib.h>  
       
      int main( void )  
      {  
         char  tokenstring[] = "15 12 14...";  
         char  s[81];  
         char  c;  
         int   i;  
         float fp;  
       
         // Input various data from tokenstring:  
         // max 80 character string plus NULL terminator  
         sscanf_s( tokenstring, "%s", s, _countof(s) );  
         sscanf_s( tokenstring, "%c", &c, sizeof(char) );  
         sscanf_s( tokenstring, "%d", &i );  
         sscanf_s( tokenstring, "%f", &fp );  
       
         // Output the data read  
         printf_s( "String    = %s\n", s );  
         printf_s( "Character = %c\n", c );  
         printf_s( "Integer:  = %d\n", i );  
         printf_s( "Real:     = %f\n", fp );  
      }  


          对于多个字符串读入的情况,代码如下:


      sscanf_s(inputString, "%s.%s.%s.%s", s1, s1.length, s2, s2.length, s3, s3.length, s4, s4.length);  



      sscanf 函数非常好用,居然我以前一直不知道这个函数。最近朋友用VS2008写程序时用到这个函数的安全版本 sscanf_s ,却出现异常问题,无法解析字符串不说,还会崩溃。
      int sscanf_s(
       const char *buffer,
       const char *format [,
          argument ] ...
    );
      这是MSDN里面关于函数的定义,没有继续详细查看后面的备注,以及实例的情况下。根本感觉不到sscanf 与 sscanf_s 的区别。以为仍然是像sscanf 一样使用,以致出现奇怪问题。
    1. Example:
    复制代码
    1. // crt_sscanf_s.c
    2. // This program uses sscanf_s to read data items
    3. // from a string named tokenstring, then displays them.
    4. #include <stdio.h>
    5. #include <stdlib.h>
    6. int main( void )
    7. {
    8.    char  tokenstring[] = "15 12 14...";
    9.    char  s[81];
    10.    char  c;
    11.    int   i;
    12.    float fp;
    13.    // Input various data from tokenstring:
    14.    // max 80 character string plus NULL terminator
    15.    sscanf_s( tokenstring, "%s", s, _countof(s) );
    16.    sscanf_s( tokenstring, "%c", &c, sizeof(char) );
    17.    sscanf_s( tokenstring, "%d", &i );
    18.    sscanf_s( tokenstring, "%f", &fp );
    19.    // Output the data read
    20.    printf_s( "String    = %s\n", s );
    21.    printf_s( "Character = %c\n", c );
    22.    printf_s( "Integer:  = %d\n", i );
    23.    printf_s( "Real:     = %f\n", fp );
    24. }
    复制代码
    1. 直到看完整个文档,看到这个实例,才发现原来还有猫腻!sscanf_s 取值的时候,需要在每个取值后面指定取值的最大大小。
    复制代码





    在使用VS2005编译一个程序时,出现了很多警告,说是用的函数是不安全的,应当使用安全版本,即函数名称增加“_s”的版本。

    警告内容:
    warning C4996: "sscanf": This function or variable may be unsafe. Consider using sscanf_s instead.

    据了解,“_s”版本函数是微软后来对c++做得扩展,用来替代原先不安全的函数,例如:printf、scanf、strcpy、fopen等等。
    详细参考:
    ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_vccrt/HTML/d9568b08-9514-49cd-b3dc-2454ded195a3.htm
    原来安全版本的函数,对参数和缓冲边界做了检查,增加了返回值和抛出异常。这样增加了函数的安全性,减少了出错的几率。
    同时这也意味着在使用这些函数时,有时你不得不输入更多的关于缓冲区大小的参数,多敲几下键盘能换来更少的麻烦,值得!
    下面总结了sscanf的以及sscanf_s的常用方法,也体现了“_s”版本函数与原函数的特别之处:
    1、sscanf和scanf的不同是输入来源,前者是一个字符串,后者则是标准输入设备
    2、sscanf的使用,以解析时间字符串为例,将字符串“2009-01-02_11:12:13”解析为整型年月日时分秒
    //定义
    char cc;
    tm tm_temp={0};
    string stime("2009-01-02_11:12:13");
    //(1) 必须严格按照分隔符形式匹配填写,若遇到不匹配项则终止解析


    sscanf(stime.c_str(), "%4d-%2d-%2d_%2d:%2d:%2d",
      &tm_temp.tm_year,
      &tm_temp.tm_mon,
      &tm_temp.tm_mday,
      &tm_temp.tm_hour,
      &tm_temp.tm_min,
      &tm_temp.tm_sec
      );
      
    //(2) 可以不按照分割符号形式填写,字符数必须一致,例如可以正确解析“2009/01/02_11:12:13”


    sscanf(stime.c_str(), "%4d%c%2d%c%2d%c%2d%c%2d%c%2d",
      &tm_temp.tm_year, &cc,
      &tm_temp.tm_mon, &cc,
      &tm_temp.tm_mday, &cc,
      &tm_temp.tm_hour, &cc,
      &tm_temp.tm_min, &cc,
      &tm_temp.tm_sec
      );

    //(3) 可以不按照分割符号形式填写,字符数必须一致,同上,%1s可以等同于%c

    sscanf(stime.c_str(), "%4d%1s%2d%1s%2d%1s%2d%1s%2d%1s%2d",
      &tm_temp.tm_year, &cc,
      &tm_temp.tm_mon, &cc,
      &tm_temp.tm_mday, &cc,
      &tm_temp.tm_hour, &cc,
      &tm_temp.tm_min, &cc,
      &tm_temp.tm_sec
      );
    //(4) 可以不按照分割符形式和数量填写,类型必须一致,例如可以正确解析“2009/01/02___11:12:13”
    //这里使用了sscanf的正则表达式,与通用的正则表示类似但不完全相同,%*c表示忽略连续多个字符


    sscanf(stime.c_str(), "%4d%*c%2d%*c%2d%*c%2d%*c%2d%*c%2d",
      &tm_temp.tm_year,
      &tm_temp.tm_mon,
      &tm_temp.tm_mday,
      &tm_temp.tm_hour,
      &tm_temp.tm_min,
      &tm_temp.tm_sec
      );
      
    3、sscanf_s的使用
      //定义
    char cc[2];
    tm tm_temp={0};
    string stime("2009-01-02_11:12:13");
    //(1) 与sscanf第一种方法相同,可以使用"%4d-%2d-%2d_%2d:%2d:%2d"格式匹配解析


    sscanf_s(stime.c_str(), "%4d-%2d-%2d_%2d:%2d:%2d",
       &tm_temp.tm_year,
       &tm_temp.tm_mon,
       &tm_temp.tm_mday,
       &tm_temp.tm_hour,
       &tm_temp.tm_min,
       &tm_temp.tm_sec
       );
      
    //(2) 使用%c格式对数据解析时,必须对相应的缓冲区增加长度参数,否则将会出错

    sscanf_s(stime.c_str(), "%4d%c%2d%c%2d%c%2d%c%2d%c%2d",
      &tm_temp.tm_year, &cc, 1,
      &tm_temp.tm_mon, &cc, 1,
      &tm_temp.tm_mday, &cc, 1,
      &tm_temp.tm_hour, &cc, 1,
      &tm_temp.tm_min, &cc, 1,
      &tm_temp.tm_sec
      );
      
    //(3) 使用%s格式对数据解析时,缓冲长度必须大于字符串长度,否则不予解析

    sscanf_s(stime.c_str(), "%4d%1s%2d%1s%2d%1s%2d%1s%2d%1s%2d",
       &tm_temp.tm_year, &cc, 2,
       &tm_temp.tm_mon, &cc, 2,
       &tm_temp.tm_mday, &cc, 2,
       &tm_temp.tm_hour, &cc, 2,
       &tm_temp.tm_min, &cc, 2,
       &tm_temp.tm_sec
       );
    //(4) 与sscanf一样,sscanf_s同样支持正则表达式

    sscanf_s(stime.c_str(), "%4d%*c%2d%*c%2d%*c%2d%*c%2d%*c%2d",
      &tm_temp.tm_year,
      &tm_temp.tm_mon,
      &tm_temp.tm_mday,
      &tm_temp.tm_hour,
      &tm_temp.tm_min,
      &tm_temp.tm_sec
      );
      
    通过以上对比sscanf与sscanf_s的使用,可以看出后者对缓冲区安全有了更多的考虑,从而避免了许多不经意的烦恼。
    大家都知道sscanf是一个很好用的函数,利用它可以从字符串中取出整数、浮点数和字符串等等。它的使用方法简单,特别对于整数和浮点数来说。但新手可能并不知道处理字符串时的一些高级用法,这里做个简要说明吧。
      1. 常见用法。

      
       
        以下是引用片段:
      char str[512] = ;
      sscanf("123456 ", "%s", str);
      printf("str=%sn", str);
       
      

      2. 取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。

      
       
        以下是引用片段:
      sscanf("123456 ", "%4s", str);
      printf("str=%sn", str);
       
      

      3. 取到指定字符为止的字符串。如在下例中,取遇到空格为止字符串。

      
       
        以下是引用片段:
      sscanf("123456 abcdedf", "%[^ ]", str);
      printf("str=%sn", str);
       
      

      4. 取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。

      
       
        以下是引用片段:
      sscanf("123456abcdedfBCDEF", "%[1-9a-z]", str);
      printf("str=%sn", str);
       
      

      5. 取到指定字符集为止的字符串。如在下例中,取遇到大写字母为止的字符串。


    以下是引用片段:

      sscanf("123456abcdedfBCDEF", "%[^A-Z]", str);

      printf("str=%sn", str);
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-20 12:04 , Processed in 0.350911 second(s), 38 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表