初阶指针(详细版)

news2025/4/28 8:58:38

目录

一、指针是什么

                1、内存

                2、内存的管理与使用                

                3、指针变量的使用

二、指针和指针类型

              1、指针类型的意义

              2、指针+ 或 - 整数 

              3、指针解引用

三、野指针

              1、野指针成因

              2、如何规避野指针

四、指针运算

             1、指针+-整数

             2、指针 - 指针

                             指针 - 指针的运用(求字符串)

            3、指针的关系运算(比较大小) 

五、指针和数组

六、二级指针

            1、什么是二级指针

            2、二级指针的运算

七、指针数组

            1、什么是指针数组

            2、用一位数组模拟二维数组


一、指针是什么

这部分在以往初识C语言将的比较细点(初识C语音---指针),这里就简单为大家回忆一下

1、内存

想要理解什么是指针,必须先了解什么是内存。内存是电脑上的存储设备,一般都是4G/8G/16G等,程序运行的时候会加载到内存中,也会使用内存空间,例如任务管理器:

 2、内存的管理与使用

我们将内存划分为一个个小格子,每一个格子是一个内存单元,大小为一个字节,对每一个内存单元进行编号,假设未来要找一个内存单元,就可以通过编号很快的找到,我们把这些编号叫做地址,而地址在c语言中又叫做指针

举一个例子,在下图中,假设定义一个变量 int a=10,一个int类型的变量,需要占4个字节的空间,而每个空间都有地址,&a取出的是哪一个的地址呢?其实取出的是第一个字节的地址(也就是较小的地址),也就是说,&a最终取出来的地址是0x0012ff40 ,当然,可以把这个地址存到一个变量中,int* pa=&a,*表示pa是一个指针,int代表pa所指向的类型是int类型,这个pa也叫做指针变量(它是专门用来存放地址的)。

指针理解的2个要点:

1、指针是内存中一个最小的单元编号,也就是地址。

2、平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。

总结:指针就是地址,口语中说的指针通常指的是指针变量。

 3、指针变量的使用

通过以上代码就验证了,指针变量p存放的就是a的地址。

接下来,我们可以使用*解引用操作符来对其使用

总结:指针变量,就是用来存放地址的变量。(存放在指针中的值都被当成地址处理)。

那么问题来了:一个内存单元到底是多大? --- 刚刚讲过,就是一个字节

那它又是如何编址的呢?

经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。 对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0)

那么32根地址线产生的地址就会是:

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000001

.....

11111111 11111111 11111111 11111111

这里就有2的32次方个地址。 一个地址管理一个内存单元,那么2的32次方个地址就能管理2的32次方个内存单元,也就是2的32次方个字节,那2的32次方个字节又是多大空间呢?

根据进制转化:

2^32Byte = 2^32÷1024KB÷1024MB÷1024GB = 4GB

同样的方法,64位机器,也可以计算出来。

这里我们就明白:

•在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以 一个指针变量的大小就应该是4个字节。

•那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址。

总结:

•指针变量是用来存放地址的,地址是唯一标示一个内存单元的。

•指针的大小在32位平台是4个字节,在64位平台是8个字节

二、指针和指针类型

1、指针类型的意义

通过上面我们知道了

32位机器,地址是4个字节,指针变量大小是4个字节。

64位机器,地址是8个字节,指针变量大小是8个字节。

这时有人就很疑惑,假设在32位机器上,大家都是4个字节,直接搞一个通用指针不就完事了,那为什么要区分int*、char*、double*这些呢?那它肯定就有特殊的意义。

先看看下面的代码

 我们可以通过调试来观察变量a在内存中的变化

调试:先按下F10

为了方便观察,我们把它调成4列

 我们发现,内存中确实存的是44332211,只不过是倒着放的,这个后期会讲。

接着按F10再往下走

我们发现,4个字节全部被改为0,这说明a的值确实被修改成0了

假设我把指针变量pa的类型改为char*结果又会是如何呢?

可以继续通过观察其内存变化

 继续按F10

它只改变了1个字节!! 

总结:指针类型其实是有意义的

