保姆级的指针详解(超详细)

目录

一.内存和地址 

1.初识指针

2.如何理解编址

二. 指针变量

三.指针的解引用操作符

1.指针变量的大小

四.指针变量类型的意义

五.指针的运算

1.指针加减整数

2.指针减指针

3.野指针

3.1指针未初始化

3.2指针越界访问

3.3指针指向的空间被提前释放

3.4如何规避野指针

六.void* 指针和const修饰指针

6.1void

6.2const

七.传值调用和传址调用

八.指针比较和二级指针

8.1指针比较

8.2二级指针

九.字符指针

十.指针数组

10.1指针数组模拟⼆维数组

十一.数组指针

11.1定义

11.2再次讨论数组名

11.3⼆维数组传参的本质

十二.函数指针

12.1函数指针定义

12.2函数指针变量的使用

12.3怪题

12.4回调函数

十三.函数指针数组

十四.指向函数指针数组的指

十五.qsort的实现

一.内存和地址

1.初识指针

在学习指针之前我们先要明白指针到底是什么,指针就是用来访问内存的,每一个单位内存都会占一个字节,也就是八个比特位,每一个内存单号有一个编号,就是地址,这样可以让CPU快速地找到他,我们可以把内存比做成房子,内存单号就是每一个住户,那么地址也就是你的门牌号了。所以我们可以理解为:内存单元的编号 == 地址 == 指针。在C语言中地址的新名字就可以把它看作成指针。

2.如何理解编址

CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,而因为内存中字节 很多,所以需要给内存进行编址,那么到底是如何编址的呢?

首先必须理解计算机内是有很多硬件单元,这些硬件单元他们是相互工作的,他们会进行数据传递相互的,我们可以来看一下这个图片图片中,一共有三个线地址,总线数据总线和控制总线。比如说,我要从内存中读取一个信息,这个读的指令就是通过控制总线内存向CPU传递的,然后CPU通过地址总线向找到内存所开辟的空间,然后内存再用数据总线传给CPU。不过,我们今天只关心组线,叫做地址总线。其实所谓硬件编制还跟你是几位机器有关,如果你是32位机器,那么你就有32位地址线,64位机器则64位地址总线,一根机器含有两个态0.1,所以说32根地址线就可以表示2的32次方含义,每种含义都可以表示一个地址.

二. 指针变量

所以说指针到底是什么呢?他就是地址,那么指针变量,他就是存放指针的变量,比如说整形变量int a=4;它可以用来存放一个整型,反之指针变量也是可以用来存放指针也就是地址。我们先来看一个最简单的指针变量。

这就是最简单的一个指针的创建,然后我们把它拆分开来看就可以了。注意指针变量是用来存放地址的,也就是存放变量a的

所以是指针他也是分类型的,如果有⼀个char类型的变量ch,ch的地址,要放在char*的指针变量种去。

三.指针的解引用操作符

那么这个存起来的地址到底有什么用呢?肯定我们将地址保存起来,未来是要使用的,那怎么使用呢? 在现实生活中,我们使用地址要找到⼀个房间,在房间里可以拿去或者存放物品。 C语言中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这里必须学习⼀个操作符叫解引用操作符(*)。

*pa 的意思就是通过pa中存放的地址,找到指向的空间, *pa其实就是a变量了;所以*pa = 0,这个操作符是把a改成了0.其实可以这样看*可以与&操作抵消因为pa=&a所以*pa=*&a=a'。

1.指针变量的大小

所以说指针变量的大小到底是什么呢?我们可以这样来推理,指针变量是用来存放地址的那么地址是怎么产生的呢?地址肯定是由地址线产生的,以32位机器为模板32位机器就是32根地址线,就是32个比特位那么32个比特位置四个字节,所以说指针变量大小就是地址的大小那么地址大小就和机器的这个位数是有关系的,你是64位,那你就是八个字节,注意类型是无关的

四.指针变量类型的意义

