数组与指针到底是啥关系啊?引用《C语言深度剖析》中的一句话:“他们没有任何关系,只是经常穿着相似的衣服逗你玩儿罢了”。
数组与指针的相互转换是非常微妙且容易出错的:
1.数组符号的值以及其取址的值都是数组地址,但又不完全相同(主要是用sizeof以及地址+1操作时,详见“类型和类型转换一节”);
2.数组在参数传递时自动变成指针。
3.数组的访问方式a[n],最终都转换成*(a+n)
这几点内容在很多书上都有详述,而我这一节详细分析一下数组与变量的定义与声明时的一致性问题,我们将看到不一致的定义将引起灾难。
代码:
array1.c
- #include <stdio.h>
-
char apple[] = "apple";
-
char banana[] = "banana";
-
char *cherry = "cherry";
-
char *peach = "peach";
-
-
-
func(){
-
-
puts("orginal definition");
-
printf("the address of apple is %x\n",(int)&apple);
-
printf("the value of apple is %x\n",(int)apple);
-
printf("the value of apple[0] is %x\n",(int)apple[0]);
-
puts("*******************************************");
-
printf("the address of banana is %x\n",(int)&banana);
-
printf("the value of banana is %x\n",(int)banana);
-
printf("the value of banana[0] is %x\n",(int)banana[0]);
-
puts("*******************************************");
-
printf("the address of cherry is %x\n",(int)&cherry);
-
printf("the value of cherry is %x\n",(int)cherry);
-
printf("the value of cherry[0] is %x\n",(int)cherry[0]);
-
puts("*******************************************");
-
printf("the address of peach is %x\n",(int)&peach[0]);
-
printf("the value of peach is %x\n",(int)peach);
-
printf("the value of peach[0] is %x\n",(int)peach[0]);
-
}
array2.c
- #include <stdio.h>
-
extern func();
-
extern char *apple;//from char[] to char *
-
extern char banana[];//from char[] to char[]
-
extern char *cherry;//from char * to char *
-
extern char peach[];//from char* to char[]
-
-
main(){
-
func();
-
puts("external declaration");
-
printf("the address of apple is %x\n",(int)&apple);
-
printf("the value of apple is %x\n",(int)apple);
-
//printf("the value of apple[0] is %d\n",(int)apple[0]);//会引起段错误
-
puts("*******************************************");
-
printf("the address of banana is %x\n",(int)&banana);
-
printf("the value of banana is %x\n",(int)banana);
-
printf("the value of banana[0] is %x\n",(int)banana[0]);
-
puts("*******************************************");
-
printf("the address of cherry is %x\n",(int)&cherry);
-
printf("the value of cherry is %x\n",(int)cherry);
-
printf("the value of cherry[0] is %x\n",(int)cherry[0]);
-
puts("*******************************************");
-
printf("the address of peach is %x\n",(int)&peach);
-
printf("the value of peach is %x\n",(int)peach);
-
printf("the value of peach[0] is %x\n",(int)peach[0]);
-
puts("*******************************************");
-
-
}
输出结果:
- orginal definition
-
the address of apple is 804a018
-
the value of apple is 804a018
-
the value of apple[0] is 61
-
*******************************************
-
the address of banana is 804a01e
-
the value of banana is 804a01e
-
the value of banana[0] is 62
-
*******************************************
-
the address of cherry is 804a028
-
the value of cherry is 80488e8
-
the value of cherry[0] is 63
-
*******************************************
-
the address of peach is 804a02c
-
the value of peach is 80488ef
-
the value of peach[0] is 70
-
external declaration
-
the address of apple is 804a018
-
the value of apple is 6c707061 就是'a' 'p' 'p' 'l'
- 错误 会引起段错误
-
*******************************************
-
the address of banana is 804a01e
-
the value of banana is 804a01e
-
the value of banana[0] is 62 正确
-
*******************************************
-
the address of cherry is 804a028
-
the value of cherry is 80488e8
-
the value of cherry[0] is 63 正确
-
*******************************************
-
the address of peach is 804a02c
-
the value of peach is 804a02c
-
the value of peach[0] is ffffffef 错误
-
*******************************************
这里的代码试验了定义为指针或数组,而以指针或数组的方式访问的四种可能组合情况,并打印出各符号的地址与值。首先,可以肯定以一致的方式定义与引用不会产生错误;其次另外两种定义与引用不一致的情况会引起错误。
首先明确一点,作为全局符号表,其中存储的都是全局符号的地址,而不是它们的值。
1.定义为数组,按照指针引用的情况:例如apple[0],过程就是在全局符号表里面取apple这个标号的地址,该地址对应的值,此时该值被理解为一个指针,也就是4个字节,因此取出来的也就是数组的前4个元素appl;故而apple[0]的地址也就是0x6c707061,访问这个地址当然会引起段错误。总结一下,这种情况下出错主要是由于apple作为数组时其标号值就是标号地址这一歧义引起的。
2.定义为指针,按照数组方式引用的情况:在全局符号表里面得到peach的地址0x804a02c,同样由于数组标号的值即为地址,peach数组的地址出现了错误。其真实地址应该是peach的地址处对应的那个指针值,也就是0x804a02c处存储的值0x80488efc。现在peach[0]相当于访问了0x804a02c处的数值。也就是0xef,按照整数打印时判断为负数,所以前面填充了很多ffffff.
至此,一切真相大白,世界人民震惊了。。。。。一个小小的数组和指针竟能引发出如此大的混乱,这不得不引起我们的反思。。。。
PS.参考《C专家编程第4章》
阅读(1544) | 评论(0) | 转发(0) |