strcat函数越界的问题

时间:2022-11-18 06:00:21

首先,这是一个非常有趣的问题!
我也是最近看了一本《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的!