1、指针类型决定了,指针在进行解引用操作的时候,一次性访问几个字节

如果是char*类型的指针,解引用访问内存中的一个字节

如果是int*类型的指针,解引用访问内存中的四个字节

float*和double*也同样如此......

指针类型还要其它意义,接着往下看

 我们发现,pa+1跳过了4个字节,pc+1跳过了1个字节

总结:

指针类型的意义2:指针类型决定指针的步长(指针+1到底跳过几个字节)

字符指针+1,跳过1个字节

整型指针+1,跳过4个字节

其它类型的指针也是如此......

它的用途是什么呢?

举个例子

因为它是char*类型的指针,第一次循环改变一个字节,直到4次循环后,就把a改成0

最后再次总结指针类型的意义:

1、指针类型决定了,指针在进行解引用操作的时候,一次性访问几个字节

如果是char*类型的指针,解引用访问内存中的一个字节

如果是int*类型的指针,解引用访问内存中的四个字节

float*和double*也同样如此......

2:指针类型决定指针的步长(指针+1到底跳过几个字节)

字符指针+1,跳过1个字节

整型指针+1,跳过4个字节

其它类型的指针也是如此......

2、指针+ 或 - 整数 

除了上面的+1,还可以-5或者+4等

 注意:指针+一个数,是往高地址走,指针-一个数,是往低地址走

 总结:指针的类型决定了指针向前或者向后走一步有多大距离。

3、指针解引用

这个在上面已经讲过了

总结:

指针的类型决定了,对指针解引用的时候有多大权限(能操作几个字节)。

比如:char*的指针解引用就只能访问1个字节,而int*解引用就只能访问4个字节

三、野指针

概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

相当于“野狗”

1、野指针成因

①指针未初始化

②指针越界访问

 ③指针指向的空间释放

解析:首先a是一个局部变量,根据局部变量的生命周期,出了它的作用域,生命周期结束。返回的时候a的地址就已经被销毁了,此时的地址就是一个野指针。但是运行的时候结果还是10,这只是侥幸,这是因为之前的内存空间还没有被覆盖。我们加上个输出语句就能破坏掉这个内存空间。

2、如何规避野指针

(1)指针初始化

(2)小心指针越界

(3)指针指向空间释放,及时置NULL

(4)避免放回局部变量的地址

(5)指针使用之前要检查有效性

四、指针运算

1、指针+-整数

上面已经讲过了,这里再举一个例子

 解析:看下图就很容易理解代码循环了,但这里要主要循环体内的代码,*的优先级是比++操作符要高的,而++是后置的(先使用,后++),所以这代码的意思是把数组内5个元素全部赋值成0

 2、指针 - 指针

运算的前提条件:两个指针要指向同一块空间(同个数组)

运算结果是:相减绝对值的结果就是两个指针之间的元素个数

 解析:它是如何得到9的呢?看下图你就明白了

 指针-指针的运用

之前我们求字符串长度是这么写的(不能用strlen的情况下)

其实还能这么写

 解析:

注意:++千万不要放到循环表达式中,因为不管是前置还是后置++,它都会有副作用,会导致return的结果有误差 。

3、指针的关系运算(比较大小) 

 那么接下来我把代码简化下面这样

 其实,简化过的代码实际在绝大部分的编译器上是可以顺利完成任务的,然而我们应该避免这样书写,因为标准规定并不保证它可行。

标准规定:

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

五、指针和数组

1.指针和数组是不同的对象

•指针是一种变量,存放地址的,大小4/8字节的

•数组是一组相同类型元素的集合,是可以放多个元素的,大小是取决于元素个数和元素类型

2.数组的数组名是数组首元素的地址,地址是可以放在指针变量中,可以通过指针访问数组

如何用指针来访问数组呢?

或者还能这么写

 

总结:

int arr[10];

int* p = arr;//首元素地址

这里有一层等价关系

arr[i] == *(arr + i) == *(i + arr) == i [arr]

