编译器在处理对数组的引用 如a[i] 在编译的时候总是被编译器改成*(a+i),其实方括号也是一个运算符,类似像加法运算一样,取下标操作数是可以互换的,因为在编译器处理*(a + i)和*(i+a)是一样的,也就说在
1、表达式中 指针和数组是可以互换的
2、下标运算符总是指针的偏移量相同
3、在函数参数的声明中,数组名被当做指向该数组的第一个元素的指针,
其他情况下 数组和指针是不一样的,如 数组 char a[ ] = "abcdefg"; 和 char *p = “abcdefg”
a 和&a中存的都数组的首地址
p存的一个指针的地址 *p的地址才是数组的首地址 也就是说用指针表示数组比直接表示数组多一次操作,相当于间接访问数组
取a[0]的过程是 首先得到a的地址 然后加上下标运算符的偏移量 得到结果 2步
取p[0]的过程是首先得到p的地址,然后取得*p的内容 数组a的首地址 然后在加上偏移量 多一次操作 3步
所以在声明和定义数组的时候要互相匹配 即 文件1定义一个char a[ ] = "bbbbbb",文件2声明的时候要声明为extern char a[] 不能写成 extern char *a;然后在程序的某个地方 出现了 a[0]之类的引用 编译连接能够通过 但是运行的时候 程序就会挂掉 这种错误是很难发现的 ,另一方面在文件1中定义了char *a = "bbbb" 文件2中 上面了 extern char a[ ];可以编译连接都通过 甚至运行的时候程序也不挂掉 但是取得的数据确实错的,所以还是建议 在声明的时候 最好和定义时候写法是一样的
至于 文件1定义一个char a[ ] = "bbbbbb",文件2声明的时候要声明为extern char *a ,并在文件2某一个地方 用a[0]使用数组元素的时候会出错的原因是
文件2 声明a是一个指针 所以 编译器首先通过a的地址 取得a中存取数组的内容 ,然后把这个内容当做数组的地址 和偏移量进行偏移 来取得数组的元素,但是文件1中 a的定义是
char a[ ] 所以 a中存放的就是数组的地址 这样编译器会取得一个字符 然后把这个字符当做地址和偏移量进行偏移操作 当然就出错了。。。
另一方面 在文件1中定义了char *a = "bbbb" 文件2中 上面了 extern char a[ ] ,在文件2某一个地方用a[0]使用数组元素的时候得到的数据也是错误的 原因是 在文件2中 a被声明为 char a[ ] ,编译器就把a当做数组来处理 ,文件1中实际上定义的是一个指针 ,编译器先取得a的内容 然后加上偏移量 实际上是在文件1定义的指针的地址上进行偏移取得的值 结果当然不对了
其实只要记住 指针是通过三个步骤取得 数组的值 数组是通过两个步骤取得数据的值 所以在声明和定义的时候要一一对应才不会出错 特殊情况是 最开始说的三条中 数组被编译器转换成 指针来处理了 ,可能这样做编译器的效率会更高些,只用处理一种情况 而不用分开处理了 。
这种错误其实也类似于 一个文件中定义了一个浮点数 另一个文件中却把它声明为整形的 当然就出错啦!
附 测试
文件1
char *test = "bbbbbb";
文件2
#include <IOSTREAM>
#include <CSTDIO>
using namespace std;
extern char test[];
int ga[10] = {1,2,3,4,5,6,7,8,9,0};
void f1(int ca[])
{
printf("f1 : \n ca = %d \n &ca = %d \n &(ca[0]) = %d \n &(ca[1]) = %d \n",ca,&ca,&(ca[0]), &(ca[1]));
}
void f2(int *ca)
{
printf("f2 : \n ca = %d \n &ca = %d \n &(ca[0]) = %d \n &(ca[1]) = %d \n",ca,&ca,&(ca[0]), &(ca[1]));
}
int main()
{
char a[10] = "abcdefg";
int b[10] = {1,2,3,4,5,6,7,8,9,1};
char *p = "abcd";
char c[] = "bbbb";
printf("p = %d \n *p = %d \n",p,*p);
printf("&p = %d \n &(*p) = %d \n",&p,&(*p));
printf("c = %d \n *c = %d \n",c,*c);
printf("&c = %d \n &(*c) = %d \n",&c,&(*c));
cout<<"a[2] = "<<a[2]<<endl;
cout<<"2[a] = "<<2[a]<<endl;
cout<<"main"<<endl;
f1(b);
f2(b);
cout<<"global"<<endl;
f1(ga);
f2(ga);
printf(" ga = %d\n &ga = %d \n &(ga[0]) = %d \n &(ga[1]) = %d\n",ga,&ga,&(ga[0]),&(ga[1]));
cout<<"test[1] = "<<test[0]<<endl;
return 0;
}