问题
- 取地址符号在数组前面使用代表什么?
- 指向二维数组的二级指针为什么不能二次解引用,而是经过一次解引用就可以得到首元素的值了?
- 取地址后进行数值运算,和普通的指针进行运算有什么不同?
解决
数组名是第一个元素的地址,不能说数组名是一个指针,数组名在编译阶段会被替换为,数组第一个元素的首地址,一串二进制数,同时,数组名可以理解为在常量区,因为他是不可更改的。
对于一维数组,数组名就是普普通通的第一个元素的地址,对其进行算数加减运算,都是增加sizeof(基本类型)的长度倍数。
而对于二维数组,数组名不仅仅是普通的第一个元素的地址,C语言还让他代表第一维度的全体地址,虽然这个地址的大小和首元素地址大小相同,但是进行算数加减操作,偏移量是整个维度的倍数。
#include <stdio.h>
int main()
{
int a[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = a;
printf("%d\n", p);
printf("%d\n", a);
printf("%d\n", p+1);
printf("%d\n", a+1);
return 0;
}
可以看到第二行和第三行的大小,说明了这一点。
但是如果将a赋值给一个指针类型,这相当于进行了一个隐式转换,转换为了int *类型,为什么这么说呢,因为这样破坏了a进行运算的方式,如果你进行算数操作,如图第一行和第二行的输出,你就知道,这个时候进行+1操作,只仅仅便宜一个int类型长度。并没有偏移二维数组一个行的长度。
对于一维数组这种简单情况,我们考虑一下对数组名进行取地址。
#include <stdio.h>
int main()
{
int a[5] = { 1,2,3,4,5 };
int* p = a;
printf("%d\n", p);
printf("%d\n", a);
printf("%d\n", &p);
printf("%d\n", &a);
printf("%d\n", a + 1); //这里不能&(a+1), 谁能帮我从更深入的讲解一下
printf("%d\n", &a+1); //取地址运算符,优先级最高
return 0;
}
可以看到第二行和第四行的数值是一样的,但是进行运算之后数值是不一样的。
说到这儿,就已经解决了上面的三个问题,第一个问题,数组名取地址,因为它并不是一个真正的变量,a会在编译阶段标记为数组元素首地址,这样的一串数字。当然了这串地址所指向的空间,是可以进行改变的。因为数组开辟了一堆空间,空间内的值可以改变。从不可以&(a+1)操作就可以看出,a是在编译期间进行操作的,如果&a连载一起就把首元素地址当成整个元素地址进行操作。
第二问,二次解引用:
#include <stdio.h>
int main()
{
int a[2][5] = { 1,2,3,4,5 ,6,7,8,9,10};
int** p = a;
printf("%d\n", p);
printf("%d\n", a);
printf("%d\n", *p);
printf("%d\n", *a);
printf("%d\n", p+1);
printf("%d\n", a+1);
//printf("%d\n", **p);报错
printf("%d\n", **a);
return 0;
}
在这里,把a赋值给int类型的变量也发生了隐式类型转化,a表示第一个维度的整个地址,数值上为数组首元素地址。它+1等于整个维度偏移,而赋值给int 只能进行int** 类型的偏移,指针类型进行加减操作,只能偏移基本类型的倍数,这里的基本类型是int**,但实际上和int*一样,只不过是个套娃指针。上面程序有所展示,不详细介绍了。
第三问。。。已经说完了
也正是因为*取地址运算符只能对指针使用,所以,才有了多级指针(我之前考虑能不能一个指针多次解引用,发现不行)。