在刚搞C开发的时候,对于char *p="abc"和char p[3]="abc"这两句话的理解有些问题,认为他们基本上是等同的,直到有一次在一个头文件中定义了char p[3]="abc" 在另一个文件中写了extern char *p,编译器报错!然后我就对这两句话的含义做了下分析,有空写出来备份下。呵呵 GOGO!
一、当p被定义为数组时。
先看第一种情况 char p[3]="abc"。这时编译器会将变量p理解为数组,在编译时就为p申请了3个char大小的空间,并使p等于此连续的空间的首地址,如:4081 ,这时的内存模式为:
对于p[1]来说,就可以对p进行直接内存解引,相当于 *(p+1)。
取值的运行步骤为:
1.找到p的首地址;
2.对p地址进行偏移1个单位,直接取此地址的值;
二、当p被定义为指针时。
再看第二种情况 char *p="abc"。这时编译器会将变量p理解为指针,在编译时就为这个指针对象申请了一个指针的空间大小(一般我们可以把一个指针的空间大小认为是4个字节),编译器为了记住这个指针对象,需要另外一个指针指向这个指针对象,此时p所指向的是这个指针对象的地址,如:5035,这时的内存模式为:
对于p[1]来说,就可以对p进行间接内存解引。
取值的运行步骤为:
1.找到p的地址;
2.对p进行解引,找到”abc”字符串常量的首地址;
2.”abc” 字符串常量的首地址进行1个单位,取此地址的值;
三、当char p[3]遇上char *p
现在我们可以来看 如果一个“傻乎乎”的编译器让我们的代码:char p[3]="abc"; extern char *p;通过了编译,我们运行时会出现什么呢?
此时对p[1]进行的取值操作运行步骤为:
1. 由于p被声明为指针,编译器会用指针对象的“待遇”对待p,也就是对p解引操作(此时对p进行解引操作 取出来的值就是char类型的’a’);
2. 当然此时还不会出现什么错误,接下来编译器会认为它找到了”abc”字符串常量的首地址,并对此“地址”进行1个单位的偏移。
3. 接下来编译器会对这个已经偏移过的地址进行解引操作,Oh on! 这时杯具出现啦!因为对’a’进行1个单位的偏移后的地址进行解引谁也不会知道出现什么事。。。更杯具的事 你的程序还会带着这个神秘的值跑下去!