现在有一个令人疑惑的问题,就是这个指针变量它的存在到底有什么意义?指针变量的大小和类型无关,只要是指针变量,在同一个平台下,大小都是⼀样的,为什么还要有各 种各样的指针类型呢?我一个指针变量让他有这么多类型是干什么的?或者是他到底有什么用?

调试我们可以看到,代码1会将n的4个字节全部改为0,但是代码2只是将n的第⼀个字节改为0。所以说,指针类型决定了指针进行节,引用操作的时候能够访问空间的大小

五.指针的运算

1.指针加减整数

用数组来举例子,因为数组在内存中是连续存放的,只到第一个元素的地址就能找到后面的所有,所以说数组的打印也可以用指针加减整数来去实现。

注意:这里有一个重要的思想,*(p+i)其实就等于arr[i],又因为p=arr所以arr[i]=p[i]  , *(p+i)=p[i]

只是一个很重要的思想,很多题目都会用到。

2.指针减指针

这里就是运用了指针减指针,注意不同类型的指针变量是不可以相减的,其实相同类型的指针相减可以看作这两个数组下标之间包含了几个元素,一般都是用大减小。

3.野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。野指针是非常危险的,就比如说野狗,如果没有人管的话,你怕不怕。所以说常见的野指针类型,我们是必须要知道的.

3.1指针未初始化

局部变量指针未初始化,默认为随机值,不知道初始化什么的时候,我们可以把它定做成一个空指针。

3.2指针越界访问

当指针指向的范围超出数组arr的范围时,p就是野指针。

3.3指针指向的空间被提前释放

因为出了test函数结束的时候,a的空间就会销毁,所以说访问的空间不再是当前程序的。所以地址找不到a,就会形成野指针。

3.4如何规避野指针

1.如果不知道指针应该指向哪⾥,可以给指针赋值NULL.

2.⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问。

3.避免返回局部变量的地址

六.void* 指针和const修饰指针

6.1void

在指针类型中有⼀种特殊的类型是 void* 类型的,泛型指针),这种类型的指针可以用来接受任意类型地址。但是也有局限性,void* 类型的指针不能直接进行指针的+-整数和解引用的运算

6.2const

代表他有常属性是无法修改的,他修饰指针变量时,分为在指针变量的左侧和在指针变量的右侧这两种情况。

const在修饰指针变量的时候放在*右边,const限制的是指针变量本身,不能再指向别的变量,但是可以通过指针变量修改指向的内容。

放在右边的时候,限制的是指针指向的内容,不能通过指针来修改指向的内容可以修改指针变量本身的,只也就是修改指针变量的指向。

七.传值调用和传址调用

存在传值调用和传址调用形式,也就是在有些问题中非用指针不可,所以我们才会来学习指针。比如说,写一个函数,交换两个整型变量的值。

void Swap1(int x, int y)
{
    int tmp = x;
    x = y;
    y = tmp;
}
 

当Swap1函数调用结束后回到main函数,a和b的没法交换。Swap1函数在使用的时候,是把变量本身直接传递给了函数,这种调用函数的方式我们之前在函数的时候就知道了,这种就叫传值调用。

void Swap2(int* px, int* py)
{
    int tmp = 0;
    tmp = *px;
    *px = *py;
    *py = tmp;
}
我们可以看到实现成Swap2的方式,顺利完成了任务,这里调用Swap2函数的时候是将变量的地址传递给了函数,这种函数调用方式叫:传址调用。

所以未来函数中只是需要主调函数中的变量值来实现计,就需要传值调用

如果函数内部要修改 主调函数中的变量的值,就需要传址调用 

八.指针比较和二级指针

8.1指针比较

注意:C语言语法规定,只允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较

8.2二级指针

指针变量也是变量是变量就地址,那么指针变量的地址存放在哪儿呢?其实二级指针就是用来存放指针变量的地址的。所以说,三级指针四级指针也很容易解释了,三级指针就是存放二级指针地址的四级指针就是存放三级指针地址的。

