本篇主要围绕指针是什么?为什么存在?和怎么用指针?这三个问题来讨论。
1.什么是指针和指针变量
我们知道,我们把内存划分成一个个(一字节大小)内存单元后,为了区分每个内存单元,因此我们给内存单元的赋予了一个编号,而这个编号我们可以称作他为地址或者指针。所以得到结论:
内存单元编号=内存地址=指针
而我们口头上经常说;“定义了一个某某类型的指针”并不严谨,这里指的并不是这里的内存单元编号,而是指针变量。所以大家听到这些话不要误解,这是口头习惯,但自己心里要明白。
其次,针对指针变量,我想问大家指针变量是不是变量?和int a;这些变量也没有区别?
在回答这个之前,我先向大家介绍一下:变量的左右值问题
那什么是左右值问题呢?
*左右值问题
先给大家上案例,问:第1个a是指的是什么意思,第二个呢?
int a = 0;
a = 10;---1
int b = a;--2
给大家三十秒时间思考
Sleep(30000);
好,时间到。
正确答案是:第一个a指的是a变量所在的空间。
第二个指的是把a的内容赋给b。
由此我们发现,同一变量,由于在等号的位置不同,其含义也不相同。这就是左右值问题。
那么现在看到这段代码
int *a = NULL;
a = (int*)0x1234;
int* b = a;
大家就能很快地发现了吧,和上面并无二致,也是一个指空间一个指的是内容。当指针变量作为右值时,此时指的是指针变量的内容也就是地址, 是可以视作 指针变量==指针的
那么回到刚刚那个问题,得到结论:
指针变量也是变量,和其他的变量别无两样,可不能把指针变量想复杂了。
2.为什么要有指针
说了这么多,可能有人问,为什么要有指针?
举一个通俗易懂的例子:把指针比喻成现实中的公寓门牌号,有人点了外卖,外卖小哥要送到你的面前,是不是需要知道你在哪栋楼几零几,知道这个才能准确的快速的送到你的手上。如果没有了这个门牌号,外卖小哥可能得一个一个的敲门,所以门牌号可以提高查找效率。
把这个例子放到计算机上之前,我先向大家阐述一下CPU和内存的关系:
*CPU和内存关系图
对于数据总线和地址总线现阶段我们可以简单认为CPU和内存是共用的,CPU通过总线把地址数据传给内存,内存再根据相应的地址,将数据通过总线传给CPU。
我们知道,计算机只认识二进制。why?在32位机器下,有32根地址线,通过每根先电信号的有无来说明1和0的(硬件问题),所以计算机只能认识二进制。
什么是编址?
即地址总线的排列组合:
00000000000000000000000000000000
....
11111111111111111111111111111111
我们知道CPU用于计算,内存用于存储数据,计算时需要CPU从内存中拿取数据才能计算。如果没有指针(地址)这个概念,CPU怎么知道要怎么拿自己需要的数据呢?况且还可能拿错。所以指针的存在是非常的必要的,可以保证CPU从内存获取数据的准确和高效。
3.指针的使用
指针的使用,即地址的使用,通常存在两种情况:直接和间接
int a = 0;
*(int*)0x11223344=10;//指针字面值直接使用---1
int* q =*(int*)0x11223344;//通过指针变量间接使用---2
*q = 10;
return 0;
先不论代码能否执行,首先我们能看出一点直接使用非常的不方便,每次使用还得敲一串,赋给指针变量更加高效。不过实际使用时这样的代码的1,2均不能执行,因为操作系统不会让你直接访问确定的地址的,因为这样并不安全,可能你输入的地址压根没有权限访问。
正确的方式应该采用以下:
int a = 0;
int* p = &a;
*p = 10;
可能有同学会问,你说不能访问是没有权限,那我第一次运行记住变量a的地址,下一次执行前把我上一次记录的a的地址直接赋给p,不肯定能访问了。
但内存的栈随机化的存在,解决了这个问题,即栈上的变量,每一次运行的地址都不同,这其是内存的一种保护机制。
今天的文章就到这里,感谢浏览!!!