C语言:指针学习以及理解

2023-05-16

C语言:关于指针学习以及理解

文章目录

  • C语言:关于指针学习以及理解
    • 一、什么是指针
    • 二、为什么使用指针、什么情况下使用指针
    • 三、如何使用指针
    • 四、使用指针要注意的问题
    • 五、指针与数组的关系
    • 六、指针的运算
    • 七、指针与const配合
    • 八、什么是二级指针,什么情况下使用
    • 九、指针函数和函数指针
    • 十、数组指针和指针数组
    • 十一、结构体指针
    • 十二、结构体成员指针
    • 十三、指针与堆内存配合

一、什么是指针

首先,指针是一种数据类型,使用它定义的变量叫指针变量。指针变量是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址指针的值是一个地址

指针的四个要素?:指针的类型、指针所指向的类型、指针的值 (指针所指向的内存区,即指向的地址) 、指针本身所占据的内存区(指针本身的地址)。
在这里插入图片描述

(根据上图)举个例子:
int a=111;
int *p = &a;

上面两句语句中可得出:
p 是指针变量
指针类型:  p 是一个 int 类型的指针
指向类型:  p 指向一个 int 类型的数据 a
指针的值:  p 的值是0x30009 ( 即 p 指向的地址是0x30009 )  
指针的地址:p 所占据的内存区 (即 p 本身的地址为0x30001)    

所以要注意:指针的值指针的地址 不是同一个东西,一个代表 p ,另一个代表&p 。

二、为什么使用指针、什么情况下使用指针

1、函数之间无法通过传参共享变量。
函数的形参变量属于被调用于者,实参属于调用者,函数之间的变量名字空间相互独立是可以重名的,函数之间的数据传递都是值传递(赋值、内存拷贝)。
2、使用指针可以优化函数之间传参的效率。(无需传递数组中所有参数,直接传递数组首地址)
3、堆内存无法与标识符建立联系,只能配合指针使用。

三、如何使用指针

? 定义:类型 * 变量名p;
1、指针变量与普通变量使用方法有很大区别,一般以 p 结尾,与普通变量区分开。
2、* 表示此变量是指针变量,一个 * 只能定义出一个指针变量,不能连续定义。

   int* p1,p2,p3;  // p1是指针,p2,p3是int类型变量
   int *p1,*p2,*p3; // 三个指针变量

3、类型表示的是存储是什么类型变量的地址,它决定当通过地址访问这块内存时访问的字节数。
4、指针变量的默认值也是不确定,一般初始化为NULL(空指针)。

? 赋值操作:指针变量 = 地址

    栈地址赋值:
        int num = 0;
        int* p = NULL;
        p = #
    堆地址赋值:
        int* p = NULL;
        p = malloc(4);

? 解引用(根据地址访问内存): * 指针变量名 <=> 变量
1、根据变量中存储的内存编号(即地址)去访问内存中的数据,访问多少个字节要根据指针变量的类型。
2、如果指针变量中存储的地址出错,此时可能发生段错误(这是赋值产生的错误)。

四、使用指针要注意的问题

? 空指针:

1、指针变量的值为NULL(大多数是0,也有特殊情况是1),这种指针变量叫空指针,空指针不能进行解引用(* 指针变量),NULL被操作系统当作是复位地址(存储了系统重启所需要的数据),当操作系统察觉到程序访问NULL位置的数以的时就会向程序发送段错误的信号,程序就会死亡。

2、空指针还被当作错误标志,如果一个函数的返回值是指针类型,实际返回的值是NULL,则说明函数执行失败或出错。

在C语言代码中应该杜绝对空指针进行解引用,当使用来历不明的指针(调用者提供的)前应该先判断是否为NULL。

void func(int* p)
{
     if(NULL == p)
     {
      	//函数内容
     }
}

? 野指针:指针变量的值是不确定的或都是无效的,这种指针叫野指针。

