• c++:strcat潜在的错误不报告


    #include<iostream>
    #include<cstring>
    using namespace std;
    int main()
    {
    char a[]="hello";
    char b[]="world";
    cout<<strlen(a)<<endl;
    strcat(a,b);
    cout<<a<<endl;
    cout<<strlen(a)<<endl;


    }

    运行结果:

    5
    helloworld
    10

    这个小程序中数组a的大小被改变了,但是可以正常运行。潜在的错误影响呢????


    分析如下:http://blog.csdn.net/sendfeng/article/details/6215016。感谢sendfeng.

    首先,这是一个非常有趣的问题!
    我也是最近看了一本《C++高效编程:内存与性能优化》的书才弄明白其中的奥秘!
    我们先来看一个“奇怪”的现象:

    CODE:

            struct A { char a; long b; char c; long d; };
            struct B { char a; char c; long b; long d; };

            cout << sizeof(A) <<endl;
            cout << sizeof(B) <<endl;
    按照常理,输出都应该是 10 ,其实实际运行结果是16,12 !是不是很奇怪???

    为什么会出现这个现象呢?因为编译器会强制char类型的变量与long类型的变量在内存中对齐!


    举例看结构A在内存中的布局如下:

    地址   内 容
    00     字符a
    01     未用
    02     未用
    03     未用
    04     long b, byte 0
    05     long b, byte 1
    06     long b, byte 2
    07     long b, byte 3
    08     字符c
    09     未用
    ......
    可以看到其中的原因了吧!

    再看看LZ的程序的原因。
    C++的系统函数strcat()的功能只是简单的拼接字符串,自身没有检测是否越界的功能!所以,当拼接后的新的字符串长度大于原始的空间时,strcat()会修改邻接的内存空间!所调用strlen()所取得的长度是截止到 '/0' 的长度!但是调用sizeof()会发现其空间大小还是10!
    按照上面的说法,字符数组a后面的空间应该被修改,所以b的内容会变化,但是C++编译器分配内存空间是按照倒栈的顺序的,如果把b放到a前面定义,才有可能被修改!但是由于开始说的内存对齐问题的存在,因此字符数组b的内容还是没有被改变。


    大家可以看看下面的程序,分别输出a,b的地址。

    CODE:

    int main(){

        char b[10] = "good";
        char a[10] = "java is";
        strcat(a," ");
        strcat(a,b);
        cout << int(&b) << endl;
        cout << int(&a) << endl;

        return 0;
    }
    运行结果为:

    2293600
    2293584


    (该运行结果取决于不同的机器与编译器,但是反映的问题还是很明显的!)

    a,b的头地址相距16Byte,而a的默认空间只有10Byte,还有6Byte的空间是什么呢?
    当执行strcat()时,越界的部分就覆盖了这6Byte的内容,但是还没有影响到b的内容,为了证明strcat()确实存在越界的问题,我们可以构造一个特例,程序如下:

    CODE:

    int main(){

        char b[30] = "good, but i don't think so!";
        char a[10] = "Java is";
        strcat(a," ");
        strcat(a,b);
        cout<<a<<endl;
        cout<<b<<endl;
        cout << int(&b) << endl;
        cout << int(&a) << endl;

        return 0;
    }
    我们把b放得足够大,然后调用strcat(),使得拼接后的字符串的长度大于16,这样的话,不仅仅是a,b之间的6Byte被覆盖,b的内容也被覆盖了!
    程序运行结果如下:

    Java is good, but i don't think so!
    t i'dont think so!

    可以看到,越界是存在的!

    最后总结一下:
    strcat()存在越界的问题,因此我们在使用该函数之前需要确保目标字符数组的空间足够大!在原始的程序中,由于变量较少,运行似乎没错,但是还是有很严重的BUG的!


  • 相关阅读:
    基于DM642 RAW采集格式的视频驱动开发及应用
    嵌入式开发之davinci--- 8148/8168/8127 中的添加算饭scd 场景检测 代码实现
    如何在外部采用AES-128对HLS的TS流进行加密
    阶段3 2.Spring_03.Spring的 IOC 和 DI_11 set方法注入
    阶段3 2.Spring_03.Spring的 IOC 和 DI_10 构造函数注入
    阶段3 2.Spring_03.Spring的 IOC 和 DI_9 spring的依赖注入
    阶段3 2.Spring_03.Spring的 IOC 和 DI_8 spring中bean的细节之生命周期
    阶段3 2.Spring_03.Spring的 IOC 和 DI_7 spring中bean的细节之作用范围
    阶段3 2.Spring_03.Spring的 IOC 和 DI_6 spring中bean的细节之三种创建Bean对象的方式
    阶段3 2.Spring_03.Spring的 IOC 和 DI_5 BeanFactory和ApplicationContext的区别
  • 原文地址:https://www.cnblogs.com/catkins/p/5270803.html
Copyright © 2020-2023  润新知