C语言(指针)4

                 Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注+收藏,欢迎欢迎~~     

                                💥个人主页:小羊在奋斗

                                💥所属专栏:C语言   

        本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为同样是初学者的学友展示一些我的学习过程及心得。文笔、排版拙劣,望见谅。 

一、指针与数组

        1.数组名

        通过前面的学习我们知道,数组名就是数组首元素的地址,但是看到下面的代码你会不会怀疑这句话呢?

        按道理说数组名是数组首元素的地址,那 sizeof(arr)求出来应该是4个字节的大小,这里为什么是40个字节的大小呢?

        其实,我们说数组名就是数组首元素的地址在大多数情况下并没有错,只是有两个例外。

        (1)sizeof(数组名):这里的数组名表示的是整个数组,计算的是整个数组的大小,单位是字节;

        (2)&数组名:这里的数组名表示的也是整个数组,取出的是整个数组的地址。 

            除此之外,数组名表示的都是数组首元素的地址。 

        看到上面 “取出的是整个数组的地址” 这句话,有些小伙伴可能又有疑惑了,因为他们记得我在之前的文章中说过,不管内存地址多大, “&” 操作符取出的只是内存单元地址最小的那个,那么不管是数组首元素的地址,还是整个数组的地址不是都一样吗?那为什么还要区分呢?

        如果你并没有这个疑惑,可能是你学的非常扎实,我们一起继续努力;也可能是你学的还不太扎实,或者没有好好看我之前的文章,罚你去看 —> C语言(指针)1 。

        我们在之前的文章中说过,指针的类型决定了指针的差异、决定了在对指针进行解引用时的权限、指针 +- 整数的结果取决于指针的类型等。我们还说过,地址就是指针,指针就是地址,当我们对数组首元素的地址和整个数组的地址进行一些操作时,你还觉得它们没什么区别吗?

        ( 我们每次打印得到的地址都不一样,不必在意 )。 

        可以看到,对数组首元素的地址+1增大了4个字节,对整个数组的地址+1增大了40个字节(其中地址是16进制表示),这一点相信看过我之前文章的小伙伴都已经非常清楚了,就不再赘述了。所以说,虽然数组首元素的地址和整个数组的地址取出来是一样的,但还是有很大的差别的。

        2.使用指针访问数组

        其实在之前的文章中我们已经多次的使用了指针来访问数组,这里只做一些补充。

        上面的几种输入方式都是可行的,但是你不能写成下面这种:

        上面代码的问题是,当输入操作结束后指针变量p已经指向数组内最后一个元素,如果你还想要通过指针自加的方式打印数组,就需要重新让指针变量p指针数组首元素。这种写法不推荐,还是写成之前的那几种形式更好一些。

        3. 一维数组传参的本质

        之前已经说过,数组传参的时候实参直接写数组名,传递的是数组首元素的地址,形参可以写数组的形式,也可以写指针的形式。来看下面的代码:

        上面sz1和sz2的值打印出来是一样的吗?如果不一样sz1和sz2分别等于多少?

        打印出来sz1 = 10,sz2 = 1。 

        对于sz1, sizeof(arr)中的 “arr” 表示的是整个数组的地址,所以sizeof(arr)求的是整个数组的大小,单位是字节,sizeof(arr[0])求的是数组首元素的大小,所以相除的结果应该就是数组内元素的个数;对于sz2,因为前面说过数组传参的时候传递的是数组首元素的地址,所以自定义函数fun()形参接收的时候自然只能得到数组首元素的地址,那么sizeof(arr)中的 “arr” 表示的只是数组首元素的地址,求出的就只是数组首元素的大小,sizeof(arr[0])求出的也是数组首元素的大小,所以相除的结果就为1。

        有没有对上面代码形参的部分写的 int arr [ ] 有疑惑呢,并不是我们之前写过的 int *arr,按道理来说数组传参传过来的是地址,应该用指针来接收,但是依旧能正常运行。所以我想说的是,arr[ ]本质上也是指针,arr[i] == *(arr + i)。其中括号内写不写数组的长度都是无所谓的,因为它只能接收首元素的地址。

        那我们想在自定义函数中使用数组内元素的个数这个值怎么办呢?很简单,将这个值作为函数参数传过去就行。

        总结:(1)不能看到sizeof(arr)就认定了arr表示的是整个数组的地址,还要看它是不是函数的形参;

                   (2)在用上面的方法求数组内元素个数的时候,最好紧跟在数组的定义后面写;

                   (3) 形参即使写成数组的形式,本质上也是一个指针变量;

                   (4)在自定义函数中使用数组内元素个数这个值需要在函数调用的时候作为函数参数传过去。

        4.冒泡排序

        学了上面的内容,我们就可以用数组和指针的知识来实现一下冒泡排序。我们这里写升序。

        首先,我们先简单地介绍一下冒泡排序是怎么一回事,详细的解释这里就不赘述了,不了解的同学还请查看别的资料。冒泡排序就是重复地遍历要排序的一组数,比较相邻的元素,并交换它们的位置,直到整个列表都是按照从小到大(或从大到小)的顺序排列,如果有N个元素重复的次数就是N - 1次。

        具体实现如下:

