在《C和指针》上的一道练习题。
下面的声明取自某个源文件:
int a[10];
int *b = a;
但在另一个不同的源文件中,却发现了这样的代码:
extern int *a;
extern int b[];
int x, y;
……
x = a[3];
y = b[3];
请解释一下,当两条赋值语句执行时会发生什么?(假定整型和指针的长度都是4个字节。)
书上所附的答案:
在第1个赋值中,编译器认为a是一个指针变量,所以它所提取存储在那里的指针值,并加上12(3和整型的长度相乘),然后对这个结果执行间接访问操作。但实际上a是整型数组的起始位置,所以作为“指针”获得的这个值实际上是数组的第1个整型元素。它与12相加,其结果解释为一个地址,然后对它进行间接访问。作为结果,它或者将提取一些任意内存位置的内容,或者由于某种地址错误而导致程序失败。
在第2个赋值中,编译器认为b是个数组名,所以它把12加到b的存储地址,然后间接访问操作从那里获得的值。事实上,b是个指针变量,所以从内存中提取的后面三个字实际上是从另外的任意变量中取得的。这个问题说明了指针和数组虽然存在关联,但绝不是相同的。
分析:
a是一个数组名,b是一个指向了a的指针。假设数组a的开始地址为123456,在内存里的情况如下:
[内存地址] (存放在该地址上的值)
a -- [123456] (1)
b -- [223564] ([123456])
a = 123456, a[0] = 1, *a = 1, &a = 123456;
b = 123456, b[0] = 1, *b = 1, &b = 223564;
*b,b[0]所作的间接访问正确的流程应该是,从b的内存地址223564上找到存放在该地址上的值123456,跳到地址123456,把上面所存的值提出来。
把数组名a当作指针来使用的后果就是,在地址123456上找到值1,1加上12得到新地址13,跳到地址13,提取该地址所存放的值。
把指针b当作数组名来使用,在地址223564后移3个字节,即在地址223576上提取值。