char a[]为什么不能声明为extern char *a

来源:互联网 发布:centos minimal 安装 编辑:程序博客网 时间:2024/06/07 07:38

每个符号的地址在编译时可知,即编译器符号表将每个符号的地址存储起来;

(1)对于基本类型的变量,例如,int a;char ch;long int b;unsigned int c、、、等,在符号表中存放的实际是这些变量的地址,即&a,&ch,&b,&c,所以在引用这些变量时,直接从这些地址中取出变量即可;

(2)对于数组int a[100]来说,编译器符号表中存放的就是数组a[100]所有单元的地址(即:&a[0],&a[1],&a[2],&a[3],、、、、、),因为对于数组来说,无论是否进行初始化,编译器总会为它分配空间,而且这些空间是连续的,这就意味着,编译器会在符号表中保存每一个数组成员的地址,这些地址当然也是连续的,对于a[i]来说,其实是*(a+i),分为两步,第一步是求a+i,而a是什么呢,数组名,即数组首地址,写的明白一点,数组首元素的地址应该是 &a[0] = &(*(a + 0))= &(*a) = a,&和*在这里一个是取地址,一个是解引用,互为逆运算,相互抵消,结果即为a,那么a其实是&a[0],这一点清楚了,因为编译器为数组已经分配好内存空间,即在符号表中保存了这些空间的地址,那么&a[0]代表的地址也保存在符号表中,即a代表的地址也在符号表中,那么a+i经过编译器换算,其实得到的是&a[i],这就相当于在编译器符号表中直接根据偏移得到该变量的地址;第二步是求*(&a[i]),直接取地址中的值,记得到a[i];

(3)对于指针char *p来说,编译器符号表中存放的实际是指针变量p的地址&p,注意,编译器只为p指向的字符的地址存放假设*p = “abcdefgh”,如果我们要引用这个字符p[i],需要经过三步,第一步,取地址&p中的内容,得到字符的存放地址p;第二步,根据偏移量i,得到相应的偏移地址p+i;第三步,根据上一步的偏移地址得到地址中的内容


上面讲了数组引用和指针引用的不同,下面就来讲一下为什么不能讲char a[100]声明为extern char *a?

因为数组变量a和指针变量a在编译器符号表中保存的方式不同,所以当你采用指针方式引用数组时,就会发生将&a[0]误当成&a,显然 这是错误的,&a[0]是char* ,而&a是char**,类型就不匹配,另外,从解引用过程来看也是错误的,你将&a[0]当成&a,系统先会对&a解引用,获得a,而这里实际是对&a[0]解引用,得到的却是a[0],本来你想得到一个地址,现在却得到一个字符,接着你又将a+i,获得偏移地址,实际上这里却是a[0]+i,结果却是一个字符加上一个整数,获得另一个字符,然后你进行*(a+i),而实际上是进行*(a[0]+i),很明显,a[0]+i是个字符,这里却把它当做地址,显然是错误的。

原创粉丝点击