使用野指针不一定会出问题,可能产生的后果如下
1、一切正常
2、段错误
3、脏数据

  • 虽然野指针不一定会出错,但野指针比空指针的危险更大,因为野指针是无法判断出来、也无法测试出来,也就意味着一旦产生无法杜绝。

  • 虽然野指针无法判断也无法测试出来,但是所有的野指针都是人为制造出来的,最好方法就是不生产野指针
    1、定义指针变量时要初始化。
    2、不返回局部变量的地址。
    3、资源释放后,指向它的指针及时置空。

五、指针与数组的关系

数组名就是个指针(常指针),数组名与数组首地址是映射关系,而指针是指向关系。
由于数组名就是指针,所以数组名可以使用指针的解引用运算符,而指针也可以使用数组的 [ ] 运算符。
注意:使用数组当函数的参数时,数组会蜕变成指针,长度也就丢失,因此需要额外添加一个参数用来传递数组的长度。

六、指针的运算

指针的本质就是个整数,因此从语法上来说整数能使用的运算符它都能使用。

  • 不是所有的运算符对指针运算都是有意义的。
    指针+ 整数 <=> 指针+ 宽度* 整数 向右移动
    指针 - 整数 <=> 指针 - 宽度* 整数 向左移动
    指针 - 指针 <=> 指针 - 指针/宽度 计算出两个指针之间相隔多少个元素。

七、指针与const配合

 const int* p; 		保护指针指向的数据,不能通过指针解引用修改指针指向的内存地址中的值。
 int const *p; 		//同上
 int * const p; 		保护指针变量,指针变量(地址)初始化之后不能再显式的赋值,即指针的值不能被显示的修改。
 const int *const p; 既不能修改指针的值,也不能修改指针指向的内存地址中的值。
 int const * const p;//同上。

八、什么是二级指针,什么情况下使用

二级指针:指向指针的指针。

一级指针与二级指针的比较:一级指针的值为地址,该值(即地址)需要空间来存放,存放在指针的地址中,是空间就具有地址,二级指针就是为了获取这一空间的地址。一级指针所关联的是其值(一个地址)名下空间里的数据,这个数据可以是任意类型并做任意用途,但二级指针所关联的数据只有一个类型一个用途,就是地址。在这里插入图片描述

一级指针(图中 p): 其指针的值是一个变量的地址(a的地址),对其解引用得到的是一级指针所指向变量的值(a的值10086)。
二级指针 (图中 pp):其指针的值是一个指针的地址(p的地址),对其解引用得到的是二级指针所指向的指针的值(p的值0x100A2)

指针的用途:提供目标的读取或改写,而二级指针就是对于内存地址的读取和改写。

二级指针作为函数参数的作用:在函数外部定义一个指针p,在函数内给指针赋值,函数结束后对指针p生效,那么我们就需要二级指针。

九、指针函数和函数指针

函数具有可赋值给指针的物理内存地址,一个函数的函数名就是一个指针,它指向函数的代码。一个函数的地址是该函数的进入点,也是调用函数的地址。函数的调用可以通过函数名,也可以通过指向函数的指针来调用。函数指针还允许将函数作为变元传递给其他函数。

指针函数:简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。

声明格式为:类型标识符 *函数名(参数表)

  int fun(int x,int y);
  这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。
    

  int * fun(int x,int y);
  这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。  
  其返回值是一个 int 类型的指针,是一个地址。

这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。

函数指针:其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。
声明格式:类型说明符 (*函数名) (参数)

  int (*fun)(int x,int y);
函数指针是需要把一个函数的地址赋值给它,有两种写法:

  fun = &Function;
  fun = Function;

取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,

如果是函数调用,还必须包含一个圆括号括起来的参数表。

调用函数指针的方式也有两种:

x = (*fun)();
x = fun();

两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。

十、数组指针和指针数组