#include <stdio.h>void bubble_sort(int arr[], int n)
{int i = 0; int j = 0;int num = 0;printf("正序:");for (i = 0; i < n - 1; i++)//共n - 1趟{for (j = 0; j < n - 1 - i; j++){if (arr[j] > arr[j + 1]){num = arr[j];arr[j] = arr[j + 1];arr[j + 1] = num;}}}
}int main()
{//定义一个数组存放待排序的n个数int arr[100] = { 0 };int i = 0;int n = 0;while (scanf("%d", &arr[n++]), arr[n - 1] != -1);//以-1为输入结束标志n--;//冒泡排序函数bubble_sort(arr, n);for (i = 0; i < n; i++){printf("%d ", *(arr + i));}return 0;
}

        实验结果也没问题: 

        

        但上面的代码效率还不够高,还能再优化一下。请你思考一个问题,如果当某一趟前后两个数两两相互比较过后,并没有发生交换,这时候整个数组中的元素是不是已经有序了?答案是的。那按照上面的代码即使已经有序了还要把每一趟都判断一遍才能结束,做了很过无用功。

        某一趟没有发生交换,就说明这一趟并没有满足 if 判断表达式的情况,那我们就可以在 if 分支的外面和里面设定一个标志,当不满足某一条件是,说明并没有进入到 if 分支内,这时候就可以确定这组数已经有序,然后跳出循环结束任务。

#include <stdio.h>void bubble_sort(int arr[], int n)
{int i = 0; int j = 0;int num = 0;printf("正序:");for (i = 0; i < n - 1; i++)//共n - 1趟{int flag = 1;//假设这组数本来就是有序的for (j = 0; j < n - 1 - i; j++){if (arr[j] > arr[j + 1]){flag = 0;//还没有有序的时候改变标志num = arr[j];arr[j] = arr[j + 1];arr[j + 1] = num;}}if (1 == flag)//如果确实有序就跳出循环{break;}}
}int main()
{//定义一个数组存放待排序的n个数int arr[100] = { 0 };int i = 0;int n = 0;while (scanf("%d", &arr[n++]), arr[n - 1] != -1);//以-1为输入结束标志n--;//冒泡排序函数bubble_sort(arr, n);for (i = 0; i < n; i++){printf("%d ", *(arr + i));}return 0;
}

        如果一组待排序的数是最乱的情况,那上面的代码与之前的一样;如果一组待排序的数已经基本有序,那上面的代码效率更高。

        5.二级指针

        前面不止一次说过,指针变量也是变量,既然是变量就会有地址,普通变量的地址存放在指针变量中,那指针变量的地址存放到哪里呢?接下来就介绍二级指针。

        

        相信通过之前一级指针变量的学习,二级指针对我们来说简直易如反掌,这里就不再过多赘述了。另外三级指针也是这样的用法,但更高级的指针基本用不到。

         二级指针的用法也是类似一级指针的用法:

        ( **ppa == *pa == a )这就像我们玩的套娃,你想拿到最小的那个就一层一层的去找。

        按照前面的内容,一级指针和一维数组有着密切的联系,那二级指针和二维数组有没有联系呢?没有。 

        6.指针数组

        看到这个名字你有没有疑惑,指针数组到底是指针还是数组?我们知道,整型数组是存放整型元素的数组,字符数组是存放字符元素的数组,那同样的指针数组就是存放指针的数组了,其中元素的类型是指针类型。 

        为什么要有指针数组呢?原因和整型数组及其他数组一样,当我们想创建多个相同类型的变量的时候一个一个去创建很繁琐,于是就出现了相应类型的数组,那指针数组的出现也是一样。

        但我们需要创建多个指针变量的时候,指针数组就为我们提供了比较简洁的方法,当然和其他数组一样指针数组也可以遍历打印出来:

         需要注意的是此时数组里存的是地址,需要用解引用操作符 “ * ”。

        7.指针数组来模拟二维数组
         

        上面虽然我们没有定义二维数组,但我们用指针数组的方法模拟实现了二维数组。

        上面代码的执行细节是,我们首先对指针数组arr解引用找到对应下标的元素,其中元素也是地址,那我们再对这个地址解引用就能得到对应下标的元素,此时的元素就是arr1、arr2、arr3三个数组中存的整型元素。 

        如果觉得我的文章还不错,请点赞、收藏 + 关注支持一下,我会持续更新更好的文章。

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

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

