理解指针运算符&和取值运算符*的原理
通过下面一段代码的输出结果,可以很好的理解指针运算符&和取值运算符的原理:
文字分析已经写在了代码注释中,是在做实验时根据输出结果分析的
#include <stdio.h>
int main(void)
{
/*
* int a[5] 与 int a 的本质:
* 其实两个a并无本质区别,它们都是汇编中的标签
* 汇编中的标签代表的是地址
* 所以这两个a都是代表这片空间的起始地址
* 再具体一点说:
* 数组名a代表了一个具有20字节的空间的起始地址
* 整型变量a代表了一个具有4个字节空间的起始地址
*/
int a[5] = {1,2,3,4,5};/* a作为右值时代表数组首元素的地址 */
int *ptr = (int *)(&a + 1);
/* 数组在栈上的布局 */
for (int i = 0; i < 5; i++) {
printf("address a[%d] = %p\n", i, &a[i]);
}
printf("address a:%p\n", a); /* a代表的是数组首元素的地址 */
printf("address &a:%p\n", &a);/* &a代表的是数组的首地址 */
/*
* sizeof(&a) = 8:说明&a是一个指针类型
* 一个类型为T的指针的移动,以sizeof(T)为移动单位
* 所以
* a+1:
* a本身就是一个地址,它就是汇编中的一个标签
* a代表的时数组首元素的地址,地址就是一个指针,它是一个int类型的指针,意思就是指针指向4个字节大小的内存单元
* 移动单位为sizeof(int)
* &a+1:
* 先理解&a:
* 取地址符&后面跟的是指针的类型,什么是指针的类型?
* int类型的指针,就是这个指针指向4个字节大小的内存空间
* long类型的指针,就是这个指针指向8个字节大小的内存空间
* 这个就是指针的类型
* 所以,因为这里的a是一个数组,内存空间大小为20字节
* 所以 &a + 1 的第一步就是根据a的大小计算出移动单位,然后将&a(地址)加上移动单位,最后得到新的地址
* 理解概念,你是一个什么类型的指针
*
* 总结:
* &a表示的是一个指针,更具体一点说,代表一个a类型的指针
* 再进一步说,&a 表示的是指向a类型所占有的字节空间的地址
*
* & 和 * 的原理:
* 取地址符 & 的工作原理:
* 1.先计算出占用内存空间的大小:
* 举个例子:&a就是先计算出类型a的大小
* 2.将标签a替换成地址
*
*
* 取值运算符 * 的工作原理:
* 举例:
* int * p = &a;
* *p;
* 1.先读取p里的内容,找到内存空间的首地址
* 2.连续读取这个指针类型大小的字节单元
*
*/
printf("address a+1:%p\n", a+1); /* a+1代表数组第二个元素的地址 */
printf("address &a+1:%p\n", &a+1);/* &a+1代表第二个数组的地址 */
printf("size a:%d\n", sizeof(a)); /* sizeof(a) = 20 */
printf("size &a:%d\n", sizeof(&a));/* sizeof(&a) = 8 */
printf("address (int *)(&a + 1):%p\n", ptr);
printf("address (int *)(&a + 1):%p\n", (int *)(&a +1));
printf("%d, %d\n", *(a + 1), *(ptr - 1));
return 0;
}
输出结果:
address a[0] = 0x7ffc494a8200
address a[1] = 0x7ffc494a8204
address a[2] = 0x7ffc494a8208
address a[3] = 0x7ffc494a820c
address a[4] = 0x7ffc494a8210
address a:0x7ffc494a8200
address &a:0x7ffc494a8200
address a+1:0x7ffc494a8204
address &a+1:0x7ffc494a8214
size a:20
size &a:8
address (int *)(&a + 1):0x7ffc494a8214
address (int *)(&a + 1):0x7ffc494a8214
2, 5
图解:
上面的输出结果对应的图,更容易理解