数组指针(也称行指针)
定义 int (*p)[n];
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。
如要将二维数组赋给一指针,应这样赋值:

  int a[3][4];
  int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
  p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
  p++;       //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

  所以数组指针也称指向一维数组的指针,亦称行指针。

指针数组
定义 int * p[n];
[]优先级高,先与p结合成为一个数组,再有int* 说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 * p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:

  int *p[3];
  int a[3][4];
  p++; //该语句表示p数组指向下一个数组元素。注:此数组每一个元素都是一个指针
  for(i=0;i<3;i++)
  p[i]=a[i]
  这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]所以要分别赋值。

这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间

优先级:()>[]>*

(近期更新中…)

十一、结构体指针

十二、结构体成员指针

十三、指针与堆内存配合

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言:指针学习以及理解 的相关文章

  • 记一次Linux 4.15.0-65-generic安装Elasticsearch成功的过程

    一 xff0c 操作系统和安装的应用 xff1a 1 操作系统 xff1a Linux version 4 15 0 65 generic buildd 64 lgw01 amd64 006 gcc version 7 4 0 Ubuntu
  • [docker]笔记-镜像 管理

    1 镜像管理 docker search xxxx 查找镜像 例如查找httpd root 64 localhost docker search httpd 下载镜像 docker pull xxxx root 64 localhost d
  • quill-editor扩展的正确姿势

    一 无关的插曲 曾几何时 xff0c 风云万里 xff0c 万海桑田 耕耘于代码堆里多年 做过android移动端 xff0c 做过web端 xff0c 做过java后端和 net xff0c 也做过python数据分析 但真正扩展源码的亦
  • 导入excel时js转换时间的正确姿势

    一 基础 1 excel的日期是以1900 1 0开始计算的 xff0c 既1900 1 1就是1天 xff1b 2 js的Date是以 1970 1 1 08 00 00 开始的 xff1b excel时间换算如下 xff1a 点击常规后
  • springboot下ClassUtils.getDefaultClassLoader().getResource(“static“).getPath() 空指针异常???

    在static加个文件文件就ok xff0c 不信你看看
  • Compilation failure: Compilation failure

    有a项目和b项目 xff0c 如果a项目打包成功 xff0c b依赖a 现b打包的时候报Compilation failure Compilation failure了 xff0c 原因是a中有 span class token opera
  • mysql数据更新时变更时间自动更新

    ALTER TABLE test CHANGE startTime startTime timestamp NOT NULL ON UPDATE CURRENT TIMESTAMP DEFAULT CURRENT TIMESTAMP
  • docker、docker-compose和Portainer的安装

    一 docker安装 span class token comment 安装docker相关依赖 span yum span class token function install span y yum utils device mapp
  • vue-cli+spring boot前后端分离跨域及session丢失解决办法

    前后端分离跨域笔记 小小的唠叨前端代码后端 小小的唠叨 曾几何时 xff0c 项目开发时间很紧 xff0c 项目组很多的人即不懂vue也不大懂spring boot及mybatic的强大之处 xff0c 也没有做过前后端分离 xff0c 项
  • vue打包整合到spring boot一记

    目录 背景vue cli打包之前的配置总结 背景 前段时间 xff0c 根据需求 xff0c 要将项目烧入到芯片 xff0c 但我的擅长之处就是前后端分离开发 xff0c 因此需要前端vue开发好 xff0c 打包放到后端里面一起执行 那时
  • 小四轴编程入门教程

    小四轴编程入门教程之一 xff1a 陀螺仪和加速度计 在小四轴中 xff0c 陀螺仪是一种用于测量小四轴旋转速度的传感器 xff0c 它测量的是角速度 xff0c 是指物体在单位时间内转过的角度大小 通过测量物体在X Y Z三个轴上的角速度
  • 从0开始教你三天完成毕业设计-后端api

    目录 前言 开始 env 数据库配置文件 app controller 控制器接口api 工具类 分类表 categoryController 收藏表 collecetionController 商品表 goodController 订单表
  • ZYNQ双核通信 Linux+FreeRTOS(一)

    ZYNQ 双核通信 一 OpenAMP开发换环境搭建编译U boot编译Kernel编译设备树什么是devicetree xff1f Devicetree基础设备树属性设备树生成器 xff08 DTG xff09 Task Output P
  • ZYNQ 安装ubuntu文件系统

    ZYNQ 7020 Ubuntu16 04文件系统安装 在关于zynq openamp的章节我们已经完成了zynq 的u boot 内核 xff0c 设备树的制作 xff0c 通过XSDK完成了启动文件的创建 同样道理制作zynq7020的
  • RPMsg:协议简介

    RPMsg xff1a 协议简介 本篇文章转载于简书 xff0c 在此做个整理和备份 xff0c 方便查阅 在此感谢原博主SunnyZhou1024 RPMsg xff1a 协议简介0 起因1 AMP2 RPMsg2 1 Linux中的RP
  • GEM TSU Interface Details and IEEE 1588 Support

    GEM TSU Interface Details and IEEE 1588 Support Chapter 1 IntroductionChapter 2 GEM TSU Clock SourcePCW 中的 GEM TSU 时钟源选择
  • ZYNQ UltraScale+ MPSoC Linux + ThreadX AMP玩法

    ZYNQ UltraScale 43 MPSoC Linux 43 ThreadX AMP玩法 ZYNQ UltraScale 43 MPSoC与ZYNQ 7000架构比较目标 一 创建Linux1 修改kernel2 修改设备树编译 am
  • Zipwire

    文章目录 Chapter 55 Zipwire55 1 Chip specific Zipwire information52 2 Overview55 3 Introduction55 4 Zipwire Block Diagram55
  • arm启动过程详解

    ARM芯片的启动程序的分析和总结 2009 02 04 14 35 26 标签 xff1a 杂谈 分类 xff1a ARM 1 综述 xff1a 目前大多基于ARM芯片的系统都是一个比较复杂的片上系统 xff0c 多数硬件模块都是可配置的

