欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一段神奇的c代码错误分析

程序员文章站 2022-07-15 15:26:52
...

源代码

#include <stdio.h>

int main(int argc, char* argv[])
{
        int i = 0;
        int arr[3] = {0};
        printf("first i is %p\n", &i);
        printf("first arr loc is %p\n", &arr);
        for (; i < 3; i++)
        {
                printf("arr %d loc is %p\n", i, &arr[i]);
                printf("i:%d loc is %p\n", i, &i);
                arr[i] = 0;
                printf("hello world\n");
        }
        return 0;
}

输出

在centos7 的机器上编译然后输出得到

first i is 0x7ffd1a10d21c
first arr loc is 0x7ffd1a10d210
arr 0 loc is 0x7ffd1a10d210
i:0 loc is 0x7ffd1a10d21c
hello world
arr 1 loc is 0x7ffd1a10d214
i:1 loc is 0x7ffd1a10d21c
hello world
arr 2 loc is 0x7ffd1a10d218
i:2 loc is 0x7ffd1a10d21c
hello world

神奇的地方来了

 for (; i < 3; i++)

改成

 for (; i <= 3; i++)

现在再编译输出会无限循环输出,截取其中的一段得到:

first i is 0x7ffd1a10d21c
first arr loc is 0x7ffd1a10d210
arr 0 loc is 0x7ffd1a10d210
i:0 loc is 0x7ffd1a10d21c
hello world
arr 1 loc is 0x7fff75ecb214
i:1 loc is 0x7fff75ecb21c
hello world
arr 2 loc is 0x7fff75ecb218
i:2 loc is 0x7fff75ecb21c
hello world
arr 3 loc is 0x7fff75ecb21c
i:3 loc is 0x7fff75ecb21c
hello world
arr 1 loc is 0x7fff75ecb214
i:1 loc is 0x7fff75ecb21c
hello world
arr 2 loc is 0x7fff75ecb218
i:2 loc is 0x7fff75ecb21c
hello world
arr 3 loc is 0x7fff75ecb21c
i:3 loc is 0x7fff75ecb21c
.....

为什么会发生这种现象呢?
究其原因是因为

函数体内的局部变量是存在栈上的,且是连续压栈。在Linux进程的内存布局中,栈区在高地址空间,从高向低增长。变量i和arr在相邻的地址,其i比arr的地址大,由于我们只声明数组大小为3,所以如果访问arr[3]其实已经越界了,但是虽然arr[3]是不存在的,但是如果越界访问的话我们可以发现他的地址是0x7fff75ecb21c,这和其实就是i的地址。
所以:

arr[3] = 0;
其实就是
i = 0

所以会一直进入死循环的情况。