【C语言入门】由浅入深学习指针 【第二期】

 

目录

 1. 指针变量为什么要有类型?

2. 野指针

2.1 未初始化导致的野指针

2.2 指针越界导致的野指针

2.3 如何规避野指针 

3. 指针运算

3.1 指针加减整数

3.2 指针减指针

3.3 指针的关系运算

4. 二级指针

5. 指针数组

5.1 如何使用指针数组模拟二维数组

        上一期已经解释了指针和指针变量的区别以及含义,这一期我们来具体了解一下指针到底有什么作用。

 1. 指针变量为什么要有类型?

        我们知道指针变量的大小是根据所在平台决定的,若平台是32位即x86环境,则指针变量是4个字节,若平台是64位,则指针变量是8个字节。既然指针变量不会根据指针类型变化,那么我们为什么要区分指针变量的类型呢?换句话说char* 和 int* 都有能力存储4个字节的地址,为什么不统一成一个自定义的指针变量例如ptr*

        从上图可以得知,我们把int*类型的地址强行赋给char*类型的地址,再进行取值调用的时候,会根据char*来进行赋值以至于只会将一个字节赋值成0,若是正常使用int*来接收,那么四个字节都是0 ,如下图所示。

        由下图可知,虽然不同指针变量的存储类型不影响地址的存储,但是当直接对地址进行运算,还是会根据指针类型的不同进行运算。char*类型+1,跳过1个字节,int*类型+1,跳过4个字节。

所以我们会得到这样的结论:指针变量的类型在存取地址的时候可有可无,在修改地址指向的内容的时候是非常有必要的,它决定了在利用地址更改值的时候需要更改多少个字节;若直接对地址进行运算,那么会根据指针变量的类型+‘1’,这个‘1’可能是char类型的一个字节,也可能是int类型的四个字节。 

使用float*和int*的时候,无论是访问内存还是使用内存,都是4个字节,那么可不可以混用呢?

答案是:不可以

下图是整型解引用赋值整型,我们可以看到100以16进制存入内存。

我们把100.0存入内存,发现内存存的数据发生了变化, 虽然都是100,但是浮点数存入内存的方式是不同的。

2. 野指针

        指针指向的内存没有初始化,或者已经被销毁,此时的指针称为野指针。

2.1 未初始化导致的野指针

2.2 指针越界导致的野指针

2.3 如何规避野指针 

①指针初始化。

②指针小心越界。

③指针指向的空间置为NULL。NULL是0,类型是void*,如果取值的话一定会报错(默认0地址不能访问),所以,我们可以先判断这个指针如果不是NULL再进行取值。

④避免返回局部变量的地址,因为局部变量已经被销毁了(没有那块内存空间的使用权限了)。

⑤指针使用之前检查有效性。

3. 指针运算

3.1 指针加减整数

这里的values[N_VALUES]并不算下标越界,因为并没有使用这段内存,只是用了一下这个地址作为判断条件。

3.2 指针减指针

当同类型的地址减去同类型的另外一个地址,得出的结果的绝对值是两个地址之间的元素个数

需要注意的是,两个指针指向的必须是同一块内存,不然毫无意义。

        那么有同学会想,指针+指针得到的结果是什么呢,这个结果毫无意义,类似于你可以把日期相减,得到天数,但是你不能把日期相加,这样就毫无意义

3.3 指针的关系运算

其实就是地址之间的比较,判断两个地址谁大谁小,从而对地址指向的内容进行操作。

4. 二级指针

        简单描述一下,就是指针变量里面存的地址,这个地址是一个指针的地址。乍一听是不是以为在说绕口令呢?下面用一张图来进行诠释。

        上图中表示int * pa = &a;我们可以这么理解:*号表明pa的类型是一个指针类型,int表明这个指针类型指向的是int类型;那么我们是不是可以来理解一下二级指针。

        int* *ppa = &pa;还是将类型拆开,距离ppa最近的*表明ppa是一个指针,int* 表明ppa指向的类型是int*的类型

总结:二级指针是用来存放一级指针变量的地址

5. 指针数组

主语是数组,即存放指针的数组就是指针数组