总之还可以这么理解

九.字符指针

在指针的类型中,我们知道一种指针类型叫做字符指针char*,我们知道他的使用方式就可以了。

这里是把一个字符串全部放进去了,还是只放了首字母呢?注意,他是一个常量字符串,答案是他放的是首字母把常量字符串的首字母放到了变量中。

十.指针数组

指针数组,首先他是一个数组,是用来存指针的,后面还会出现数组指针,函数指针,函数指针数组,那这些东西该如何去判断呢,我们可以这样去看找主语,比如说好大儿好大儿,他是儿子,我们只要看后面的那个主语是谁就可以判断他是谁了。

10.1指针数组模拟⼆维数组

parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型⼀维数组,parr[i][j]就是整型⼀维数 组中的元素。注意这里的parr[i][j]可以写成*(parr[i]+j)==*(*(pi)+j)。由直接的思想可以得出。

十一.数组指针

11.1定义

整形指针是用来存放整形地址的指针,字符指针是用来存放字符地址的指针,所以说数组指针就是用来存放数组地址的指针。

     int (p指向的数组的元素类型)(*p1)(变量名)[10] (指向数组的元素个数)  =&arr;         

11.2再次讨论数组名

数组名通常表示的都是首元素的地址,但是有两个意外,1.sizeof(数组名)这里数组名表示整个数组,计算的是整个数组大小。2.&数组名,这里的数组名表示的依然是整个数字,所以取地址取出的是整个数字的地址。注意:数组传参的本质是首元素的地址,所以形参访问的数组和实参的数组是同一个数组

11.3⼆维数组传参的本质

有了数组指针的理解,我们就能够讲⼀下⼆维数组传参的本质了。二维数组传参本质上也是传递了地址,传递的是第一行这个一维数组的地址。前面也讲过怎么实现二维数组这里就不展示代码了,主要还是讲解一个传递参数方式,我们用函数来打印二位数组的话肯定就需要传递参数。有两种传参的形式

1.void test(int (*p)[5], int r, int c)

2.void test(int a[3][5], int r, int c)

为什么这样可以呢?因为二维数组的首元素是他第一行,第一行的地址就是一个意位数组的地址。所以说我需要他的一个首元素,那么首元素就很好说了,我要么就直接打印他的数组名,要么就用数组指针,所以就会有这两种方法。所以说⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。

十二.函数指针

12.1函数指针定义

就是指向函数的一个指针,对于函数来说,取地址函数名和函数名都是函数的地址。他的定义方法是(返回类型) (*p) (参数)。

定义:   int           (*pf3)     (int x, int y)

12.2函数指针变量的使用

可以直接通过指针来进入函数,为什么两种写法都可以,因为前面讲过了对于函数来说,取地址函数名和函数名都是函数的地址

12.3怪题

1          (*       (void    (*) ()    )   0)   ()   ;是什么意思?

题目来自于《c语言陷阱与缺陷》这句代码表达了什么意思直接看的话,是有点复杂,所以我们把他拆分下来,先看里面的void(*) ()这是一个函数指针类型,拿出去,还剩一个(*0)这是一个指针变量,表示0处的地址,所以

以上代码是一次函数的调用调用的是0作为地址处的函数,把0强制类型转化为一个没有参数返回类型,是void的函数地址,在调用0地址处的这个函数。

2            void         (*signal    (int , void   (*)  (int)  ))   (int)