i[arr]是可以正常使用的,因为 [ ]只是一个操作符,i和arr是[ ]的操作数而已(就像a + b同样也能写成b + a)。在编译的过程中,arr[i]也会被翻译成*(arr+i)

 六、二级指针

1、什么是二级指针

 a的地址存放在指针变量pa中,我们称pa是一级指针。指针变量也是变量,是变量就得有地址,pa的的地址存放在ppa中,所以我们称ppa是二级指针。

这里再解释一下,pa前面一颗的*告诉我们pa是指针变量,而pa指向的a是int类型,所以pa的类型就是int*;同样的,ppa前一颗的*告诉我们ppa是指针变量,而ppa指向的pa是int*类型的,所以ppa的类型就是int**。

a、pa、ppa关系如下:

 2、二级指针的运算

 七、指针数组

1、什么是指针数组

指针数组是指针还是数组? --- 是数组(存放指针的数组)

可以类比整型数组和字符数组

整型数组是存放整型的数组

字符数组是存放字符的数组

举一个简单的例子

2、用一位数组模拟二维数组

假设要模拟三行四列的数组

思路:

开辟一个数组用来存放3个数组首元素的地址,因为数组在内存中是连续存放的,所以知道首元素的地址,后面也自然而然也就跟着知道了。

代码实现: 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/144735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11_6、Java集合之Map接口(包括HashMap在内的子接口)的使用

一、引入Map与Collection并列存在。用于保存具有映射关系的数据:key-value (双列集合框架),Map 中的 key 和 value 都可以是任何引用类型的数据 。Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应 的类&…

Android Studio生成自己的so库

一、创建Native项目 1、新建 Native 项目 1)新建项目 选择最下面的 Native C 下一步即可 2)填写项目信息 3)选择C版本可以直接选择默认 2、下载并配置NDK及CMake 1)进入Studio 设置 SDK 设置界面 这里选择需要的 NDK 和 CMake…

c++之 OpenGL(1)-安装与概述

目录概述fedora下安装编写OpenGL应用程序测试hello,world概述 OpenGL(英语:Open Graphics Library,译名:开放图形库或者“开放式图形库”)是用于…

Linux开发工具的使用(一)

文章目录Linux开发工具的使用(一)1. Linux软件包管理器yum1.1 查看软件1.2 下载软件1.3 卸载软件2.vim编辑器的介绍和使用2.1 vim的介绍2.2 vim的基本操作2.3 vim命令模式命令集(必须是命令模式下)2.3.1 移动光标2.3.2 删除文字2.3.3 复制文本内容2.3.4 …

C++ 不知树系列之二叉堆排序(递归和非递归实现上沉、下沉算法)

1. 前言 什么是二叉堆? 二叉堆是有序的 完全二叉树,在完全二叉树的基础上,二叉堆 提供了有序性特征: 二叉堆 的根结点上的值是整个堆中的最小值或最大值。 当根结点上的值是整个堆结构中的最小值时,此堆称为最小堆。…

xpath获取标签之间的文本内容

目前在学习xpath,需要取一个package信息,如图: 标题 "package"在span里面,比较方便取,用这个xpath就行: //div[idartikeltabelle]/table/tbody/tr[1]/td[2]/span[classinsertlabela and text()pa…

/mmcv/_ext.cpython-36m-x86_64-linux-gnu.so: undefined symbol: _ZN3c107Warning

报/mmcv/_ext.cpython-36m-x86_64-linux-gnu.so: undefined symbol: _ZN3c107Warning 就是mmcv或者mmcv-full编译有问题; 尝试了mmcv_full-1.7.1-cp36-cp36m-manylinux1_x86_64.whl pip 安装,都不是对应版本; 在安装mmcv或者mmcv-full都是无…

如何用PPT画出好看的科研图

前言 好看的科研图可以从前人的作品中进行借鉴,今天介绍2副精美的科研图以及他们在PPT中的绘制方法,话不多说,先摆上标准科研图 1. 黑色粗体边框以及淡填充颜色 黑色粗体边框和淡填充颜色真的让矩形一下子变得很有质感,在学习的…

VMware Fusion设置静态IP+端口转发(macOS)+内网穿透