5.1 如何使用指针数组模拟二维数组

        首先构造出三个一维数组,所谓二维数组就是将这三个一维数组连起来;我们构造一个指针数组,分别存入之前构造的一维数组名,在之前的帖子说明,一维数组名是数组的第一个元素的地址,所以分别存入了三个地址,我们需要遍历指针数组,得到三个一维数组的首地址,再引入一个变量j,根据指针加减法,就可以访问一维数组中除了第一个元素的其他元素的地址,最后解引用就可以得到最后的结果。

#include <stdlib.h>int main()
{int arr1[4] = {1,2,3,4};int arr2[4] = {2,4,6,8};int arr3[4] = {3,6,9,12};
// 用一维数组模拟出二维数组的效果int* arr_sum[3] = {arr1,arr2,arr3};for(int i = 0;i < 3;i++){for(int j = 0;j < 4;j++){printf("%d ",*(arr_sum[i] + j));}printf("\n");}return(0);
}

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

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

相关文章

OpenCV 图形API(13)用于执行两个矩阵(或图像)逐元素乘法操作的函数mul()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 描述 计算两个矩阵的每个元素的缩放乘积。 mul函数计算两个矩阵的逐元素乘积&#xff1a; dst ( I ) saturate ( scale ⋅ src1 ( I ) ⋅ src2 ( I ) ) …

人工智能混合编程实践:C++调用封装好的DLL进行图像超分重建

人工智能混合编程实践:C++调用封装好的DLL进行图像超分重建 前言相关介绍C++简介ONNX简介ONNX Runtime 简介**核心特点**DLL 简介**核心特点****创建与使用****应用场景****优点与挑战**图像异常检测简介应用场景前提条件实验环境项目结构C++调用封装好的DLL进行图像超分重建C…

Linux内核之高效缓冲队列kfifo

一、先说FIFO 队列是常见的一种数据结构&#xff0c;简单看来就是一段数据缓存区&#xff0c;可以存储一定量的数据&#xff0c;先存进来的数据会被先取出&#xff0c;First In Fist Out&#xff0c;就是FIFO。 FIFO主要用于缓冲速度不匹配的通信。 例如生产者&#xff08;数…

【面试篇】Kafka

一、基础概念类 问题&#xff1a;请简述 Kafka 是什么&#xff0c;以及它的主要应用场景有哪些&#xff1f; 答案&#xff1a;Kafka 是一个分布式流处理平台&#xff0c;它以高吞吐量、可持久化、可水平扩展等特性而闻名。其主要应用场景包括&#xff1a; 日志收集&#xff1a…

解释回溯算法,如何应用回溯算法解决组合优化问题?

一、回溯算法核心原理 回溯算法本质是暴力穷举的优化版本&#xff0c;采用"试错剪枝"策略解决问题。其核心流程如下&#xff1a; ​路径构建&#xff1a;记录当前选择路径​选择列表&#xff1a;确定可用候选元素​终止条件&#xff1a;确定递归结束时机​剪枝优化…

Vue 学习随笔系列二十二 —— 表格高度自适应

表格高度自适应 文章目录 表格高度自适应1、方法一2、方法二 1、方法一 根据页面元素计算各自占比 <template><div class"main"><div class"query-form" ref"Query"><QueryFormref"QueryForm"query"query&q…

ubuntu22.04.5安装docker,解决安装出现的错误,解决Docker hello-world没打印出来

文章目录 前言一 安装失败解决1结合具体报错分析2 首先怀疑是VPN的问题3 直接百度报错信息4最终解决问题 二 验证Docker hello-world没打印出来总结 前言 先说一下前面的情况&#xff0c;使用的是公司的工作站&#xff0c;登录公司一个帐号使用的公司网络&#xff0c;使用网上…

idea插件(自用)

.ignore git排除文件插件&#xff1a;.ignore介绍 Grep console 自定义日志颜色&#xff1a;Grep console介绍 AceJump 光标快速定位&#xff1a;AceJump介绍 Key promoter 提示插件:Key promoter介绍 MetricsReloaded 分析代码复杂度的插件&#xff1a;MetricsReload…