比较第一题要更加复杂了,我们还是可以拆分来看,先看里面的signal(int,void(*(int)这是一个函数指针类型,拿去后,还剩一个void(*)(int)这也是一个函数指针类型,

以上代码是一次函数的声明,声明的signal函数的第一个数参数的类型是int,第二个参数的类型是函数指针,该指针指向的函数参数是int,返回类型是void,signal函数的返回类型,也是一个函数指针的函数,该指针指向的函数参数是int,返回类型是void。

12.4回调函数

就是一个通过函数指针调用的函数,如果你把函数指针(地址)作为参数传给了另一个函数,当这个指针被用来调用其所指向的函数的时候就叫做回调函数。

十三.函数指针数组

数组是一个存放相同类型数据的存储空间,那么如果我要把函数的地址存到一个数组中,这些数字该如何定义呢?这里就要用到函数指针数组了,首先他肯定是一个数组,我们用函数指针的结构再去套上数组就行了。

                               int (*arr[4]) (int,int) ={add,sub,mul,div};

运用了就是可以用它来定义一个计算机把他的计算机方法的函数全部定义在这个数组里

十四.指向函数指针数组的指针

因为我的能力也有限,在此只能补充一个定义,首先他肯定是指针,然后他是指向函数指针数组的

                                     int (*(*arr[4]) )(int,int)=&arr;

十五.qsort的实现

以前写过一篇就直接放在这里了用c语言自己实现qsort和冒泡排序-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Rust学习之Features

Rust学习之Features 一 什么是 Features二 默认 feature三 简单的features应用示例四 可选(optional)的依赖五 依赖的特性5.1 在依赖表中指定5.2 在features表中指定 六 命令行中特性控制七 特性统一路径八 其它8.1 相互排斥特性8.2 观察启用特性8.3 [Feature resolver version…

从源码角度透视QTcpServer:解构QTcpServer的底层原理与技术细节

深入了解QTcpServer的底层原理和技术细节 一、背景二、QTcpServer的基本原理2.1、TCP协议简介2.2、QTcpServer的概念 三、QTcpServer源码解析3.1、QTcpServer的构造函数3.2、调用listen函数启动tcpserver3.3、QSocketNotifier的实现 总结 一、背景 QTcpServer是Qt网络模块中的…

花瓣网美女图片爬取

爬虫基础案例01 花瓣网美女图片 网站url:https://huaban.com 图片爬取 import requests import json import os res requests.get(url "https://api.huaban.com/search/file?text%E7%BE%8E%E5%A5%B3&sortall&limit40&page1&positionsear…

『C++成长记』string使用指南

🔥博客主页:小王又困了 📚系列专栏:C 🌟人之为学,不日近则日退 ❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、string类介绍 二、string类的常用接口说明 📒2.1string类对象的常…

数据结构+算法(第10篇):叉堆“功夫熊猫”的速成之路

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖&…

Elasticsearch:集群故障排除和优化综合指南

Elasticsearch 是一个强大的搜索和分析引擎,是许多数据驱动应用程序和服务的核心。 它实时处理、分析和存储大量数据的能力使其成为当今快节奏的数字世界中不可或缺的工具。 然而,与任何复杂的系统一样,Elasticsearch 可能会遇到影响其性能和…

【ACL 2023】Enhancing Document-level EAE with Contextual Clues and Role Relevance

【ACL 2023】Enhancing Document-level Event Argument Extraction with Contextual Clues and Role Relevance 论文:https://aclanthology.org/2023.findings-acl.817/ 代码:https://github.com/LWL-cpu/SCPRG-master Abstract 与句子级推理相比&…

linux中的静态库和共享库

库:库是二进制文件,是源代码文件的另一种表现形式,是加了密的源代码;是一些功能相近或者相似函数的集合体 库的使用: 头文件--包含了库函数的声明 库文件--包含了库函数的代码实现 注意:库不能单独使用…

应用智能家居领域中的低功耗蓝牙模块

智能家居(smart home, home automation)是以住宅为平台,利用综合布线技术、网络通信技术、 安全防范技术、自动控制技术、音视频技术将家居生活有关的设施集成,构建高效的住宅设施与家庭日程事务的管理系统,提升家居安…

某零售公司竞聘上岗项目成功案例纪实

——建立科学选人标准、评价方法,实现人岗匹配 【客户行业】零售业;销售行业 【问题类型】竞聘上岗 【客户背景】 半月(化名)有限公司成立于2008年,以母婴零售为基础,始终坚持以客户为导向,…

Stable diffusion使用和操作流程

Stable Diffusion是一个文本到图像的潜在扩散模型,由CompVis、Stability AI和LAION的研究人员和工程师创建。它使用来自LAION-5B数据库子集的512x512图像进行训练。使用这个模型,可以生成包括人脸在内的任何图像,因为有开源的预训练模型,所以我们也可以在自己的机器上运行它…

第1章 简单使用 Linux

第1章 简单使用 Linux 1.1 Linux 的组成 1.2 远程连接 首先以 root 用户登录到 Linux 系统,然后在 Terminal 终端上输入 ip add 命令,来查看 IP 地址。 上图中的 192.168.72.128 就是 IP 地址。 然后打开 XShell 远程连接工具。 然后在命令提示符下输…

C++ Webserver从零开始:基础知识(七)——多进程编程

前言 在学习操作系统时,我们知道现代计算机往往都是多进程多线程的,多进程和多线程技术能大大提高了CPU的利用率,因此在web服务器的设计中,不可避免地要涉及到多进程多线程技术。 这一章将简要讲解web服务器中的多进程编程&#x…

养猫家庭必备猫用空气净化器哪款牌子好?宠物空气净化器值得推荐的品牌

养宠家庭的朋友们都知道,猫咪的浮毛无处不在,每天都会在空气中飘荡。无论是沙发、地板还是衣服,都成了浮毛的重灾区。这些浮毛不仅难以清理,而且对于呼吸道敏感的人来说,可能会引发过敏反应。为了除去猫毛,…

Zoho Mail 2023:回顾过去,展望未来:不断进化的企业级邮箱解决方案

当我们告别又一个非凡的一年时,我们想回顾一下Zoho Mail如何融合传统与创新。我们迎来了成立15周年,这是一个由客户、合作伙伴和我们的敬业团队共同庆祝的里程碑。与我们一起回顾这段旅程,探索定义Zoho Mail历史篇章的敏捷性、精确性和创新性…

2024美赛预测算法 | 回归预测 | Matlab基于WOA-LSSVM鲸鱼算法优化最小二乘支持向量机的数据多输入单输出回归预测

2024美赛预测算法 | 回归预测 | Matlab基于WOA-LSSVM鲸鱼算法优化最小二乘支持向量机的数据多输入单输出回归预测 目录 2024美赛预测算法 | 回归预测 | Matlab基于WOA-LSSVM鲸鱼算法优化最小二乘支持向量机的数据多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果…

vit细粒度图像分类(八)SIM-Trans学习笔记

1.摘要 细粒度视觉分类(FGVC)旨在从相似的从属类别中识别物体,这对人类准确的自动识别需求具有挑战性和实用性。大多数FGVC方法侧重于判别区域挖掘的注意机制研究,而忽略了它们之间的相互依赖关系和组成的整体对象结构,而这些对模型的判别信…

防御保护---防火墙双机热备直路部署(上下三层接口)

防御保护---防火墙双机热备直路部署(上下三层接口) 一、根据网段划分配置IP地址和安全区域二、配置动态路由OSPF三、配置双机热备四、测试:4.1 测试一:查看状态和路由器路由表(双机热备)前后对比4.2 测试二…

2024年美赛数学建模B题思路分析 - 搜索潜水器

# 1 赛题 问题B:搜索潜水器 总部位于希腊的小型海上巡航潜艇(MCMS)公司,制造能够将人类运送到海洋最深处的潜水器。潜水器被移动到该位置,并不受主船的束缚。MCMS现在希望用他们的潜水器带游客在爱奥尼亚海底探险&…

2024年美赛美国大学生数学建模竞赛BCEF题思路解析+代码+论文

下文包含:2024年美国大学生数学建模竞赛(美赛)A- F题思路解析、选题建议、代码可视化及如何准备数学建模竞赛(2号发) 将会第一时间发布选题建议、所有题目的思路解析、相关代码、参考文献、参考论文等多项资料&#x…