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

我发现了一个秘密:数组和指针真的不一样啊。

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

array.c

 

图片

Array.h

 

 

Pointer.c

 

图片

 

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

 

 

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

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

 

图片

 

数组的下标引用

 

 

图片

 

对指针的引用

 

图片

 

对指针进行下标引用


我现在遇到的状况是: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.cextern 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 *pp声明为指针后,不管p原先是定义为指针还是数组,取p[i]的值都会按照往上面好几行已经说过的三个步骤走,即:

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

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

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

所以呢,p[0]就是访问地址0x64636261里存储的值,但由于0x64636261被保护,不可访问,所以就出现了”Segmentation fault”的错误。会出现这个错误并当场宕机算幸运的了,要是内存这样被程序污染了,并且没当场死掉,指不定什么时候会出现一些莫名其妙的Bug,到时候会把人搞死的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值