内存越界问题

转自http://blog.qiwen.name/2009_09_01_archive.html

关于内存读写越界的一点讨论
根据最近的一点经验,先总结如下两点

1.指针强制转换的隐患
先看一个程序:
#include <stdio.h>

void set_zero(unsigned short *p)
{
    *p = 0;
}

typedef struct
{
    unsignedchar a;
    unsignedchar b;
}test_c_c_struct;

typedef struct
{
    unsigned char a;
    unsigned short b;
} test_i_c_struct;

int main()
{
    test_c_c_struct cc;
    test_i_c_struct ic;
    cc.a = 1;
    cc.b = 1;
    ic.a = 1;
    ic.b = 1;
    set_zero((unsigned short *)&(cc.a));
    set_zero((unsigned short *)&(ic.a));
    printf("%d\n", cc.b);
    printf("%d\n", ic.b);
    return 0;
}

在未经特殊设置的VC++6.0中编译,运行输出
0
1

set_zero((unsigned short *)&(cc.a));这句中,把一个unsigned char*转换为unsigned short*,之后在set_zero函数中对对*p赋值为0,其实是把&(cc.a)为启示位置的2字节内容置为0,而cc.a本来只是占1字节的,所以其后的1字节内容也被置0了,这就是为什么printf("%d\n",cc.b);会输出0的原因。

同理printf("%d\n",ic.b);也应该输出0啊,为什么却得到了1?
这是由“内存中字节对齐”导致的。(在VC++6.0中未经特殊设置,是4字节对齐,关于字节对齐的详细情况超出本文的讨论范围。)

虽然test_i_c_struct中a只占1字节,由于字节对齐,导致其后1字节空出来不用,如果a从地址n开始,那么b就是从地址n+2开始,所以在set_zero((unsigned short*)&(ic.a));之后并未影响到ic.b的值.

2.数组越界的危险

再来看一个程序

#define ARR_LEN3
void test_array(void)
{
    int i;
    int arr[ARR_LEN];
    for (i = 0; i <= ARR_LEN; i++)
    {
       arr[i] = 0;
    }
}

如果这个程序拿去执行会得到什么结果了?

死循环!!!

可以输出i,以及arr各个元素的地址出来看看:
i      0x13ff28
arr[0] 0x13ff1c
arr[1] 0x13ff20
arr[2] 0x13ff24
arr[3] 0x13ff28 (虽然arr[3]不是arr的元素)

很容易看出来arr[3]的地址和i的地址是一样的,所以每次i == 3的时候把arr[3] = 0;等于是i = 0;那么循环仍然继续,编成了死循环。从内存地址可以看出,内存分配的时候是从高位往地位分配,数组越界访问导致了这一可怕的结果。

posted @ 2012-10-19 10:38  一只海星  阅读(411)  评论(0编辑  收藏  举报