深入理解并打败C语言难关之一————指针(3)
前言:
昨天把指针最为基础的内容讲完了,并且详细说明了传值调用和传址调用的区别(这次我也是做到了每日一更,感觉有好多想写的但是没有写完),下面不多废话,下面进入本文想要说的内容
目录:
1.数组名的理解
1.1数组名代表着什么
1.2.数组名的几种特殊情况
2.使用指针访问数组
2.1指针如何访问数组
3.一维数组传参的本质
4.冒泡排序算法的实现(先预热一下,这个太重要我写在下一篇了)
5.二级指针相关知识点
5.1二级指针是什么
5.2二级指针中的解引用操作
6.指针数组相关知识点
6.1指针数组
6.2利用指针数组模拟二维数组
正文:
1.数组名的理解
1,1数组名是什么
其实数组名我在之前就解释过了,现在我们正式的来介绍它,数组名是数组首元素的地址,通过代码的撰写就可以看出来二者是一样的,代码以及展示图如下:
#include<stdio.h>
int main()
{int arr[10] = {0};int *p = &arr[0];printf("%p",arr);printf("%p",p);return 0;
}
在说上面之前,我想起来我忘记说%p这个占位符的作用了,这个占位符是代表着地址的占位符,想要打印地址就需要它,不难看出,上面两个地址打印出来的结果是一样的,所以可以更好的理解数组名就是数组首元素的地址,不过,这也不是绝对的,下面一种特殊情况数组名就不是数组第一个元素的地址。
1.2数组名的几种特殊情况
1.2.1sizeof(arr)
我们知道,sizeof运算符是用来计算长度的,上面讲了,arr指的是数组第一个元素的地址,按道理来讲,我们计算arr的长度应该就是第一个元素的长度即四个字节,但是看见下面的代码和打印结果:
#include<stdio.h>
int main()
{int arr[10] = {0};printf("%zd",sizeof(arr));return 0;
}
我们不难看出,这里打印的结果是40个字节,为什么会打印出40呢?因为这是arr整体的元素个数,所以此时sizeof(arr)并不是第一个元素的长度,而是整个元素的长度,这个一定要记住,在某些企业的笔试题中或者正常的考试题中可能会出一个类似这样的题来迷惑你,所以我们要记住这个特殊情况! 不要出错,不要出错,不要出错!
1.2.2&arr
上面小编说过,arr是数组名,代表着数组第一个元素的地址,那么我们如果直接对arr去地址呢?这种情况我们先通过代码打印看一下:
#include<stdio.h>
int main()
{int arr[10] = { 0 };printf("%p\n", arr);printf("%p\n", &arr[0]);printf("%p\n", &arr);return 0;
}
看到这里可能有些读者朋友会想,这三个的地址不都是相同的吗?是不是&arr就是数组第一个元素的地址呢?当然,如果真一样的话,我写这个小标题就一点意义都没有了,先不要着急,我们再看一下下面这个代码就可以知道&arr到底指的是什么了:
#include<stdio.h>
int main()
{int arr[10] = { 0 };printf("%p\n", arr + 1);printf("%p\n", &arr[1]);printf("%p\n", &arr + 1);return 0;
}
这个时候就可以很清楚的发现三者的不同了,前两个肯定是一样的(前面的知识点的运用),而第三个,经过我们的计算,发现比前两个多了36个字节的内存空间 ,这是为什么呢?我也不卖关子了,其实取地址arr取到的是整个数组的地址,所以我们在进行加1操作的时候,其余都是加了一个字节,而&arr是跳跃了一个完全的数组,从而我们在想要取到地址的时候,一定要知晓取到的应该是一个完整的数组地址,不过刚开始指向的是数组第一个元素的地址罢了,在进行加减的时候一定要小心。
小结:
我们在使用数组名的时候一定要注意这两个特殊情况,除了这两个特殊情况意外,其余的数组名都是代表首元素的地址
2.使用指针去访问数组
2.1指针如何访问数组
其实用指针数组我在上一节课的代码中就已经实现了,以后我还是得改掉超前讲的坏毛病,不多废话,我们知道数组名就是数组第一个元素的地址,所以我们在使用输入函数的时候便可以用数组名来替代&arr[i]类似这样的写法,这样可以减少我们在使用scanf函数的时候忘记运用取地址符的尴尬情况(小编就时常忘记写这个,我还抱怨是编译器的问题,😅),在打印的时候我们就可以利用解引用操作符来实现操作,光说不练等于白说,下面来进行一个久违的环节,小小的例题
例1.利用指针访问数组随机打印五个数
#include<stdio.h>
int main()
{int arr[10] = { 0 };int i = 0;for (i = 0; i < 10; i++){scanf("%d", arr + i);}for (i = 0; i < 10; i++){printf("%d ", *(arr + i)); //在这里arr[i] == *(arr + i),甚至还可以写成[i]arr,我们在这里可以看出[]仅仅就是一个运算符罢了,不过为了视觉效果所以才这么用的}return 0;
}
可以看出这个功效和我们正常使用一位数组是一样的,不过正如我前面所说的,这样写可以避免一些错误的出现,这也让我们之后写数组的方式变得更多了 ,一定要合理运用(scanf函数会时时常忘记写的读者朋友们可以这么写呦~)。
3.一维数组传参的本质
数组我们是知道的,函数我们也是知道的,但是我们之前在利用函数传数组的参数的时候,我们也是传参的数组名,当时我们并没有考虑到数组名到底是干什么的,也不知道数组名就是数组第一个元素的地址,现在根据我们前面讲过的知识,下面小编出一个小小的题目,我们可以不可以通过函数来计算数组元素的个数呢?读者朋友们可以先思考一下,下面是相关代码:
#include<stdio.h>
void ceshi(int arr[10])
{printf("%zd", sizeof(arr));
}
int main()
{int arr[10] = { 0 };ceshi(arr);return 0;
}
可以看出打印出来的结果是8(我这是在X64环境下写的),不难看出,此时打印的数组元素的地址的大小,并没有打印出整个元素的字节长度,原因很简单,我们知道arr是数组名,代表的是第一个元素的地址,所以我们传过去的是地址,计算长度的时候自然就是计算地址的长度了!所以我们每次想要传数组的时候,需要把数组的个数也传递过去。对于数组传参,其实是有两种形式的,下面来展示一下:
#include<stdio.h>
void ceshi1(int arr[10])
{//我就不写内容了,看外观别看内容
}
void ceshi2(int* arr)
{//这两个是一样的,小编比较喜欢写第一个的形式(说实在的这个形式在我复习的时候我才记着有)
}
int main()
{int arr[10] = { 0 };ceshi1(arr);ceshi2(arr);return 0;
}
正如我在代码页所写的,两种形式均可,可以按着自己习惯来进行书写,第二个可以更好的展示为什么字节数是4 / 8个,因为这本来就是计算地址的长度!
小结:
对于这部分的知识点,大家一定要好好掌握(客套话),下面进入二级指针(冒泡排序我觉着单独出一篇来写去,感觉写在中间有点显的它不重要) 。
4.冒牌排序算法的实现(下一篇见喽)
5.二级指针相关知识点
5.1.二级指针是什么
我们知道,指针变量也是变量,同样也是有地址的,对于普通变量地址的存放是在指针里面,那么指针变量的地址应该存放到哪里呢,显然易见,它会放到二级指针里面,所以用大白话来讲,二级指针就是指针的指针,对于它如何进行初始化,下面献上代码:
#include<stdio.h>
int main()
{int a = 20;int* p = &a;int** m = &p; //可以这么记,有多少个*就代表着几级指针在初始话的时候return 0;
}
正如我上问所说,经过我的观察,我发现*数决定着几级指针,其实二级指针目前我也没有设计很多,大多数题目设计到的都是一级指针,二级指针先知道大概就行,小编觉着这个在后期(数据结构,我还没学不知道大概)使用的应该更广一点。
5.2.二级指针的解引用操作
我们知道,在一级指针的时候进行解引用操作的时候,会直接取到这个数的本身,所以我们类比二级指针,在二级指针进行解引用的时候,会直接对应到一级指针的内容,也就是一级指针对应元素的地址,详情的代码如下:
#include<stdio.h>
int main()
{int a = 20;int* p = &a;int** m = &p;printf("%p\n", p);printf("%p", *m);return 0;
}
从上面可以很显然的看出二者是相同的,这更加的证实了我上面所说,对二级指针进行第一次解引用的时候,得出的是一级指针的详情内容,划重点(第一次),所以有一必有二,二级指针也可以进行二次解引用,试想一下,第一次解引用的时候取到的是一级指针,对二级指针进行解引用的时候就是对一级指针再次进行解引用,得到了数的本身,很有趣吧,知识都是环环相扣的,下面是代码展示:
#include<stdio.h>
int main()
{int a = 20;int* p = &a;int** m = &p;**m = 12;printf("%d\n", a);printf("%d\n", **m);return 0;
}
上面的代码很好的证实了我刚才说的正确性,所以二级指针是可以进行二次解引用的,当然,除了二级指针,还有三级指针,四级指针等等 ,不过这些都不经常使用,所以,指针记住一级指针=和二级指针就好,我们记住对我们有用的,记太多是容易遗忘的。
小结:
二级指针的知识已经全部都讲完了,希望读者朋友们好好的理解,下面进入最后一小节喽!
6.指针数组相关知识点
6.1指针数组
在讲到这个之前,记住这是指针数组,一定要跟后期的数组指针区分开, 这俩真容易弄混。好了,进入正题,指针数组这个名字,可以类比记忆,类似整型数组,浮点型数组,顾名思义,这是个存放指针的数组,数组中的每一个元素都是指针(地址),下面来介绍一下它是如何进行初始化的:
int * arr[5] = {0};
int代表的是类型,这一个不唯一,我只是当作例子展示一下,也可以是float,double等等,* 代表的是指针类型,arr是指的名字,arr[5]代表着存了五个地址,一定要记住它的写法,后期有很多指针类型等着我们记,我们一定不要搞混,这便是指针数组的初始化,下面可以进入一个小小的案例:用指针数组来模拟实现二维数组(小重点)!
6.2.利用指针数组模拟二维数组
二维数组我们都知道(这部分我没有出博客,因为我有点懒),我们可以通过我们刚刚了解到的指针数组来进行模拟实现二维数组,下面先呈上代码供各位观看(代码下面是讲解
#include<stdio.h>
int main()
{int arr1[5] = { 1,2,3,4,5 };int arr2[5] = { 1,2,3,4,5 };int arr3[5] = { 1,2,3,4,5 };int* arr[] = { arr1,arr2,arr3 }; //存放的都是数组第一个元素的地址,存放地址的叫做指针数组int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("%d ", *(*(arr + i) + j)); //也可以写成arr[i][j]//上面这个是挨着访问的,具体理解我写到博客里面,在这里我不好展开}printf("\n");}return 0;
}
下面我们来对上面的代码进行更详细的解释 ,首先我们先要设置三个数组,里面都放着想对应的元素,是为了后续二维数组更加的完善,我们先把每个数组的首地址放到指针数组里面,为了可以把每个元素都打印出来,我们设置了两层循环,外层循环三次的原因是因为先选好每一个数组是什么,就比如i是0的时候,这时候开始访问第一个数组的地址,我们之后在进行循环就可以打印出第一个数组的内容了,这里的知识点涉及到了上面小编写过的《使用指针访问数组》就写到了如何用指针来写出数组,之后每次i++就会打印每一行数组的内容了,然后我们便模拟出了二维数组,小编画了两张抽象图片供读者理解:
这个图虽然有点抽象,但我也画出了大概的雏形,就比如右图代表着设置了三个数组,左边代表着指针数组里面包含着三个数组首元素的地址。
小结:
数组指针是指针中较为重要的知识点,读者朋友们一定要好好的领悟这个,不然后期真的很容易和数组指针弄混,小编建议大家可以看完文章后敲一下我在这篇文章写过的代码一定会有收获的!
总结:
可算是写完这篇文章了,这篇文章可以看作是指针的进阶篇,指针从这便开始上强度了,大家一定要好好的学会指针,学会指针C语言便会打下半壁江山,加油,以后大厂的程序员们!如果文章出现了差错,欢迎从评论区指出,希望各位可以多点点赞,您的点赞便是我进步的动力,我们下一篇见啦!
相关文章:

深入理解并打败C语言难关之一————指针(3)
前言: 昨天把指针最为基础的内容讲完了,并且详细说明了传值调用和传址调用的区别(这次我也是做到了每日一更,感觉有好多想写的但是没有写完),下面不多废话,下面进入本文想要说的内容 目录&#…...

Ubuntu-24.04-live-server-amd64启用ssh
系列文章目录 Ubuntu-24.04-live-server-amd64安装界面中文版 Ubuntu安装qemu-guest-agent Ubuntu乌班图安装VIM文本编辑器工具 文章目录 系列文章目录前言一、输入安装命令二、使用私钥登录(可选)1.创建私钥2.生成三个文件说明3.将公钥复制到服务器 三…...
Leetcode 2786. 访问数组中的位置使分数最大(DP 优化)
Leetcode 2786. 访问数组中的位置使分数最大 DP 以每个位置为结尾的序列的分数取决于前方的分数,根据奇偶性计算,取最大值 超时 class Solution {public long maxScore(int[] nums, int x) {int n nums.length;long dp[] new long[n];Arrays.fill(dp…...

【docker实战】使用Dockerfile的COPY拷贝资源遇到的问题
事情是这样的。 在我负责的golang项目中,使用硬代码验证某块逻辑。比如: 于是,为了解决硬代码的问题,我制作了表格工具:【开源项目】Excel数据表自动生成工具v1.0版 – 经云的清净小站 (skycreator.top)。 使用表格工…...

如何用多线程执行 unittest 测试用例实现方案
前言 使用python做过自动化测试的小伙伴,想必都知道unittest和pytest这两个单元测试框架,其中unittest是python的官方库,功能相对于pytest来要逊色不少,但是uniitest使用上手简单,也受到的很多的小伙伴喜爱。一直以来都…...

Ascend310 EP模式下容器内进行推理测试
EP模式下容器内进行推理测试 本文的软硬件环境如下: 机器:x86台式机一台 OS: 5.4.0-26-generic Ubuntu20.04 LTS 推理卡:DLAP200-HP-2(凌华基于atlas200模块打造的两模块推理卡) 1. 推理卡固件和驱动安…...

(el-Transfer)操作(不使用 ts):Element-plus 中 Select 组件动态设置 options 值需求的解决过程
Ⅰ、Element-plus 提供的Select选择器组件与想要目标情况的对比: 1、Element-plus 提供Select组件情况: 其一、Element-ui 自提供的Select代码情况为(示例的代码): // Element-plus 提供的组件代码: <template><div class"f…...
Java基础之Math与Array类与System
文章目录 一、Math.random()二、Arrays.binarySearch()三、asList()四、System tip:以下是正文部分 一、Math.random() a < num < b int num (int)(Math.random() * (b - a 1)) a二、…...

警告:Hydration attribute mismatch on Note: this mismatch is check-only.(水合不匹配)
vue3Nuxt3运行代码是提示如下警告 [Vue warn]: Hydration attribute mismatch on <ul id"sub_menu_5_$$_sub1-popup" class"ant-menu ant-menu-sub ant-menu-inline" data-menu-list"true" style"display:none;">…...

【机器学习】CART决策树算法的核心思想及其大数据时代银行贷款参考案例——机器认知外界的重要算法
目录 引言 概述 CART决策树的特点 核心思想 减少不确定性的指标 基尼系数(Gini Index) 分类错误率 熵 银行实例 背景 数据准备 模型构建 模型评估与优化 应用与结果 代码示例 ✈✈✈✈引言✈✈✈✈ CART算法既可以用于分类问题࿰…...
编程软件是由什么编程的
编程软件是由什么编程的 在数字化的世界里,编程软件作为构建数字生态的基石,其背后所蕴含的奥秘往往令人感到困惑。那么,这些编程软件究竟是由什么编程的呢?这背后隐藏着怎样的逻辑与技术?接下来,我们将从…...

如何查看自己本地ip
1.winR 2.cmd 3.ipconfig...

高考分数限制下,选好专业还是选好学校?
高考分数限制下,选好专业还是选好学校? 高考作为每年一度的盛大考试,不仅关乎学生们的未来,更承载了家庭的期望。2004年高考刚刚结束,许多考生和家长已经开始为填报志愿而焦虑。选好学校和专业,直接关系到…...
Django学习(2)项目实战
1、环境及简介 前端开发:HTML、CSS、JavaScript 后端开发:Java、PHP、Python、GO 数据库:MySQL、MSSQL、Oracle、Redis 安装Django pip install Django 或 下载.whl后 pip install D:\xxx.whl 创建Django项目 File--New Projec…...

pdf格式转成jpg图片,pdf格式如何转jpg
pdf转图片的方法,对于许多人来说可能是一个稍显陌生的操作。然而,在日常生活和工作中,我们有时确实需要将pdf文件转换为图片格式,以便于在特定的场合或平台上进行分享、展示或编辑。以下,我们将详细介绍一个pdf转成图片…...

Java的三个接口Comparable,Comparator,Cloneable(浅拷贝与深拷贝)
Comparable 当我们要进行对象的比较的时候,我们是不能直接用>、< 这些符号直接进行比较的。 由于这是引用类型变量也是自定义类型变量,直接进行比较的时候,我们是通过对象的地址进行比较的,我们可以使用、! 进行两个对象的…...

pytorch学习笔记7
getitem在进行索引取值的时候自动调用,也是一个魔法方法,就像列表索引取值那样,一个意思 import torchvision from torch.utils.data import DataLoaderdata_transformtorchvision.transforms.Compose([torchvision.transforms.ToTensor()] ) test_datatorchvision.datasets.C…...
LeetCode热题3.无重复的最长字串
前言: 经过前序的一系列数据结构和算法学习后,开始用leetCode热题练练手。 . - 力扣(LeetCode) 给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为…...

Python武器库开发-武器库篇之SQL注入扫描器(五十九)
Python武器库开发-武器库篇之SQL注入扫描器(五十九) SQL注入漏洞简介以及危害 SQL注入漏洞是一种常见的Web应用程序漏洞,攻击者可以利用该漏洞在应用程序的数据库中执行恶意的SQL查询或指令。这可能导致数据泄露、数据损坏、应用程序崩溃或未经授权的访问。 SQL注…...

图说设计模式:单例模式
更多C学习笔记,关注 wx公众号:cpp读书笔记 5. 单例模式 单例模式 模式动机模式定义模式结构时序图代码分析模式分析实例优点缺点适用环境模式应用模式扩展总结 5.1. 模式动机 对于系统中的某些类来说,只有一个实例很重要,例如…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...