很少有资料提到配置macOS上VMware Fusion的端口转发,因此我在这里进行了一些记录打开网络设置解锁并添加新的网络适配器只有新的网络适配器才允许配置转发,默认的不允许这样做。设置NAT转发虚拟机选择使用新创建的虚拟网络适配器Ubuntu配置静态IP/DNS服务…

linux xshell用户免密登录设置

最重要准备工作 ​编辑linux xshell用户免密登录设置步骤 1.在xshel进行密钥获取操作 2.创建mkdir ~/.ssh目录(检查有没有这个目录,没有自己添加) 3.在该目录创建authorized_keys目录。注意(目录权限为600) 4.将刚…

Android Studio arctic Fox(北极狐)导入openCV

Android studio arctic Fox在引入opencv的时候按照正常的File->New->Import Module操作时,出现无法点击“Next”和“Finish”的情况。如下图 所以我们使用另外的方法进行引入。 准备工作: 1,Android Studio 2,下载opencv…

纪念2022年11月软考高项(信息系统项目管理师)一次通过的经验随笔

一、备考背景2022年5月的浙江软考因为疫情防控原因临时取消,我离杭州买房又远了几分。众所周知,杭州是炒房投资客的香饽饽,即使主城区购房摇号制度不停打补丁,也难济于事。自住客为了与投资客抗衡,一靠社保&#xff0c…

新品做软文推广发布在哪些平台好?

新产品上市前后,会经历开发期、介绍期、成长期、成熟期、衰退期五个阶段,每个阶段都需要软文推广的助力! 当一款新品上市前后往往会面临着无法打开市场、产品卖不出去等问题,这个时候软文推广就要做到位,除了文章撰写…

在centos7安装KubeSphere

节点准备 设置hostname hostnamectl set-hostname ks-m4 关闭防火墙 启动: systemctl start firewalld 关闭: systemctl stop firewalld 查看状态: systemctl status firewalld 开机禁用 : systemctl disable firewalld 开机…

SAP 通过 OData Service 反查 CDS View 位置 视图「Workaround」

前言 使用场景:目前已知 OData Service 由 CDS View 发布,但是想要查看该 CDS 的具体内容 根据 OData Service 获取关键信息盲猜对应底表通过 SE11 反查引用位置 猜底表 目前已知 OData Service URL: http://xxx.xxx.com:xxxx/sap/opu/odata/sap/ZCD…

栉风沐雨砥砺行,春华秋实满庭芳——华秋电子2022年度大事记

岁序更替,春华秋实 转眼间,2022年已是过去 回首2022年,华秋肩负使命 持续为电子产业增效降本。 我们加大研发投入,提升全球交付保障能力; 我们以创新引领发展,以实干笃定前行; 以品质为基…

JetBrains 学生和教师认证教程

目录一、学生和教师授权申请方式二、申请网址三、激活JetBrains产品(如PyCharm、IDEA)一、学生和教师授权申请方式 详见官方教程: JetBrains 学生和教师授权申请方式 二、申请网址 学生和教师可以使用在学校注册的邮箱账号来申请。 新申请…

「EZEC-4」可乐(2种方法:差分+位运算 | 枚举+字典树)

「EZEC-4」可乐 洛谷:「EZEC-4」可乐 题目背景 很久以前,有一个 pigstd,非常迷恋美味的可乐。为了得到美味的可乐,他几乎用尽了所有的钱,他甚至对自己的 npy 也漠不关心其实是因为他没有npy,更不爱好看戏…

C语言实现烟花表白,内含源码!!

虽然现在看烟花有一定难度,但代码式烟花可以随时随地看! 烟花的代码很多,实际上是可以用 Python、HTML5 等语言写烟花,但今天主要想和大家分享用C语言写的烟花代码,非常细致和实用。 同学们一定要亲自敲一遍&#xf…

机器视觉(八):图像特征提取

目录: 机器视觉(一):概述 机器视觉(二):机器视觉硬件技术 机器视觉(三):摄像机标定技术 机器视觉(四):空域图像增强 …