• 你的sscanf用对了吗


    用sscanf解析输入字符串

    我们平常编写的很多应用程序都会处理各种各样的输入,这些输入或来自本地文件,或来自网络,或来自用户的输入。今天,让我们来看看sscanf这个和字符串相关的函数可能给你带来的麻烦。

    下面是演示代码,这段代码将一些以字符串形式保存的数据加载到程序中。这些字符串可以来自任何地方,本演示代码对字符串进行了硬编码。

     1 struct Data
     2 {
     3     char item1;
     4     char item2;
     5     char item3;
     6     char item4;
     7 };
     8 
     9 int main()
    10 {
    11     Data data;
    12     memset(&data, 0, sizeof(data));
    13 
    14     char data1[] = "1";
    15     char data2[] = "2";
    16     char data3[] = "3";
    17     char data4[] = "4";
    18 
    19     sscanf_s(data4, "%d", &data.item4);
    20     sscanf_s(data3, "%d", &data.item3);
    21     sscanf_s(data2, "%d", &data.item2);
    22     sscanf_s(data1, "%d", &data.item1);
    23 
    24     printf_s("item1:%d
    ", data.item1);
    25     printf_s("item2:%d
    ", data.item2);
    26     printf_s("item3:%d
    ", data.item3);
    27     printf_s("item4:%d
    ", data.item4);
    28 
    29     getchar();
    30     return 0;
    31 }

    你觉得执行结果会是什么?

    奇怪吗?

    分析

    让我们分析一下:

    第19行代码将4赋值给了item4,第20行代码将3赋值给了item3, 第21行代码将2赋值给了item2, 第22行代码将1赋值给了item1。似乎没什么问题。

    还是来调试下程序吧。

    下面几张图片演示了程序在执行过程中的内存布局

    执行第一条sscanf_s前的内存布局

    执行第一条sscanf_s后的内存布局

    执行第二条sscanf_s后的内存布局

    执行第三条sscanf_s后的内存布局

    执行第四条sscanf_s后的内存布局

    到这里,相信大家都已经明白程序的输出结果为何是1,0,0,0了。

    演示代码不仅发生了内存越界,而且后续所有的输入都覆盖了上一条的执行结果。

     罪魁祸首就是sscanf_s中的格式字符串"%d","%d"表明将输入字符串作为一个int类型来保存到目标地址处。而演示代码的书写方式很显然不符合Data这个结构体中各成员所声明类型的要求。

    将个数字符串修改为"%c"后,程序执行正确:

    当然,我们其实可以在编译阶段发现这类问题

    结语

    通过今天这个演示,更加让自己明白了一定要多留意编译期间的警告信息,尽全力将其消灭。

    本博客仅仅演示了sscanf_s这类函数的冰山一角,对于其他需要注意的地方可以参考Format Specifiers Checking

  • 相关阅读:
    Cogs 465. 挤牛奶
    洛谷P1083 借教室
    Cogs 1264. [NOIP2012] 开车旅行(70分 暴力)
    2017-10-19 NOIP模拟赛
    Codevs 2144 砝码称重 2
    洛谷P1450 [HAOI2008]硬币购物
    洛谷P2534 [AHOI2012]铁盘整理
    洛谷P1731 生日蛋糕
    2017-10-18 NOIP模拟赛
    洛谷P1074 靶形数独
  • 原文地址:https://www.cnblogs.com/songqiang/p/watch_out_sscanf.html
Copyright © 2020-2023  润新知