您的位置:首页 > 编程语言

代码戏我千百遍,我待代码如初恋--数组和指针真的不一样啊。

2012-07-17 07:05 288 查看
我发现了一个秘密:数组和指针真的不一样啊。

今天,我写了这么个坑爹的代码:

array.c



Array.h



Pointer.c



编译运行,运行到main红色框框里那句就出错了:



同样是打印p[0],在函数print_p();里没出错,到main里就出错了,好怪异啊。

翻书吧,在《C专家编程》的第84页对数组和指针的访问进行了解释,我在这里当一下搬运工:



图A 数组的下标引用



图B 对指针的引用



图C 对指针进行下标引用

我现在遇到的状况是:在pointer.c里写了句声明“extern char
*p;”,然后再以p[0]的方式来引用array.c里数组p[MAX_NUM+1]= "abcdefg";其实质是图A和图B访问方式的组合。首先,进行图B所示的间接引用。然后,如图A所示用下标作为偏移量进行直接访问。更为正式的说法是,编译器将会:

1. 取得符号表中p的地址,提取存储于此处的指针。

2. 把下标所表示的偏移量与指针的值相加,产生一个地址。

3. 访问上面这个地址,取得字符。

一步一步来,先看一下函数print_p()里是怎么对数组p[]进行访问的;将Array.c更改如下:



编译,执行结果如下:



访问过程:

a. 经过数组定义后,符号p代表了数组p[MAX_NUM+1]的首地址0x0804970,数组“abcdefg”存储于以0x0804970开始的8个字节的内存空间。



b. 访问p[3]时,就是先取得p的值0x0804970,然后+3得到0x0804973,再取地址0x0804973里的内容‘d’也就是0x64.

但为什么在函数main引用p[0]时会出错呢。在main函数添加一句打印p的值的语句看一下。



这次连&p的值也打印了。

执行结果如下:



由于重新编译,数组p的首地址被重新分配成0x08049768了,但这没影响。看到了没,在main里&p
= 0x08049768刚好是数组p的首地址,这时的p却等于0x64636261;

哈哈,好玩的事情来了,我在这个坎纠结了好久。

原来是这样的:

在array.c里的char p[MAX_NUM+1] = "abcdefg"告知编译器p是一个字符序列,经过编译后数组p[MAX_NUM+1]首地址是0x08049768,在array.c里引用p时,p代表的就是数组的首地址,也就是p=0x08049768;而在pointer.c里extern
char *p却告知编译器p是一个指向字符的指针,此时p代表的是地址0x08049768里存储的值0x64636261(p是个指针,占用四个byte的空间,而从0x08049768开始的四个byte里存的是‘a’’b’’c’’d’,即0x64636261),即p
= 0x64636261。就像定义 char a = 0x01一样,0x01存于某个地址空间内,引用a时,就去这个地址空间取得里面存储的值0x01,即a
= 0x01。

extern char *p把p声明为指针后,不管p原先是定义为指针还是数组,取p[i]的值都会按照往上面好几行已经说过的三个步骤走,即:

1. 取得符号表中p的地址0x08049768,提取存储于此处的指针0x64636261;

2. 把下标i与指针的值相加,产生一个地址,即0x64636261+i;

3. 访问上面的这个地址,取得字符。

所以呢,p[0]就是访问地址0x64636261里存储的值,但由于0x64636261被保护,不可访问,所以就出现了”Segmentation fault”的错误。会出现这个错误并当场宕机算幸运的了,要是内存这样被程序污染了,并且没当场死掉,指不定什么时候会出现一些莫名其妙的Bug,到时候会把人搞死的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: