1.取地址运算
1.1
1.2
- 打印出变量的地址,需要使用 %p,注意后面加运算符 & 。注意输出地址的代码格式。
- %p会把这个值作地址来输出,输出的结果前面会加0x,并且以16进制的方式来输出地址
- 注意int 的大小是否和地址大小相同取决于编译器32架构还是64架构(地址和整数不是一定相同的)
&去取地址的时候,必须对 一个变量 取地址!(如果不是一个变量,无法取地址)
1.3
-
相邻变量的地址:
如果两个变量储存在内存中是相邻的,那么他们的地址相差4字节(int类)
-
数组的地址:
发现int类数组相邻单元的地址差4字节
2.指针
指针变量就是记录地址的变量
2.1
“ *p ” 在这表示p是指针变量,它指向的是int。
p指向了i,即p的值就是i变量的地址
int* p,q;
int *p,q;
这两种代码是等效的
星号不是给int而是给p,即 *p 是一个int类变量
q只是一个普通的变量。如果要表达p,q都是指针变量:
int *p,*q;//p,q里面会有别的变量的地址
- 指针变量的值是 具有实际值的变量的 地址,这个地址会指向实际的变量
- 指针变量里面不会放实际的值
- 普通变量的值是实际的值
2.2 作为参数的指针
- 如果f()函数需要指针变量作为参数,那么就需要传入变量的地址,而不可以传入变量本身或者变量的值
在main函数中的变量i的地址传入f()函数,并把i的地址交给了f函数中的变量p。使得f函数拥有能够访问外部变量i的能力了
那么,p就是一个指针,它指向i这个变量。
- 如果函数要求传入的是普通变量,那么只会得到变量的值
2.3 访问
- 将&i 和 p 做地址输出,结果是一样的。在这里p就是指针变量,他已将被传入了变量的地址。所以在输出地址的时候,结果是一样的。
- “p的值就是i的地址”
int a[] = {0};
int *p = a;
——>p == &a[0]表达式的值是True
- *号在这里作为单目运算符,表示要访问对应地址的变量。*p就是i,使用%d输出 i 的值。
随后添加的代码 *p = 26;
实际就是i = 26;
3.指针与数组
- 实际上,在函数中传入的数组参数实际上就是指针变量。
- 将
void minmax(int a[], int len, int *min, int *max)
中的 a[ ] 写成 *a 指针的形式完全没有问题,int sum(int *a);
和int sum(int a[]);
这两种作为函数原型的写法是等价的。尽管函数体内部仍然使用了数组a[ ] - 这就解释了为什么在函数参数那里不能使用sizeof()函数进行数组长度的计算
数组其实 “可以被看做”是常量指针 - 数组变量本身表达的是数组的起始地址,也就是第一个元素的地址;所以
int *p = a;
等效于int *p = &a[0];
- 变量的地址——>变量
&a 表示数组a的初始地址(&号可以省略),即第一个元素的地址
&a[0] 表示数组第一个元素的地址
&a[1] 表示数组第二个元素的地址
- 关于 指针[ ] 访问
int a[] = { 5,15,34,54,14,2,52,72 };
int* p = &a[5];
printf("%d", p[-2]);
代码中指针变量p指向了数组a的第6个数据:2,下一步执行p[-2]操作,是向前移动2个位置,即第4个数据:54。所以输出结果是54
int a[] = {5,15,34,54,14,2,52,72};
int *p = &a[1];
同理,p[2]的值是54
int a[] = {0};
int *p = a;
那么以下表达式的结果为真:
p == &a[0];//p的值就是a第一个数据的地址
*p == a[0];//指向第一个数据,*p就表示访问对应地址的数据
p[0] == a[0];//p[0]是数组的访问方式,表示访问数据后后移0个单位,还是原来*p那个数据