让AI再次伟大-MCP-Client开发指南

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理、AI应用&#x1f525;如果感觉…

供应链管理:计算题 / 倒扣法

一、理解倒扣法 在供应链管理中&#xff0c;倒扣法是一种常用的成本计算方法&#xff0c;主要用于确定商品的成本和销售价格&#xff0c;以确保特定的毛利率。倒扣法的基本原理是在已知售价和期望毛利率的情况下&#xff0c;逆推计算出供货价或成本价。 二、倒扣法的计算公式…

skynet.start 的作用详细解析

目录 skynet.start 的作用详细解析1. 功能概述2. 基本用法3. 关键作用(1) 注册消息处理函数(2) 启动事件循环(3) 服务生命周期管理 4. 与其他函数的协作5. 未调用 skynet.start 的后果6. 高级场景&#xff1a;何时不需要 skynet.start7. 总结 skynet.start 的作用详细解析 在 …

基于yolo11的BGA图像目标检测

1.产生图像数据的分辨率 2.产生图像的大小 3.产生图像是黑白或是RGB彩色 灰度图像&#xff0c;达到识别要求&#xff0c;减少计算量 4.标注数据的精准程度 1.模型标注后&#xff0c;少量标注全部人工校验&#xff0c;大量数据抽检&#xff0c;部分人工检验 2.明确边界框贴合…

PADS 9.5【附破解文件+安装教程】中文激活版下载

第1步 将软件安装包下载到电脑本地&#xff0c;使用解压工具进行解压打开&#xff08;全程关闭杀毒软件以及防火墙&#xff0c;避免破解文件被删除&#xff09; 第2步 鼠标右键以管理员身份运行“PADS9.5_mib.exe” 第3步 加载片刻后&#xff0c;弹出如图界面&#xff0c;点击N…

电子电气架构 --- SOC设计流程及其集成开发环境

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 周末洗了一个澡&#xff0c;换了一身衣服&#xff0c;出了门却不知道去哪儿&#xff0c;不知道去找谁&am…

图扑 HT 电缆厂 3D 可视化管控系统深度解析

在当今数字化浪潮席卷制造业的大背景下&#xff0c;图扑软件&#xff08;Hightopo&#xff09;凭借其自主研发的强大技术&#xff0c;为电缆厂打造了一套先进的 3D 可视化管控系统。该系统基于 HT for Web 技术&#xff0c;为电缆厂的数字化转型提供了有力支撑。 HT 技术核心架…

【数据结构】邻接矩阵完全指南:原理、实现与稠密图优化技巧​

邻接矩阵 导读一、图的存储结构1.1 分类 二、邻接矩阵法2.1 邻接矩阵2.2 邻接矩阵存储网 三、邻接矩阵的存储结构四、算法评价4.1 时间复杂度4.2 空间复杂度 五、邻接矩阵的特点5.1 特点1解析5.2 特点2解析5.3 特点3解析5.4 特点4解析5.5 特点5解析5.6 特点6解析 结语 导读 大…

Docker Registry 清理镜像最佳实践

文章目录 registry-clean1. 简介2. 功能3. 安装 docker4. 配置 docker5. 配置域名解析6. 部署 registry7. Registry API 管理8. 批量清理镜像9. 其他10. 参考registry-clean 1. 简介 registry-clean 是一个强大而高效的解决方案,旨在简化您的 Docker 镜像仓库管理。通过 reg…

UART双向通信实现(序列机)

前言 UART&#xff08;通用异步收发传输器&#xff09;是一种串行通信协议&#xff0c;用于在电子设备之间进行数据传输。RS232是UART协议的一种常见实现标准&#xff0c;广泛应用于计算机和外围设备之间的通信。它定义了串行数据的传输格式和电气特性&#xff0c;以确…

机器学习算法分类全景解析:从理论到工业实践(2025新版)

一、机器学习核心定义与分类框架 1.1 机器学习核心范式 机器学习本质是通过经验E在特定任务T上提升性能P的算法系统&#xff08;Mitchell定义&#xff09;。其核心能力体现在&#xff1a; 数据驱动决策&#xff1a;通过数据自动发现模式&#xff0c;而非显式编程&#xff08…