数组和指针的区别,数组和其他类型都有区别.
一直认为,对C的指针比较了解了.最近突然发现一种写法,在C陷阱和缺陷36页左右.
char a[9]="abcdefgh";
*(a+1) 的值就是'b';
我忽然记得看C专家编程的时候,认为数组和指针完全不一样,之所以混淆主要就是因为子函数传值的时候。于是又重新看了下C专家编程,84页左右,发现自己其实当时并没有理解真正的意思.
a声明是数组,a的地址是在编译的时候确定的.现在假如a在编译器符号表具有一个地址为9980.
运行时第一步: 取i的值,与 9980相加.(char型就是1*i);
运行时第二步: 取地址(9980+i)的内容.
所以, a[1]的值就是 a的地址9980 + 1中的内容 'b';
现在再声明一个char *p="abcdefgh";如果用p[i]这种写法来取值.
首先,p在编译器符号表具有一个地址 4624.
运行时第一步: 取4624的地址的内容,假设为5650;
运行时第二步: 取i的值,和5650相加.
运行时第三部: 取地址(5650+i)的内容.
所以,p[1]的值就是 *(*(&p)+1)=*(p+1)的值,为'b'.
关键的地方就在于, a是数组,p是指针.然而 a[1]的值和p[1]的值相同,也就是*(a+1)的值和*(p+1)的值相同.非常容易造成指针和数组相同的假象.但是,明显他们的取值方式是不一样的,是的,这就是造成这种假象的原因.
结论: 在C语言中,数组类型是不同于其他类型的,当它在运行的时候,取的是它在符号表中得地址, 而int,float,*这种,会取符号表中得地址,进而地址中得值.
在C语言中,之所以数组名称a是 不可修改的左值,就是因为a代表的是符号表中得地址,是在编译的时候就确定的.
了解了这个,再回头看子函数传值的时候.
int sub_func( char * str)
{
取 str[1]的值;
} 函数定义.
传值的时候 ret = sub_func( a);
下面来分析下,在sub_func定义的时候,str在符号表中,地址为4210. 当调用函数的时候,将4210地址的值取出来,然后将数组a在符号表地址为9980传给4210地址中,作为4210地址的内容.这样,传值过程就算结束.在取str[1]的时候,就是如同上面*p的取值一样。
上面说的符号表地址等,其实是不对的,因为程序只有在运行的时候才在内存中有地址。"每个符号的地址在编译的时候是可知的。"个人猜测是符号表加载进内存的相对地址是固定的。这不是本问题的关键地方,不严谨的地方请包涵.
第一次发帖,如果有不对的地方,大家多多批评,发上来一是分享下自己的理解,二是让大家发现自己的不足.
[解决办法]
从很多实现上来看,访问一个变量,实际是先找到变量的地址,然后在读取变量地址里的数据的。
而访问数组元素,直接是数组首地址+offset,具体可以反汇编看一下,这一点正如楼主所说的.
而更深层次的区别,请参考:
http://blog.csdn.net/supermegaboy/article/details/4855027
[解决办法]
数组名不是左值,数组取下标操作的结果,比如a[1],才是左值。当然,*(a + 1)这样的也是左值。
如果不是全局变量,数组名未必放进符号表,符号表在很大程度上是给链接器和加载器使用的。一个局部的数组名,即使放进符号表,通常也只是用于调试的符号。
[解决办法]