在理解定义成数组,声明成指针与定义成指针,声明成数组之前,我们需要知道:
(1)数组就是数组,指针就是指针,虽然在用法上相似,但是他们的实际意义完全是两回事。
char arr[]="abcdef";
char *p=arr;
arr和p都可以通过指针的方式和下表的方式访问字符串”abcdef”;但是他们的意义却不一样。如图所示
(2)关于定义和申明的区别,即定义为变量分配了内存,而申明没有;定义只能出现一次,而申明可以出现多次。extern告诉编译器arr这个名字已经在别的文件中被定义了,代码中使用的arr是在别的文件中定义的。
(3)对于编译器来说,如果他需要读取某个地址(可能还需要加上偏移量)来进行某种操作,他就可以通过“开锁动作”直接读\写这个地址上的内存。但是,对于指针而言,必去先找到存储这个地址的地方,取出这个地址值然后对这个地址进行“开锁动作(即解引用)”,然后才能访问内存。
1.定义成数组,声明成指针
cpp1:
char arr[] = "abcdef";
cpp2:
#include<stdio.h>
#include<stdlib.h>
extern char *arr;
int main()
{
printf("%x\n", arr);
// printf("%s",(char *)&arr );
system("pause");
return 0;
}
在文件1中,arr被定义成字符数组,在文件2中,声明arr为指向字符的指针变量。
在64\32位系统,vs平台下,指针变量占4个字节,编译器会把存储在指针变量中的任何值都当做地址来处理。所以,如果需要访问字符串”abcdef”,必去先从指针变量中取出其保存的地址。但是,对于cpp2中的指针arr保存的是什么呢?如下图:
(1)编译器取出前4个字节空间的值,转换成十六进制0x64636261(不考虑大小端存储)。
(2)地址0x64636261上的内容按照char类型读写。但是地址0x64636261有可能不是有效的地址,或者是有效地址,但并不是我们想要的。
那么,我们到底怎样输出字符串“abcdef”呢?这里就要用到简单粗暴的方式了,哈哈,就是我们的强制类型转换。正确的输出语句:printf(“%s”,(char *)&arr );就可以输出字符串“abcdef”。
2.定义成指针,声明成数组
cpp1:
char *arr = "abcdef";
cpp2:
#include<stdio.h>
#include<stdlib.h>
extern char arr[];
int main()
{
printf("%s\n", arr);
system("pause");
return 0;
}
在cpp1中,编译器为指针变量arr分配4字节的空间,保存了字符串“abcdef”首字符的首地址,并且这个字符串本身保存在内存的静态区,其内容不能修改。在cpp2中,编译器认为arr是一个数组,数组内保存的是char类型的数据,那么具体是什么内容呢?如图所示:
编译器把arr当做一个包含4个char类型数据的数组使用,按照char类型取出arr[0]、arr[1]、arr[2]、arr[3]的值0x00、0x00、0x00、0x10,。但这并非我们需要的那块内存的的数据。