随机推荐

  • 数据读写的乒乓操作

    数据读写的乒乓操作 文中一部分从其他博客中学习到 xff0c 加入了自己实际应用的过程 在重要数据的解帧与处理过程中 xff0c 为了确保数据的实时性与可靠性 xff0c 我们一般对收到的数据存储到芯片的RAM或Flash xff08 掉电
  • 生命在于学习——Linux提权

    本篇文章仅用于学习记录 xff0c 不得用于其他违规用途 一 内核漏洞提权 1 常规查找 查看内核版本信息 uname span class token operator span a uname span class token oper
  • 前入式JUC常用类源码分析

    CountDownLatch span class token keyword public span span class token keyword class span span class token class name Coun
  • dockerfile中的命令:run, cmd, entrypoint, copy和add

    总结一下 xff0c run 可以有多个 xff0c cmd 和entrypoint 只能有一个 xff08 常用来跑app xff09 cmd 可以被docker 指令overwrite xff0c entrypoint不可以 此命令会在
  • Qt类关系一览表

    Qt类关系一览表
  • ros之pid

    PID口诀 参数整定找最佳 xff0c 从小到 大顺序查 先是比例后积分 xff0c 最后再把微分加 曲线振荡很频繁 xff0c 比例度盘要放大 曲线漂浮绕大湾 xff0c 比例度盘往小扳 曲线偏离回复慢 xff0c 积分时间往下降 曲线波
  • 导 Kinect2库,opencv库,pcl库

    导 Kinect2库 opencv库 pcl库 Kinect2驱动安装 https blog csdn net qq 15204179 article details 107706758 ndfreenect2 cmake Kinect2
  • ros中订阅/map话题,获取地图尺寸,获取机器人原点origin,获取地图分辨率resolution (c++,python,waitForMessage,wait_for_message)

    ros中订阅 map话题 获取地图尺寸 获取机器人原点position 获取地图分辨率resolution 1 nbsp include lt ros ros h gt include lt nav msgs OccupancyGrid h
  • geometry_msgs::TransformStamped与geometry_msgs::PoseStamped消息互转

    geometry msgs TransformStamped与geometry msgs PoseStamped消息互转 下面是一个将geometry msgs TransformStamped转换为geometry msgs PoseSt
  • ros中获取小车当前位置

    ros中获取小车当前位置 一 tf2获取小车当前位置 xff1a include 34 tf2 ros transform listener h 34 include 34 tf2 ros buffer h 34 include 34 tf
  • 记一次被正点原子坑了的经历

    被正点原子坑 xff0c 不是买了他们的板子 xff0c 而是用了他们的一个Lwip的配置文件lwipopt h文件 xff0c 事情是这样的 xff0c 我现在开发的这个项目用lwip的库 xff0c 版本是1 4 1 xff0c 上手的
  • SecureCRT连接超时设置-The semaphore timeout period has expired

    设置 设置后就不会出现短时间没有操作连接超时的局面 xff0c 要求需要再次重连的问题 FR 徐海涛 xff08 hunk Xu xff09 QQ技术交流群 xff1a 386476712
  • CANoe-Trace-CAN Error

    CANoe软件CAN Error排查经验案例 系统模拟充电桩 xff0c 和实车车辆通过枪线连接 xff0c 启动充电流程 xff0c 在Trace界面看到CAN1有故障 xff0c CAN Error xff0c 并且是TxError 原
  • Makefile的使用

    Makefile规则 规则解析 一个简单的 Makefile 文件包含一系列的 规则 xff0c 样式如下 xff1a 目标 target 依赖 prerequiries lt tab gt 命令 command 目标 xff08 targ
  • STM32用一个定时器输出多路不同频率及占空比的PWM(输出比较模式)

    我们使用STM32输出PWM时会使用定时器的PWM输出模式来进行生成 xff0c 但是这样子生成PWM是有局限的 xff0c 它只能生成四路频率相同的PWM xff0c 当你设定了TIMx PSC xff08 预分频寄存器 xff09 和T
  • 虚拟机的安装与开发环境的配置

    前言 最近开始接触嵌入式 xff0c 之前也就学过C语言 xff0c 但是都是是非常基础的一些知识 知识最高峰的时期就是为了过国家计算机二级C 而一通猛学 下面就放入我最近学习笔记的内容 一 Linux开发环境的搭建 下载VirtualBo
  • C语言:基础知识

    基础C语言 基本知识 如何在虚拟机上写代码 1 打开终端 xff08 Ctrl xff0b Alt xff0b t xff09 xff0c mkdir day01 创建目录 cd 目录名 2 vim file c xff0c 进入vim文本
  • 详解scanf、gets、getchar和getch 使用及其原理。

    scanf gets getchar和getch 使用及其原理 一 说在最前 xff1a 回车及换行 概念 在计算机还没有出现之前 xff0c 有一种叫做电传打字机 在电传打字机打字时 xff0c 在每行后面加两个表示结束的字符 xff0c
  • 小项目:学生成绩管理系统

    学生成绩管理系统 前言 xff1a 此项目不具有商业价值 xff0c 旨在总结C语言所学知识点及各知识点在项目中的运用 xff0c 主要锻炼编码能力 xff0c 程序设计能力 xff0c 对业务逻辑的理解能力 文章目录 学生成绩管理系统系统
  • C语言:指针学习以及理解

    C语言 xff1a 关于指针学习以及理解 文章目录 C语言 xff1a 关于指针学习以及理解一 什么是指针二 为什么使用指针 什么情况下使用指针三 如何使用指针四 使用指针要注意的问题五 指针与数组的关系六 指针的运算七 指针与const配