分析数组和指针“相同的原因”
数组和指针两者不同,因为他们概念就不同。数组表示一个集合,具有确定数量的元素;而指针只是一个标量值器,表示某个元素地址。
之所以会出现两者相等的说法,是因为我们给数组起名叫做a,那么对a的相关操作,就认为是对数组整体的操作,如sizeof(a)是整个数组的大小;但有时似乎和指针的功能一样,指针和数组都可以访问一些地址,可以进行相同的运算。
许多初学者对于数组和指针的使用感到很迷茫,感觉数组和指针的功能相互交叉,有点无所适从。
今天梳理了一下思路。分享给大家。
《C和指针》第141页中,作者写到“在C中,在几乎所有使用数组名的表达式中,数组名的值是一个指针常量,也就是数组第一个元素的地址。它的类型取决于数组元素的类型”。
在后面作者具体的给出了
“只有在两种情况下,数组名并不用指针常量来表示——就是当数组名作为sizeof操作符或单目操作符&的操作数时。”
也就是说:
1,对于int a[10];在sizeof(a)和&a两个表达式中,数组名a是表示整个数组(数组元素集合),分别得到的是数组a的整体大小和数组a的地址。
2,除了上述表达式外,其他的任何操作,都是将数组名a降级为一个指针常量,表示首元素地址,这也是为什么有时a可以当做指针使用的原因,也是一些初学者纠结困惑的地方。因为在大部分表达式中a就是一个指针,只是a的值不能改变,是个常量,所以int b[10]; a = b错误,;但是可以像指针那样,灵活的访问某一地址,比如a[1]等价与*(a+1)
例如在下面程序中:通过监视中,可以获取我们想要信息。
#include <stdio.h>
void fun1(int *b)
{
;
}
void fun2(int c[])
{
;
}
int main()
{
int a[10];
int *p_a = a;
int i = 0;
while (i < 10)
a[i++] = i;
//断点1
fun1(a);
//断点2
fun2(a);
return 0;
}
F5到断点1,从在监视中输入以下数据,可以发现其中奥秘
a单独出现,不在表达式中,类型为int [10]。a代表数组整体,且保存数组的地址。
&a,类型为int [10]*,表示一个指向整个数组的指针,值为数组的地址,此时a表示整个数组。
&a[0],类型为int *,表示一个指向整型的指针,值为a[0]的地址,即数组首元素地址。可以发现a,&a,&a[0]的值一样,都是数组首元素的地址。
&a+1,类型为int [10]*,同样表示一个指向整个数组的指针,不过,该数组地址增加了40(10进制)个字节,刚好是一个数组的大小,表明,移动到了数组a的下一起点地址。
&a[0]+1,类型为int *,表示一个指向整型的指针,其地址数组a的后一个字节,表示数组元素a[1]的地址。
sizeof(a)的值为0x28(十六进制) = 40(10进制),即整个数组大小。此时a代表整个数组。
*(&a)类型都为int [10],即此时*(&a)代表整个数组,还是原数组。因为它是对一个数组类型指针int [10]*进行解引用,表示一个数组。
继续执行F10,进入fun1函数,查看b和sizeof(b)
注意:
此时b的类型是int *,也就是说,在调用fun1(a)时,a作为数组a第一个元素的首地址,传给了形参int *型指针b,
既然b只是一个指针,不是数组,那么sizeof(b)就是指针的大小4。
继续F5进入断点,查看c和sizeof(c)
注意:
虽然,fun2(char c[]),看起来是以一个数组形式接受的,但是实际上,编译器还是改写为char* c接收。
所以,c和b的情况相同。
总结:
通过以上,可以看出,只要我们牢记红字标记的两句话,不管数组名的上下文是多么的不同,诡异,我们都可以按着规则,一步一步的分析出它的功能。