相关文章

网络安全与IP地址的关联

网络安全与IP地址之间存在着密不可分的关系。IP地址作为网络通信的基础&#xff0c;对于网络安全的保障具有至关重要的作用。以下将详细探讨网络安全与IP地址之间的关联&#xff0c;以及IP地址在网络安全中的应用。 一、IP地址与网络安全的关系 IP地址是网络通信的基础&#x…

2024年人工智能数据报告

大家好&#xff0c;我是爱编程的喵喵。双985硕士毕业&#xff0c;现担任全栈工程师一职&#xff0c;热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。…

常用Linux命令详细总结

一、文档编辑、过滤、查看命令 1、cp 复制文件和目录 -a 复制文件并保持文件属性 -d 若源文件为链接文件&#xff0c;则复制链接文件属性而非文件本身 -i 覆盖文件前提示&#xff0c;如果不要提示&#xff0c;在命令前加上\ -r 递归复制&#xff0c;通常用于目录的复制 …

Java NIOAIO

多路复用概念介绍 多路复用是一个在计算机网络、操作系统&#xff0c;以及软件开发中广泛使用的技术&#xff0c;它允许单一的资源&#xff08;如网络连接或者CPU&#xff09;同时服务于多个请求或多个应用程序。在I/O操作&#xff08;输入/输出操作&#xff09;的上下文中&am…

什么是IP跳变?

IP 跳跃&#xff08;也称为 IP 跳动&#xff09;的概念已引起使用代理访问网站的用户的极大关注。但 IP 跳跃到底是什么&#xff1f;为什么它对于各种在线活动至关重要&#xff1f; 在本文中&#xff0c;我们将深入探讨 IP 跳跃的世界&#xff0c;探索其实际应用、用例、潜在问…

读写备份寄存器BKP与实时时钟RTC

文章目录 读写备份寄存器接线图代码 RTC实时时钟接线图代码 读写备份寄存器 接线图 即接个3.3v的电源到VBT引脚 代码 代码效果&#xff1a;第一次写入备份寄存器&#xff0c;下载程序后再注释掉&#xff0c;再进行下载&#xff0c;之前写入的数据还会保存在备份寄存器中&am…

使用 sudo apt upgrade 出现的提示

┌────────────────────────────────────────────────┤ Pending kernel upgrade ├────────────────────────────────────────────────┐ │ …

搭建一个vue3+vant4+vite4+pinia 的移动端h5模板

效果图 项目的创建和组件库的安装 项目创建 pnpm create vite vue3-vant4-vite-pinia-pro-h5注意&#xff1a; node版本控制在 18&#xff0c; 可以通过nvm来管理本地的node版本&#xff0c;具体可以看这篇文章 nvm的简单使用 vant-ui库的安装【这里安装的是 ^4.6.0 版本的】…

Maven- Profile详解

