| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> 直接带你对指针进行一个门的入|指针初阶 -> 正文阅读 |
|
[C++知识库]直接带你对指针进行一个门的入|指针初阶 |
一、首先,什么是指针? ? ? 如果我有事要找住在酒店中的某个人,那我得先知道他具体住在酒店的哪里,比如他住在xx层房间号为x0x,根据他的住址我们就可以找到他。 ? ? 内存就相当于一个大的酒店,而内存中存储的数据就相当于住在酒店房间的人,每个人住在不同的房间,同样每个数据被存储在不同的格子中;我们在编写程序的时候经常会由于需要去调用内存中的某个数据,但是很多时候不知道数据在哪,换言之,不知道数据的“地址”从而无法找到他。那么这时……
? ? 指针指针,那它不就是指引的那根针嘛;指针之中存放的就是这个数据在内存中的地址,根据这个地址我们很容易就可以在内存中找到我们想要的数据。 二、关于指针的一些常规操作 1、定义指针变量 ???在指针前面写上指针指向的数据类型,同时*表示这是一个指针(如整型指针p写作int*p) 2、取地址 ?? 既然指针是存放地址的,那么我们要使指针指向这个数据,就需要取出数据的地址,并且将地址赋给指针变量,这里需要用到取地址符&
? ? 观察上面这个例子,定义i为整型变量,那么它在内存中占了4个字节(相当于4个格子,假设一个格子是一个字节),每个格子都有自己的地址,但是&i取出的是第一个格子的地址,因为我们已经定义了指针类型为int类型,那么它就会从第一个格子开始往后数四个。(好吧,其实我觉得电脑才是最懒的人) ? ? ? ? 与此同时,指针p同样需要在内存中占据空间,在32位中指针是4个字节,64位中指针是8个字节,我们假设这里的指针p是4个字节,那么指针p中就会存放上面 i 占据的四个格子中第一个格子的地址。 3、解引用 ? ? ?*为解引用操作符,&为取地址符,二者互为逆运算;取地址符是指取出内存中数据的地址,那么解引用符就是指向这个地址的数据。 ? ? 换句话说,解引用+指针 等价于 指针指向的数据 三、指针有哪些类型? ? ? 在介绍下面指针的这些不同类型之前,我们首先要搞明白一件这样的事:为什么要区分不同的指针类型? 1、操作的字节数不同
? ? 通过以上两个例子可以看出,指针的类型不同,操作范围也不相同,整型指针可以操作4个字节,而字符型指针只能操作1个字节;因此,指针类型决定了指针在被解引用时访问的权限。 2、指针每走一步跨过的距离不同 ? ? 通过上图对比,不难发现,对于整型指针pa来说,指针每加一跨过的是一个整数即为4个字节;对于字符型指针pc来说,指针每加一跨过的是一个字符即为1个字节 下面可以来康康应用:
? ? 定义整型arr数组,数组中有10个元素,说明在内存中开辟了40个字节的空间。这里的arr数组元素原本为int类型,因此指针类型也应该是int*,但是整型指针每向前一步跨过一个整数即为4个字节,如果我们想要一个字节一个字节地进行访问,那么这时我们只能使用字符型指针。无论是4个字节4个字节的访问,还是1个字节1个字节的访问,我们都需要将第一个字节的地址存放在指针中,因为数组名代表数组首元素地址,因此char*p等于数组名arr,但是数组本身是整型数组,因此数组首元素地址是int*类型的,要放到字符型指针里面就要进行强制类型转换。其中w放在4个字节里,结果却不是它的4倍,是把这4个字节当作一个int看的(如果在监视中观察a[i]中存储的ASCII码值的话) ? ? 那么,如果4个字节4个字节地访问呢?
? ? 我们还是获取了数组arr的数组名即为首元素地址,因为数组本身存放的即为整型,因此不需要强制类型转换,地址类型本身即为int*类型,因为int类型是4个字节,所以p++,地址每+1访问的应该是跨过sizeof(int)即为4个字节,同时*p=‘w’将数组的每个元素都改为了w ? ? 酒店肯定不会因为你是歪果仁,或者是男/女就拒绝你入住吧,那么内存也是同样,每个房间里存放的数据也并非单一类型,由于指针指向的数据类型不同,指针也因此分为不同类型 ? ? 因为这篇文章算是指针入门介绍,所以在这里只列举了几种基本的指针类型: 四、野指针 什么是野指针? 顾名思义,野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的) 导致野指针的原因有以下三种: 1、未对指针进行初始化
? ? 我们声明了p这个指针变量,但从未对它进行初始化,里面放的是一个随机值,所以没有办法预测10这个地方存储在什么地方。如果变量是静态的,它会被初始化为0,但如果变量是自动的,它根本不会被初始化。 ? ? 如果想要不出现野指针,这里第一行可以写做int*p=NULL,NULL指针是一个特殊的指针变量,它表示不指向任何东西,所以同样不能对这个指针进行解引用操作。 2、指针进行越界访问 ? ? ? 数组中只有5个元素,定义整型指针p存放数组首元素地址,也就是从数组第一个元素开始访问,每次访问数组中的一个元素,但是后面的for循环却循环了10次,在访问完数组的5个元素之后接着对后面的元素进行访问就属于越界访问了。 3、指针指向的空间释放
? ? 上面test函数的变量a是进入函数创建,但是一旦出了这个函数a就会被销毁,内存空间就会还给操作系统不属于当前程序了,那么这个时候p里面存储的地址就无法使用了,指针p也会变成野指针。 ? ? 就好比我今天在酒店102订了房间并且电话叫好盆友过来住,但是他今天却没有时间,第二天我退了房间后,他来了,那他现在就没办法住了鸭😊 如何规避野指针? 1、指针初始化
? ? 在我们还没想好对指针p初始化什么值的时候,我们可以先让它等于空指针NULL,当指针不是空指针时,我们再去用它 2、小心指针越界 3、指针指向空间释放之后及时将指针置为空指针 ? ? 就是它存放的地址没用了之后赶紧放上NULL 4、避免返回局部变量地址 ? ? 就是尽量不返回在一个函数里面的变量哦~ 5、指针使用之前检查有效性 ? ? 如果指针为空指针我就不使用它了,当它是空指针的时候我再去使用它 五、指针运算 1、指针加减整数/关系运算 指针可以进行加一减一的操作,并且指针每行动一步跨过sizeof(指针指向的变量类型)个字节 ? ? 可以来看一下这段代码,首先定义了一个含有5个元素的数组arr,定义整型指针p,接着运用for循环,使得指针p指向的为数组首元素地址,同时p小于arr第五个元素的地址,p++,即对p进行+1的操作,同时打印出*p。因为指针也是有大小的,所以指针可以比较大小,比如p<&arr[5],就是进行指针的关系运算。 ? ? 这段代码其实还有可优化之处,我们可以把p++与*p合在一起,即为*p++,对p进行解引用之后再++,最终打印出来的效果也还是一样的
2、指针减指针运算
? ? 这里打印的两个地址相减的结果,其实就是在算两个指针相减,最终运行结果为9,代表两个指针之间有9个元素。因此,当两个指针指向同一块空间时,指针减去指针所得结果的绝对值为指针之间元素的个数 ? ? 那么这个东西有什么用呢?我们来看下面的代码,不调用库函数strlen来实现我们自己求字符串长度的一个函数
? ? 运行结果为6,首先我们在arr数组中存放了一个字符串,注意在f后面还有一个\0,要计算这个字符串中有几个字符,可以用\0的地址,减去a的地址,通过指针减指针,来计算出有多少个字符 ??因为从数组首元素地址开始,所以我们将arr数组名传给my_strlen函数并用char*str指针接收这个char类型变量的地址,同时指针减指针得到的是指针之间元素的个数,因此函数的返回类型为int类型。将第一个元素的地址赋给新的指针char*start代表第一个字符,而后用while循环,*str表示str指针指向的元素,从第一个元素开始,只要指向的元素不是\0(因为\0的ASCII码值就是0)str就++继续往后走,直到\0,最终返回str-start,指针减指针,算出字符串中字符的个数并进行打印。 六、下面我想来说一说我之前学习指针混淆的一些地方 易错点1:指针 等价于 指针指向变量的地址 ? ? ?我也不理解为什么我之前总是认为这二者之间存在某种神秘的隔阂╮(╯-╰)╭明明定义中说的清清楚楚,指针就是用来存放地址的,这两者完全可以画上等号鸭,这就相当于,我用袋子装着写着你地址的小纸条 跟 我直接拿着写着你地址的小纸条 去找你,效果是完全一样滴,都可以找到你鸭? ψ(`?′)ψ ? ? 因此,指针有不同类型的区别,同样地址也有;指针的类型有int*,char*等等,那地址当然也一样喽 易错点2:指针的类型 不等于 指针指向的变量类型 ?就拿最简单的这个int*p指针来举例叭,我们都知道这里定义了一个指针变量,指针的名字叫做p,删去指针的名字p,剩下的内容是指针的类型int*,指针的类型就表明这是一个指向整型的指针变量;同样,删去指针名字p和它前面的*表示的就是指针指向的类型int 易错点3:指针类型不同不代表指针大小不同 ? ? 虽然p1指针和p2指针类型不同,但是两个指针都是用来存放地址的,无论是整型地址还是字符型地址,地址都是64个比特位,要把这个地址存起来所需要的空间自然也是一样的。 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 7:16:45- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |