目录
如对您有帮助,还望三连支持,谢谢!!!
1.内存和地址
计算机中常⻅的单位(补充):
如何理解编址
2.指针变量和地址
2.1取地址操作符(&)
2.2指针变量和解引用操作符(*)
2.2-1指针变量
2.2-2如何理解指针变量
2.2-3解引用操作符
2.3指针变量的大小
3.指针变量类型的意义
3.1指针的解引用:
3.2指针+-整数:
4.const修饰指针
4.1const指针变量:
4.2const修饰指针变量:
5.指针运算
5.1指针+-整数
5.2指针-指针
5.3指针关系运算
6.野指针
指针未初始化:
指针越界访问:
指针指向已经释放了的空间:
如对您有帮助,还望三连支持,谢谢!!!
前言:指针通常被认为是c语言中比较难的知识,今天我们就来用大致5篇文章来带领大家深入理解指针,使读者对指针有更加深刻的认识。
1.内存和地址
在讲解指针之前,我们要先了解一下内存和地址,由于指针知识相对有点小抽象,所以我们尽量以举例子的形式给大家讲解,就比如我们生活中的例子:
我们上大学时为了管理学生,把学生分配到了一个个的宿舍房间中,每个房间都有固定的人数:比如6人寝,4人寝。
我们姑且认为是八人寝(有点夸张了哈哈):
一个寝室由八个人组成,而这个寝室就相当于一个内存单元;寝室里面的每个学生就相当于组成内存单元的一个比特位。
计算机内存就是由一个个内存单元(寝室)组成的,单位为字节。
了解了这个后,我么再来想一个问题:如果我要找二楼一个特定的房间,怎么找?
为了更好的管理寝室,每个寝室都有一个寝室号,也就是门牌号:
就如上图所示,有了门牌号,就能更加方便的找到我们想要的寝室了。
而门牌号就相当于地址,有了地址(门牌号),就能更快的找到特定的寝室(内存单元)。
通过这个例子,我们就对内存单元和地址的关系有了一个初步的了解。
放在计算机中来说:
我们知道计算上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数
据也会放回内存中,那我们买电脑的时候,电脑上内存是8GB/16GB/32GB等,那这些内存空间如何⾼效的管理呢?
其实也是把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节。
计算机中常⻅的单位(补充):
在生活中我们把门牌号叫做地址,在计算机中我们把内存单元的编号也成为地址,c语言给地址起了一个新的名字:指针
所以我们可以理解为:
内存单元的编号==地址==指针
如何理解编址
有读者会问,为什么地址是0XFFFFFFFF这个长度呢?长度不能是别的数了吗?这就涉及到计算机组成原理的知识了:
CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,⽽因为内存中字很多,所以需要给内存进⾏编址(就如同宿舍很多,需要给宿舍编号⼀样)。
计算机中的编址,并是把每个字节的地址记录下来,⽽是通过硬件设计完成的。
地址总线32位环境下有32根,所以地址长度为32,表示成16进制,所以才会是8个数字表示一个地址。
这里了解一下即可。
2.指针变量和地址
2.1取地址操作符(&)
理解了内存和地址的关系,我们再回到C语⾔,在C语⾔中创建变量其实就是向内存申请空间,⽐如:
⽐如,上述的代码就是创建了整型变量a,内存中申请4个字节,⽤于存放整数10,其中每个字节都有地址,我们通过调试可得到:
如上图所示,我们通过调试获取了整型变量a的地址,那么我们想要得到a的地址,又该怎么做呢?这时候就得用&操作符,代码如下:
如上图所示,我们就成功的取出了a的地址并将结果打印了出来,假设我们的打印结果006FFD70,则a在内存中的储存大致如下图所示:
我们取出了a的4个字节中最小的地址。虽然整型变量占⽤4个字节,我们只要知道了第⼀个字节地址,顺藤摸⽠访问到4个字节的数据也是可⾏的。
2.2指针变量和解引用操作符(*)
2.2-1指针变量
上面讲了如何取出a的地址,但是我们取出a的地址,要把他存放起来,以便以后使用,这时我们应该把它存放在哪里呢?
答案:指针变量
指针变量也是一个变量,用来存放地址,存在指针变量中的值会被认为是地址。
2.2-2如何理解指针变量
如上图,int*pa=&a,其中*说明pa是一个指针变量,int说明pa指向的是int类型的对象。
那如果char b='w',这时候又该用什么类型的指针来接受呢?
char*pb=&b;
用char类型的指针接收char类型的数据地址。
2.2-3解引用操作符
们将地址保存起来,未来是要使⽤的,那怎么使⽤呢?
在现实⽣活中,我们使⽤地址要找到⼀个房间,在房间⾥可以拿去或者存放物品。
C语⾔中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)
指向的对象,这⾥必须学习⼀个操作符叫解引⽤操作符(*)。
上面的代码我们创建了一个整形a和一个int类型的指针pa指向a,
然后我们通过解引用操作符(*)找到a并将a的值修改为了1。
有同学肯定在想,这⾥如果⽬的就是把a改成0的话,写成 a = 0; 不就完了,为啥⾮要使⽤指针呢?
其实这⾥是把a的修改交给了pa来操作,这样对a的修改,就多了⼀种的途径,写代码就会更加灵活,后期慢慢就能理解了。
2.3指针变量的大小
我们上面讲了指针变量存放的是地址,所以指针变量的大小取决于地址的大小。
而在X64环境中,有64根地址线,所以地址大小为8个字节。
在X86环境中,有32根地址线,所以地址大小为4个字节。
3.指针变量类型的意义
既然我们上面讲了不管什么类型的指针变量,大小都为4/8个字节,那么不同类型的指针变量又有什么意义呢?
3.1指针的解引用:
通过调试我们可以看到,代码一对pi解引用会把n的四个字节全部修改为0;
而代码二对pc解引用只会把n的第一个字节修改为0
由此我们可以得出以下结论:
指针的类型决定了:对指针解引用时有多大的访问权限(一次能访问操作几个字节)
比如:char*的指针解引用能访问一个字节,int*解引用能访问4个字节。
3.2指针+-整数:
代码运行结果如下:
我们通过上面的代码发现:pc指针加1跳过了一个字节(地址加了一),而pi指针加一跳过了四个字节(地址加了4)。这就是不同类型指针所带来的变化。
结论:指针的类型决定了指针向前或者向后走一步的距离有多大
4.const修饰指针
4.1const指针变量:
变量是可以被修改的,可以直接修改,也可以通过指针的方式修改,那么如果我们想要一个变量加上一些限制,使其不能被修改,该怎么做呢?这时就要用到const。
那么,此时问题来了,被const修饰的变量的值一定能被修改吗?
答案:可以。
我们虽然不能直接修改,但是我们可以通过指针来访问改变量,从而修改该变量的值。
4.2const修饰指针变量:
这段代码,我们运行可以初步看出:const在*左边,影响的是指针指向的内容,是指针指向的内容不能被修改;const在*右边,影响的是指针本身,指针本身的值不能被修改。
结论:const修饰指针变量的时候
• const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。
但是指针变量本⾝的内容可变。
• const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指
向的内容,可以通过指针改变。
5.指针运算
指针运算大致可分为以下三种:
5.1指针+-整数
我们都知道数组在内存中是连续存放的,所以我们可以通过指针顺藤摸瓜打印出数组内容:
5.2指针-指针
strlen的模拟实现,这种方式就是指针减去指针,我们以前再讲字符串函数的时候讲过,不再赘述。
5.3指针关系运算
arr+sz指针跳过了整个数组,指向紧挨数组后面的地址;p初始时是数组首元素的地址,通过比较这两个指针,打印出来了数组的内容。
6.野指针
概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
指针未初始化:
指针越界访问:
指针指向已经释放了的空间:
所以我们在写代码时,要尽量的避开野指针。
避开野指针,我们就要养成良好的代码风格:指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性;避免返回局部变量的地址等等
至此,我们已经初步认识了解了指针。下篇文章我们将更深层次的讲解指针的知识。