当前位置: 首页 > news >正文

指针!!C语言(第二篇)

目录

一. 数组名的理解

二. 一维数组传参的本质

三. 冒泡排序法

四. 二级指针与指针数组

五. 字符指针变量与数组指针


一. 数组名的理解

在我们对指针有了初步的理解之外,今天我们来掌握一些新的知识就是数组与指针,第一个对数组名的了解,我们先来看一段代码:

int main()
{int arr[5] = { 1,2,3,4,5 };int* p = &arr[0];//取出arr数组中第一个元素的地址printf("&arr[0]=%p\n", &arr[0]);return 0;
}

在上面的代码中我们可以看到我们取出了arr数组中的第一个元素的地址,并将其打印出来,而在在之前的知识中我们也提到过,其实数组名就是数组首元素的地址,为了验证这个结论的正确性,我们看下面一张图片:

从图我们可以看出来,&arr[0]和arr的地址是一样的,所以说明数组名的地址就是数组首元素的地址,但是还是有两个例外的,比如说sizeof(arr),计算的并不是首元素的字节,而是整个数组的字节,再比如&数组名,取出的是也整个数组。我们插入一段代码来看看具体的情况:

int main()
{int arr[5] = { 1,2,3,4,5 };int* p1 = &arr[0];int* p2 = arr;int* p3 = &arr;printf("&arr[0]     =%p\n", &arr[0]);printf("&arr[0]+1   =%p\n", &arr[0]+1);printf("arr         =%p\n", arr);printf("arr+1       =%p\n", arr+1);printf("&arr        =%p\n", &arr);printf("&arr+1      =%p\n", &arr+1);return 0;
}

从上面的代码中我们可以更直观的感受arr和&arr的区别,arr+1移动了4个字节,而&arr+1移动了20个字节,也就是移动了一整个数组,这就是arr和&arr最本质的区别。 

使用指针打印数组:

在学习上面的知识之后,我们可以试着用指针打印出数组:

int main()
{int arr[5] = { 0 };int sz = sizeof(arr) / sizeof(arr[0]);int* p = &arr[0];for (int i = 0; i < sz; i++){scanf("%d", p+i);}for (int i = 0; i < sz; i++){printf("%d ", *(p + i));}return 0;}

我们再试一下,如果我们再分析⼀下,&arr[0]是数组元素的地址,可以赋值 给p,其实&arr[0]和p在这里是等价的。那我们可以使用arr[i]可以访问数组的元素,那p[i]是否也可 以访问数组呢?
将*(p+i)换成p[i]也是能够正常打印的,所以 本质上p[i] 是等价于 *(p+i)
同理arr[i] 应该等价于 *(arr+i),数组元素的访问在编译器处理的时候,也是转换成 首元素的地址+偏移量 求出元素的地址,然后 解引用 来访问的。

二. 一维数组传参的本质

然后我们讨论一下数组传参的本质。
首先从一个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把数组传给⼀个函 数后,函数内部求数组的元素个数吗?
#include <stdio.h>
void test(int arr[])
{int sz2 = sizeof(arr)/sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int sz1 = sizeof(arr)/sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}

打印出的如果可能会让我们抓不着头脑,到底是为什么呢?这里也为大家解释一下,数组名是数组首元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参传递的是数组首元素的地址所以函数形参的部分理论上应该使用指针变量来接收首元素的地址。那么在函数内部我们写 sizeof(arr) 计算的是⼀个地址的大小(单位字节)而不是数组的大小(单位字节)。正是因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的。所以数组在传参的时候也是可以直接出传入指针的。eg:int* arr。

三. 冒泡排序法

学习了上面的知识之后我们来练习一个题目,要求就是在数组中输出一些乱序数字,最终可以升序排列出来。下面给出大家一张图片说明:

代码如下:

