⚔️1.2 指针
🗡1.2.1 指针究竟是什么
先放上一张神图。大名鼎鼎的冯·诺伊曼体系结构。
可以发现运算器能直接读取的程序是在存储器内的。那么运算器怎么拿到这个数据呢?
首先我们先明确,因为变量的读取都是从内存中的,所以一定会有一片空间在内存中。我们把它想象成有一栋公寓有一堆房间,我们想要找到我们的房间是不是得有个房间号?
然后有没有发现102 103 104 105这四个房间我没画隔断,因为很多地方是按照门来编号的,但是一个大房间可能对应多个门呀。
上面的门的编号方式就是编制方式(可以一个门一个号,也可以两个门一个号),地址就每个门的房号,然后数据其实就是门内的内容。
我们根据房号找到家,计算机就是根据地址找到数据。
指针其实就是地址。也就是上面的房号。
我们假如忘了门号就看看外面门上的标识牌对吧?计算机内如果变量想要直到自己的地址也是需要看看自己的房号,怎么去看呢?用&,因为是变量自己看所以就是&x就拿到地址啦0.0
举个例子:
#include<cstdio> int main(){ int a = 0; printf("%d %d\n", &a,a); return 0; }
输出结果可能是:2686748 1
其中地址是一个unsigned类型的整数(64位是unsigned longlong),至于为啥是无符号的,你见过谁家房号是负数么0.0
🛡1.2.2 指针变量
指针变量用来存放地址,然后可以看下图,就是指针变量,比较厉害,手里有把钥匙,并且这个钥匙可以开对应的门。
然后由于这是一把钥匙,所以在声明它的时候需要在它前面加个*,表示它是一把钥匙。也就是int *p;,一般来说都是把*放在变量前面。
同时*也表示拿钥匙开门,*p就表示拿到对应的数据,所以图上的就是104号房间对应的元素。
刚才知道&是取地址,就是看看房间号,那么p = &a就可以把p这把钥匙变成a所对应的地址。此时再去*p就是a的值。
看下面的程序:
#include<cstdio> int main(){ int a; int *p = &a; *p = 233; printf("%d %d", *p, a); return 0; }
输出结果是233 233,因为开房间的优先级很高,在赋值的时候是先打开门,再把数据写入,所以就把值写入到了a之中。最后输出就是两次a的值。
最后说明一下,不同的指针是不同的,比如下面的两把钥匙是不一样的。因为102-105是连着的,所以第一把钥匙钥匙+1实际地址会加4,而右边的指针对应的只有一个门,+1的时候只会加1,
其实对应的就是int *和char *类型的指针,其中一个长度为4,另一个为1。
这个指针的类型叫做基类型。
🔧1.2.3 指针与数组
之前有提到过数组就是一片连续的空间,数组名称也作为数组的首地址使用。
根据上面提到的指针加1等于加对应的数据长度,所以a+i和&a[i]是完全相同的。
在枚举元素的时候可以这么写:
#include<cstdio> int main(){ int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; for(int *p = a; p < a +10;p+) printf("%d ",*p); return 0; }
指针的减法
#include<cstdio> int main(){ int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int *p = a; int *q = &a[5]; printf("p = %d ", p); printf("q = %d ", q); printf("q - p = %d",q - p); }
输出结果是:p = 2686688 q = 2686708 q - p = 5
会不会感觉震惊?这个q-p竟然不是20???,其实指针的减法是计算两个指针直接差多少个基类型,因为是int所以返回的就是相差多少个int。
⚒1.2.4 使用指针变量作为函数参数
指针变量也可以作为函数的参数,这时会把变量的地址传入函数。如果在函数中对这个地址中的元素进行修改,那么原本的数据也会修改。
例如:
#include<cstdio> void swap(int *a, int *b){ int temp = *a; *a = * b; *b = temp; } int main(){ int a = 1, b = 2; swap(&a,&b); printf("%d %d",a , b); return 0; }
结果就是2 1,是不是就做到了?但是为啥呢?我们来看看这个过程
可以发现在执行的过程中,swap直接改的就是原内存空间的值,当然改成功啦0.0
我们再看一个错误写法:
void swap(int *a,int *b){ int *temp = a; a = b; b = temp; }
这个如果看图就是讲swap调用栈里的a和b的值改了,并没有对之前的a和b造成任何影响。
🔨1.2.6 引用
引用是C++中一个强有力的写法,引用时候不产生副本,只是给原变量起了个别名。对引用变量的操作就是对原始变量的操作。
看一个例子:
#include<cstdio> void change(int &b){ b = 1; } int main(){ int x = 10; change(x); printf("%d\n",x); return 0; }
上面打印的结果就是1。
其实底层实现的话就是使用的指针,我猜想应该是使用的不可修改指针进行实现的。感兴趣的话可以看看这篇博客。理解C++中引用的底层实现
但是要注意:
#include<cstdio> void swap(int &a, int &b){ int temp = a; a = b; b = temp; } int main(){ int a = 1, b = 2; swap(&a,&b); return 0; }
上面的写法会直接报错,因为a和b的地址都是常量,所有声明的变量的地址都是常量不可进行修改!!!所以引用的时候不能传入变量的取地址。
关于指针的一些知识点我写了一篇文章做总结,如果大家有兴趣的话可以去阅读一下,保证会有更深的理解0.0
关于室友收租懂了指针那点事
🐳课后习题
今天的题目难度也不高,也不老多 哈哈哈哈哈,我写完会放题解,大家写完了可以在评论区打卡哟!我觉得,题解我放评论区吧,这样不用修改文章。(大家有问题可以联系我,今天太晚了,题解等明天把)
题目
2.6小节——C/C++快速入门->函数
2.7小节——C/C++快速入门->指针