地址就像是变量的身份证
运算符 &
对变量进行运算, 返回这个变量的地址
- 本地变量定义在栈中是自上而下的
- 数组
a,&a,&a[0]
地址相同, 相邻地址差一个字节数, 下标大的地址大
输出时:
int i = 0;
printf("0x%x\n", &i); // 会有汪咛, 因为c出地址有更好的
printf("%p\n", &i); // %p
int i = 0;
int p;
p = (int)&i // 不加int有汪咛
printf("0x%x\n", p); // 没有汪咛了
printf("%p\n", &i); // %p
所以地址数据类型有别于整形, 又有关于整形 (以上结果在32位或64位结果会不同)
指针类型变量
就是专门去保存那个形如&i
的变量
当我们说 p指向 i其实是说, p这个变量里面存放的是 i的地址
int* p,q;
int *p,q;
两种写法没区别, 但那时p
是指针了, q
还是一个int
* 给的是p, 不是int
事后金: 这里 p是一个指针变量, 访问指向 p的变量的方法是 *p
好, 也就是说, p是指针, *p是变量, 每个类型数据都有其对应地址, 所以这个定义指针的方式是多么巧妙
至于我指向的到底是数组呢还是单个元素呢? 绝对是单个元素的地址 因为我指向一个地方, 这个地方只有一个类型, 如果它恰好是数组, 有一块连续的内存空间 那我可以通过地址的运算得到数组的其他值, 看起来就像”指向了数组”
作为函数参数的指针
void f(int *p);
被调用时得到某个变量的地址
int i=0; f(&i)
- 在函数里可以通过这个指针 访问 外面的这个i 普通的传值只传值, 之间没有任何关系
这里没什么新奇的, 变量是指针变量, 同样传入的是值, 只不过这个值是地址而已 牛逼的是地址
什么时候会用到呢?
- 当我们需要返回多个值的时候, 就可以传入地址, 传入的*地址就是”接收”返回值的变量 传进去的是参数, 作用是把结果带出来
- 函数需要返回运行状态(0,-1之类的), 这时候函数的返回结果怎么办? 利用地址 其实思路是差不多的
访问地址上的变量
*是一个单目运算符
- *[地址] 可以完整的作为变量, 当左值当右值
- 可以给指针用, 也可以给数组用
int *p;
int k=12;
*p = 2;
有问题吗? ——太有问题了, 定义了指针变量, 却没有传入地址, 那么在写入这个地址的变量的时候, 要是不凑巧就崩溃了
指针运算
+1是+一个单元, 而单元==sizeof(类型) 也就是字节
- 给指针 +,-,+=,-= 一个数
- ++,—
- 两个指针相减
- 返回整数, 是地址差/sizeof(类型) 也就是 “间距 ”
- 可以比较指针的大小 (就是地址数值的大小)
- 实际上指针运算的意义在于内存上的一块连续区域, 也就是数组
不是连续区域的话, 意义不是很大
不确定, 反正我实际写的时候出了问题
指针与数组
数组变量是const的指针
int b[]
⇒int * const b
int a[5] = {0};
int vir=2;
a[0]=1;
int *b=a;
cout<<b[0]<<endl; // 1
cout<<(&vir)[0]; // 2
- 数组变量名是地址常量, 所以赋给指针变量可以实现数组的浅复制
我好像知道为什么会有浅复制了 a==&a[0]
- []运算符可以对数组(名常量)做, 也可以对指针做 说白了就是对地址做
*(b+n)
⇐>a[n]
数组中的元素在内存中是连续依次排列的
void b(int* c) {
c++;
*c = 1;
}
int main(){
int a[5] = {0};
b(a);
cout<<a[1]; // 1
return 0;
}
这也看到了以数组做参数可以用起码两种方式
void f(int a[])
void f(int *a)
指针与const
常量指针
const int *p
或int const *p
- 不能改p指向的变量的值, (当然啦, 这个变量本身可以改的)
- 但可以改p所指向的地址
指针常量
int * const p
- 不能改p指向的地址
- 但可以改p所指向的变量的值
动态内存分配
题外话
0地址 NULL
0地址通常是不能随便碰的地址 要使用0地址最好用NULL, 因为有的编译器不喜欢用0
指针的类型转换
void*
表示不知道指向什么的指针 往往用在底层开发中
- 计算时与
char*
相同, 但不相通 - 用于转换类型:
int *p=&i; void *q=(void*)p;
- 这没有改变p所指的变量类型, 而是让后人用不同的眼光通过p看它指的变量
- 我不再当你是int啦, 我认为你就是个void