前言 Profile能让你为一个特殊的环境自定义一个特殊的构建&#xff1b;profile使得不同环境间构建的可移植性成为可能。 <project><profiles><profile><build><defaultGoal>...</defaultGoal><finalName>...</finalName><…

HTML控件和Web控件之间的区别是什么

HTML控件和Web控件在ASP.NET中有着不同的定义和用途&#xff0c;它们之间的主要区别体现在以下几个方面&#xff1a; 概念&#xff1a; HTML控件&#xff1a;就是我们通常所说的HTML语言标记&#xff0c;这些标记在静态页面和其他网页中存在。它们不能在服务器端直接控制&#…

linux系统服务器中常见故障及排查方法

目录 故障1&#xff1a;系统无响应 故障2&#xff1a;网络连接问题 故障3&#xff1a;文件系统错误 故障4&#xff1a;软件包依赖问题 故障5&#xff1a;用户权限问题 故障6&#xff1a;服务无法正常工作 故障7&#xff1a;磁盘空间不足 故障8&#xff1a;内存不足 故障…

2024年华为OD机试真题- 手机App防沉迷系统-(C++)-OD统一考试(C卷D卷)

题目描述: 智能手机方便了我们生活的同时,也侵占了我们不少的时间。“手机App防沉迷系统”能够让我们每天合理的规划手机App使用时间,在正确的时间做正确的事。 它的大概原理是这样的: 1、在一天24小时内,可注册每个App的允许使用时段; 2、一个时段只能使用一个App,举例…

掼蛋—开牌三步走

掼蛋是消遣也是一项脑力活动&#xff0c;除了牌运&#xff0c;还要掌握技巧。和大家一起分享一下掼蛋游戏中的“开牌三步走”技巧。 1、快速理牌 目的&#xff1a;潜力最大化 开局时可以快速查看一下自己的同花顺&#xff0c;优先保留不损害其他炸弹的同花顺&#xff0c;并及时…

精益生产咨询公司:深入探讨其独特魅力与核心竞争力

精益生产咨询公司&#xff0c;作为专注于帮助企业实现精益转型和效率提升的专业机构&#xff0c;在现代工业生产中扮演着不可或缺的角色。这些公司不仅具备深厚的行业经验和专业知识&#xff0c;还能够根据企业的实际情况和需求&#xff0c;提供个性化的解决方案和持续的支持服…

用户至上!探索7种常用的用户体验研究方法

用户体验研究是产品开放过程中的重要组成部分&#xff0c;优秀的产品设计与高质量的用户体验是不可分割的。对于产品开发&#xff0c;选择合适的用户体验研究方法在很大程度上决定了产品的使用效果。本文全面阐述了用户体验研究、用户体验研究的重要性和用户体验研究方法&#…

mamba复现—mamba+yolov8魔改(win)

Mamba复现出现的问题 安装下列步骤一步步走 一、 注&#xff1a;若是Windows环境下python一定是3.10版本的&#xff0c;要不然trition无法安装 conda create -n mamba python3.10 conda activate mamba conda install cudatoolkit11.8 -c nvidia pip install torch2.1.1 t…

探索国外静态住宅代理:保护网络安全与隐私的利器

随着互联网的日益发展&#xff0c;网络安全和隐私保护成为越来越多用户关注的焦点。在这个信息爆炸的时代&#xff0c;如何确保网络活动的匿名性和安全性成为了我们必须面对的问题。国外静态住宅代理作为一种新兴的网络技术&#xff0c;为我们提供了有效的解决方案。 &#xf…

OSTEP Projects:KV

本文将介绍操作系统导论&#xff08;Operating Systems: Three Easy Pieces&#xff09;作者所开源的操作系统相关课程项目 的 KV 部分&#xff0c;包含个人的代码实现和设计思路。 思路 题目要求实现一个最简单的数据库&#xff0c;以支持数据的持久化。 每个操作由格式为 o…

目标检测——道路检测数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

C#中的异步编程模型

在C#中&#xff0c;async和await关键字是用于异步编程的重要部分&#xff0c;它们允许你以同步代码的方式编写异步代码&#xff0c;从而提高应用程序的响应性和吞吐量。这种异步编程模型在I/O密集型操作&#xff08;如文件读写、网络请求等&#xff09;中特别有用&#xff0c;因…