看了《c专家编程》,对指针和数组的区别有了比较清晰的了解。
先写一个小程序
#include <stdio.h>
int main()
{
char a[2], *p;
printf("a:%x\n&p:%x\n", (int)a, (int)&p);
return 0;
}
|
结果
a:bfa10942
&p:bfa1093c
p和a都保存在栈中,内存布局是这样的(此时p并未初始化,但这个不影响下面的讨论),
| p | &p = 0xbfa1093c
| a[0] | a = 0xbfa10942
| a[1] | a+1 = 0xbfa10943
看到这个布局,不难理解为什么数组的指针为常量而不能改变,因为a的含义跟&p其实是类似的,为非左值,正如我们也无法修改&p的值。
另外一个比较明显的区别是指针和数组的寻址方式:
修改程序,加上
p = a;
a[0] = 0, a[1] = 0;
|
指针:
获得p[1]的值
1.找到指针p在栈中的位置,即&p,读取其中的内容p。
2.找到地址为p的内存位置,即为0xbfa10942。
3.然后偏移1位(偏移大小对应于指针类型),即为0xbfa10943,读取其中的内容0。
数组:
获取a[1]的值
1.找到a在栈中的位置0xbfa10942。
2.向下偏移一位,0xbfa10943,读取其中内容,即为0。
再举个书中的例子,我觉得这个例子能更能将两者的区别体现出来。
在a.c中 定义 char a[2] = {0, 1};
在b.c中 定义 extern char* p;
此时若在b.c中 读取 p[1]中的内容,会产生什么样的后果呢?
因为extern是声明,并未在栈中给p分配一个实际的空间,此时p的保存位置其实就是a所在位置,即&p == a(0xbfa10942),然后进行对p[1]的寻找。
系统认为p是一个指针,则会按照指针的方式来寻找p[1]。
1.找到&p,读取内容p,而&p中的内容即为 a[0],即此时结果为 p = 0;
2.找到地址为p的内存位置,即找到内存地址为0的地方。
3.然后偏移1位,访问地址为0x1的内存,出错。(或者为程序崩溃,或者为结果错误)
同理,若原定义为指针,而声明为数组,也会出现类似的问题。所以最好的办法是,一一对应,才会避免出现上面的错误。
阅读(556) | 评论(0) | 转发(0) |