void test(int arr[], int sz)//参数接收数组元素个数
{int i = 0;for (i = 0; i < sz - 1; i++){int flag = 1;//假设这⼀趟已经有序了int j = 0;for (j = 0; j < sz - i - 1; j++){if (arr[j] > arr[j + 1]){flag = 0;//发⽣交换就说明,⽆序int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}if (flag == 1)//这⼀趟没交换就说明已经有序,后续⽆序排序了break;}
}int main()
{int arr[10] = { 0 };int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;for (int i = 0; i < sz; i++){scanf("%d", p + i);}test(arr, sz);for (int i = 0; i < sz; i++){printf("%d ", *(p + i));}return 0;
}

上面的代码详细的展示了整个冒泡排序法的过程,对应了上面的图片解释,另外加上了一个int flag=1;就是说如果我们输入直接是有序的,那就没有没有必要再去排一遍,所以我们在if里面增加一个条件,如果需要发生交换就将flag置为0。如果flag=1,就说明这一趟已经有序了,进行下一趟排序。大家也可以自己动手操作一下。

四. 二级指针与指针数组

二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里? 这就是二级指针

eg:int a = 10;
        int* p = &a;
        int**pa = &p;→将p的地址存放在二级指针pa中。同时解引用**pa就是找到a的值。
指针数组
顾名思义就是指存放指针的数组,也就是说数组的每个元素其实是指针类型。指针数组的每个元素都是用来存放地址(指针)的。

使用指针数组模拟二维数组: 

 

int main()
{int arr1[5] = { 1,2,3,4,5 };int arr2[5] = { 2,3,4,5,6 };int arr3[5] = { 3,4,5,6,7 };int* pa[3] = { arr1,arr2,arr3 };int i = 0;int j = 0;for (i = 0; i < 3; i++){for (j = 0; j < 5; j++){printf("%d ", pa[i][j]);}printf("\n");}
}

pa[i]是访问pa数组的元素, pa[i]找到的数组元素指向了整型一维数组 ,pa[i][j]就是整型一维数
组中的元素。
上述的代码模拟出二维数组的效果,实际上并非完全是二维数组,因为每一行并非是连续的。

五. 字符指针变量与数组指针

我们可以想到指针变量可以是整型的,就会有字符型的,即char*:

int main()
{char ch = 'w';char *pc = &ch;*pc = 'w';return 0;
}

同时也可以:

int main()
{const char* pstr = "hello bit.";printf("%s\n", pstr);return 0;
}

在这个代码中我们可以想想是不是把hello bit完全放入指针pstr中呢代码 const char* pstr = "hello bit."; 特别容易让同学以为是把字符串 hello bit 放 到字符指针 pstr 里了,但其实本质是把字符串 hello bit. 首字符的地址放到了pstr中。下面我们来练习一道与字符相关的习题:

#include <stdio.h>
int main()
{char str1[] = "hello bit.";char str2[] = "hello bit.";const char *str3 = "hello bit.";const char *str4 = "hello bit.";if(str1 ==str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if(str3 ==str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}
1

 

这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域, 当 几个指针指向同一个字符串的时候,他们实际会指向同一块内存 。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。

 

数组指针
前面我们说 指针数组 ,指的是数组,那么 数组指针 指的是什么呢?数组指针 指向数组的指针,也即是指针变量。
整形指针变量: int * pa; 存放的是整形变量的地址,能够指向整形数据的指针。
浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。
所以数组指针存放的应该是数组的地址,能够指向数组的指针变量
下面我们来思考一下:1.  int *p1[ 10 ];      2.  int (*p2)[ 10 ];p1和p2分别代表什么?在这里就给大家区分一下, p先和*结合,说明p是一个指针变量 ,然后指针指向的是一个大小为10个整型的数组。所以p是 一个指针,指向一个数组,叫数组指针。
这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。
数组指针变量怎么初始化
数组指针变量是用来存放 数组地址的 ,那怎么获得数组的地址呢?就是我们之前学习的 &数组名
1. int arr[ 10 ] = { 0 };
2. &arr;//得到的就是数组的地址
如果要存放个数组的地址,就得存放在数组指针变量中,如下:
int(*p)[10] = &arr;

 

 

 

 

 

 

相关文章:

指针!!C语言(第二篇)

目录 一. 数组名的理解 二. 一维数组传参的本质 三. 冒泡排序法 四. 二级指针与指针数组 五. 字符指针变量与数组指针 一. 数组名的理解 在我们对指针有了初步的理解之外&#xff0c;今天我们来掌握一些新的知识就是数组与指针&#xff0c;第一个对数组名的了解&#xff…...

AIGC-ToonCrafter: Generative Cartoon Interpolation

论文:https://arxiv.org/pdf/2405.17933 代码:https://doubiiu.github.io/projects/ToonCrafter 给定首尾帧&#xff0c;生成逼真生动的动画 MOTIVATION Traditional methods which implicitly assume linear motion and the absence of complicated phenomena like disoccl…...

牛奶供应(三)

一个字贪&#xff0c;第一天&#xff0c;只能选择制作方式&#xff0c;后面的每一天&#xff0c;在<今天制作>与<前期存储>之间取更优解 例如样例&#xff1a;100 5&#xff0c;200 5&#xff0c;90 20&#xff0c;存储成本为10 第1天&#xff1a; 一定是制作&…...

首批通过 | 百度通过中国信通院H5端人脸识别安全能力评估工作

2024年5月&#xff0c;中国信息通信研究院人工智能研究所依托中国人工智能产业发展联盟安全治理委员会&#xff08;AIIA&#xff09;、“可信人脸应用守护计划”及多家企业代表共同开展《H5端人脸识别线上身份认证安全能力要求及评估方法》的编制工作&#xff0c;并基于该方法开…...

JVM---对象是否存活及被引用的状态

1.如何判断对象是否存活 1.1 引用计数算法 概念&#xff1a;在对象头部增加一个引用计数器,每当有一个地方引用它时&#xff0c;计数器值就加一&#xff1b;当引用失效时&#xff0c;计数器值就减一&#xff1b;任何时刻计数器为零的对象就是不可能再被使用的。 优点&#xff1…...

科研绘图系列:R语言分割小提琴图(Split-violin)

介绍 分割小提琴图(Split-violin plot)是一种数据可视化工具,它结合了小提琴图(violin plot)和箱线图(box plot)的特点。小提琴图是一种展示数据分布的图形,它通过在箱线图的两侧添加曲线来表示数据的密度分布,曲线的宽度表示数据点的密度。而分割小提琴图则是将小提…...

WEB前端09-前端服务器搭建(Node.js/nvm/npm)

前端服务器的搭建 在本文中&#xff0c;我们将介绍如何安装和配置 nvm&#xff08;Node Version Manager&#xff09;以方便切换不同版本的 Node.js&#xff0c;以及如何设置 npm&#xff08;Node Package Manager&#xff09;使用国内镜像&#xff0c;并搭建一个简单的前端服…...

ASP.NET Core在启动过程中使用数据库实例的几种方式

ASP.NET Core项目启动过程中若要调用SqlSugarClient实例操作数据库数据&#xff08;假设操作函数如下&#xff09;&#xff0c;特此记录以下几种方式&#xff1a; public class PublicDataBuffer {public static List<EnvironmentRecord> DataBuffer new List<Envir…...

AndroidStudio 编辑xml布局文件卡死问题解决

之前项目编写的都是正常&#xff0c;升级AndroidStudio后编辑布局文件就卡死&#xff0c;还以为是AndroidStudio文件。 其实不然&#xff0c;我给整个项目增加了版权声明。所以全部跟新后&#xff0c;布局文件也增加了版权声明。估计AndroidStudio在 解析布局文件时候因为有版…...

使用 PVE 自签 CA 证书签发新证书

前言 PVE 安装时会自动创建一个有效期 10 年的 CA 证书, 我们可以利用这个 CA 证书给虚拟机中的 Web 应用签发新的 TLS 证书用于提供 HTTPS 服务. 下面以 PVE 虚拟机中通过 Docker 跑的一个 雷池 应用为例进行演示. PVE 证书位置 官方文档: https://pve.proxmox.com/wiki/Pr…...

ubuntu 22.04安装Eigen

1 安装 git clone https://gitlab.com/libeigen/eigen.gitcd eigen mkdir build cd build cmake ..sudo make install... -- Installing: /usr/local/include/eigen3/unsupported/Eigen/CXX11/src/TensorSymmetry -- Installing: /usr/local/include/eigen3/unsupported/Eige…...

vue使用audio 音频实现播放与关闭(可用于收到消息给提示音效)

这次项目中因为对接了即时通讯 IM&#xff0c;有个需求就是收到消息需要有个提示音效&#xff0c;所以这里就想到了用HTML5 提供的Audio 标签&#xff0c;用起来也是很方便&#xff0c;首先让产品给你个提示音效&#xff0c;然后你放在项目中&#xff0c;使用Audio 标签&#x…...

STM32 产生Hard Fault 调试方法

STM32 产生hard-fault 调试方法 需求 当STM32 产生Hard Fault的时候我们希望可以打印出一些重要的寄存器信息&#xff0c;然后定位代码出错的地方。 参考 https://github.com/ferenc-nemeth/arm-hard-fault-handler 原理 STM32代码运行的时候一般在是main函数while(1)中循…...

java-selenium 截取界面验证码图片并对图片文本进行识别

参考链接 1、需要下载Tesseract工具并配置环境变量&#xff0c;步骤如下 Tesseract-OCR 下载安装和使用_tesseract-ocr下载-CSDN博客 2、需要在IDEA中导入tess4j 包&#xff1b;在pom.xml文件中输入如下内容 <!--导入Tesseract 用于识别验证码--><dependency>&l…...

【Linux】进程信号 --- 信号产生

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…...

Docker 容器中的 Docker Compose 简介

Docker Compose是什么 Docker Compose是一个用于定义和运行多个Docker容器的工具。它是Docker官方提供的开源项目&#xff0c;用于实现对Docker容器集群的快速编排。通过Compose&#xff0c;开发者可以使用YAML文件&#xff08;通常是docker-compose.yml文件&#xff09;来配置…...

手机日历如何与Outlook同步

有很多人和我一样遇到手机日历与Outlook同步问题&#xff0c;如新版outlook与小米日历的同步问题 - Microsoft Community&#xff0c;outlook账号无法在手机端自带的电子邮件App以exchange模式登录 - Microsoft Community&#xff0c;在安卓手机端无法电子邮件App以exchange模式…...

python基础语法 007 文件操作-1读取写入

1 文件操作 1.1 什么时候用文件操作&#xff1f; 打开文档写东西看东西拿文档做统计 在python 文档操作作用 存储数据读取数据 打开文件有什么用&#xff1f; 读取数据&#xff0c;写入数据不管什么数据都可以用open打开&#xff0c;如可复制一张图片 1.2 open() 读取,…...

C语言·函数(超详细系列·全面总结)

前言&#xff1a;Hello大家好&#x1f618;&#xff0c;我是心跳sy&#xff0c;为了更好地形成一个学习c语言的体系&#xff0c;最近将会更新关于c语言语法基础的知识&#xff0c;今天更新一下函数的知识点&#xff0c;我们一起来看看吧&#xff01; 目录 一、函数是什么 &a…...

Windows及Linux系统加固

君衍. 一、Windows加固1、配置简介2、账户配置3、本地配置4、安全设置 二、Linux加固1、配置简介2、网络配置3、日志和审计配置4、访问认证和授权配置5、系统运维配置 一、Windows加固 1、配置简介 通常在Windows安全配置中有两类对象 一类是Windows Server&#xff0c;如win …...

Postman安装使用教程(详解)

目录 一、Postman是什么 二、安装系统要求 三、下载Postman 四、注册和登录Postman 五、创建工作空间 六、创建请求 一、Postman是什么 在安装之前&#xff0c;让我们先来简单了解一下Postman。Postman是一个流行的API开发工具&#xff0c;它提供了友好的用户界面用于发送…...

【嵌入式开发之标准I/O】文件I/O的基本概念,打开、关闭、定位函数及实例

文件I/O和标准I/O 什么是文件I/O?什么是标准I/O? 文件I/O&#xff1a;文件I/O又称系统IO&#xff0c;系统调用&#xff0c;称之为不带缓存的IO&#xff08;unbuffered I/O)。是操作系统提供的API接口函数。不带缓存指的是每个read&#xff0c;write都调用内核中的一个系统调…...

C++文件操作-文本文件-读文件

第一种 #include<iostream>//1、包含头文件 fstream #include<fstream> using namespace std;void test01() {//2、创建流对象ifstream ifs;//3、打开文件 并且判断是否打开成功ifs.open("test.txt", ios::in);if (!ifs.is_open()){cout << "…...

二叉树精选面试题

&#x1f48e; 欢迎大家互三&#xff1a;2的n次方_ 1. 相同的树 100. 相同的树 同时遍历两棵树 判断结构相同&#xff1a;也就是在遍历的过程中&#xff0c;如果有一个节点为null&#xff0c;另一棵树的节点不为null&#xff0c;那么结构就不相同 判断值相同&#xff1a;只需…...

如何在 Android 中删除和恢复照片

对于智能手机用户来说&#xff0c;相机几乎已经成为一种条件反射&#xff1a;你看到值得注意的东西&#xff0c;就拍下来&#xff0c;然后永远保留这段记忆。但如果那张照片不值得永远保留怎么办&#xff1f;众所周知&#xff0c;纸质快照拿在手里很难舍弃&#xff0c;而 Andro…...

HarmonyOS Next原生应用开发-从TS到ArkTS的适配规则(六)

一、仅支持一个静态块 规则&#xff1a;arkts-no-multiple-static-blocks 级别&#xff1a;错误 ArkTS不允许类中有多个静态块&#xff0c;如果存在多个静态块语句&#xff0c;请合并到一个静态块中。 TypeScript class C {static s: stringstatic {C.s aa}static {C.s C.s …...

功能测试与APPSCAN自动化测试结合的提高效率测试策略

背景 手工探索性测试&#xff08;Manual Exploratory Testing&#xff0c;简称MET&#xff09;是一种软件测试方法&#xff0c;它依赖于测试人员的直觉、经验和即兴发挥来探索应用程序或系统。与传统的脚本化测试相比&#xff0c;手工探索性测试不遵循固定的测试脚本&#xff0…...

AVL树的理解和实现[C++]

文章目录 AVL树AVL树的规则或原理 AVL树的实现1.节点的定义2.功能和接口等的实现默认构造函数&#xff0c;析构函数拷贝构造函数插入搜索打印函数检查是否为平衡树&#xff0c;检查平衡因子旋转 AVL树 AVL树&#xff0c;全称Adelson-Velsky和Landis树&#xff0c;是一种自平衡…...

云计算遭遇的主要安全威胁

以下是详细说明云计算遭遇的所有主要安全威胁&#xff1a; 1. 数据泄露 描述&#xff1a;数据泄露是指未经授权的情况下访问和获取敏感数据。云计算环境中的数据泄露通常由于不安全的配置、软件漏洞或内部威胁造成。 案例&#xff1a; Capital One数据泄露&#xff1a;2019…...

[MySQL]02 存储引擎与索引,锁机制,SQL优化

Mysql存储引擎 可插拔式存储引擎 索引是在存储引擎底层上实现的 inno DB MySQL默认存储引擎: inno DB高可靠性和高性能的存储引擎 DML操作遵循ACID模型支持事务行级锁,提高并发访问性能支持外键 约束,保证数据完整性和可靠性 MySAM MySAM是MySQL的早期引擎 特点: 不支持事…...

贵州建设厅网站厅长/seo系统培训班

作者&#xff1a;chinaitlab.com 出处&#xff1a;chinaitlab.com 更新时间&#xff1a;2008-08-07 责任编辑&#xff1a;seward一、引言通过浏览器访问数据量大的表时需要进行分页。ASP对数据库记录分页显示可以通过ADO对象集Recordset对象来实现。[more]Recordset具有以下几个…...

阿里云搭建wordpress/苏州百度

JSON 对象中数组可以包含另外一个数组&#xff0c;或者另外一个 JSON 对象&#xff1a; 微信小程序交流群&#xff1a;111733917 | 微信小程序从0基础到就业的课程&#xff1a;https://edu.csdn.net/topic/huangjuhua 实例 myObj { "name":"网站", &quo…...

网页制作怎么收费/南宁百度推广排名优化

场景需求有一篇文章&#xff0c;不在人工干预下&#xff0c;自动提取关键词。基本理论文章的关键词&#xff0c;最初的方法多是使用词语出现的频次&#xff08;Term Frequency&#xff0c;缩写为TF&#xff09;作为衡量的标准&#xff0c;但在实际应用过程中会出现一些无关紧要…...

网站开发报价明细表/点金推广优化公司

作者:何祖彬[RobinHe] Mail:zubin.hegmail.com 始于2008年8月4日 PM Blog: http://blog.csdn.net/zubin006/ WebSite : http://www.wearelinuxer.com/ 版本号:Debian-Postfix-SASL-SPAM- V1.0-20080804, 2008年8月4日首版转载请注明出处&#xff0c;本文也是采用两篇网友的大…...

可以做婚礼视频的网站有哪些/stp营销战略

是的&#xff0c;有很多关于 Kalman 滤波、插值法和折线算法的例子和开源库。 Kalman 滤波: 一个简单的例子&#xff1a; https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python scikit-learn 库中的 Kalman 滤波实现&#xff1a; https://github.com/scikit-lear…...

常州淄博网站优化/网站策划方案

为什么80%的码农都做不了架构师&#xff1f;>>> 检查有关配置&#xff1a;show variables like %sche%; 1、开启配置 set global event_scheduler 1; 2、创建定时任务&#xff0c;每天执行1次(on completion preserve代表永久执行) CREATE EVENT IF NOT EXISTS my_…...