指针进阶之数组参数和指针参数

news2024/11/25 22:44:15

文章目录

  • 一、回顾
    • 1.字符指针
    • 2.指针数组和数组指针
      • (1)指针数组
      • (2)数组指针
  • 二、数组参数
    • 1.一维数组传参
      • (1)整型数组
      • (2)指针数组
      • (3)总结
    • 2.二维数组传参
      • (1)用数组接收
      • (2)用指针接收
  • 三、指针参数
    • 1.一级指针传参
      • (1)写法
      • (2)案例一
      • (3)案例二
      • (4)总结
    • 2.二级指针传参
      • (1)写法
      • (2)案例

一、回顾

1.字符指针

详细内容移步:指针进阶之字符指针

①字符

 char ch = 'w';	//字符变量ch里面存放一个w
 char* p = &ch;	//定义一个字符指针p,将ch的地址赋值给p,p是字符指针

②字符串

const char* p2 = "abcdef";

这里是将整个字符串存进p2里面了吗?不是的。p2是一个指针变量,4个字节,根本存不下“abcdef”七个字节。

当我们把一个字符串赋给p2时,其实是把这个字符串首元素a的地址交给了p2。能找到a,就能找到整个字符串。

“abcdef”是常量字符串,内容不允许被修改。所以最合理应加上“const”。

const去修饰指针变量,const放在*左边,修饰的是*p2,也就是p2指向的内容不能被修改。

2.指针数组和数组指针

详细内容移步:指针进阶之指针数组和数组指针

(1)指针数组

本质上是数组,用来存放指针。

比如:

 int* arr[10];

arr首先与[]结合,是数组,有10个元素。

除去数组名(arr)和元素个数(10),剩下的是数组的元素类型,即:int*,每个元素是int*类型,即指针类型。

又比如:

 char* ch[5];

ch数组有5个元素,每个元素是char*类型–>每个元素是字符指针类型。

(2)数组指针

本质上是指针,用来存放数组。

以前学过:

 int* p3 --> p3为整型指针 (p3指向的元素是整型的) --> 指向整形的指针
 char* p4 --> p4为字符指针(p4指向的元素是字符类型的)--> 指向字符的指针

那么数组指针 --> 指向数组的指针

比如现在有一个数组arr2,将arr2的地址取出来:

 int arr2[5];//数组
 &arr2;//取出数组的地址

再将数组arr2的地址(&arr2)存起来:

 int(*pa)[5] = &arr2;

pa先和*结合,是一个指针;指向的是一个数组,数组里面有5个元素,每个元素是int类型。

pa就是一个数组指针。

pa是什么类型?去掉pa,剩下的就是它的类型“int (* )[5]”,即指向数组的指针类型。

二、数组参数

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

1.一维数组传参

(1)整型数组

现在有一个存放整型的一维数组arr:

int main() {   
    int arr[10] = { 0 };//arr是一维数组,有10个元素,每个元素为整型   
	test(arr);  //将arr传参,传给test函数
	return 0; 
} 

要设计函数test,有以下几种方式,看一下可不可行:

①用整型数组接收

传递过来的是arr,是一个整型数组,那么就可以拿一个整型数组来接收。

void test(int arr[]) {
    //这种写法OK     
}  

这个整型数组,写上10个元素,也是可以的。

如下:


void test(int arr[10]) {
    //这种写法Ok     
} 

②用指针接收

数组名arr是首元素地址,那么就可以拿一个指针来接收。

数组arr首元素是int类型,所以指针是int*类型。

可以用整型指针来接收。如下:

void test(int* arr) {
    //传过来的是arr,数组名是首元素地址,原来的每个元素都是Int类型的,这种写法OK    
}  

🍰总结

当一维数组进行传参的时候,参数部分可以写成数组,数组大小可以省略也可以不省略(写错也无所谓);也可以写成指针

(2)指针数组

现在有一个存放指针的整型数组arr2:

int main() {   
	int* arr2[20] = { 0 };//arr2是指针数组,数组有20个元素,每个元素是int*类型  
	test(arr2);  
	return 0; 
} 

要设计函数test2,有以下几种方式,看一下可不可行:

①用指针数组接收

void test2(int* arr[20]) {
    //传来的是一个数组,20个元素,每个元素是int*,这种写法OK,想省略20也没问题           
}  

arr2是一个整型指针数组,有20个元素,每个元素是int*类型。

既然传上去的是数组,就可以用数组(20个元素,每个元素是int*类型)来接收。

②用指针接收

void test2(int** arr) {
    //传来的arr是数组名,即首元素地址,每个元素是int*类型,那参数部分可以写成指针。   
} 

数组名arr2也是首元素地址,那么参数部分可以用指针来接收。

❓ 那这个指针如何写呢?

arr2数组的每个元素是int*类型int*是一级指针。

arr2数组名表示首元素地址,首元素是一个int*类型,那么arr2表示的是一级指针的地址。

一级指针的地址传递给函数,当然要用二级指针来接收啦。

所以可以写成:int** arr

(3)总结

参数部分可以写成数组,数组大小可以省略,写错也没事(尽量别写错)。

也可以写成指针的形式,写成指针的时候,应该找一个合理的指针类型。

比如arr传递的是一个整型数组的数组名,那么函数的参数部分就要拿整型指针来接收。数组名表示首元素地址,即整型的地址,当然要放到整型指针里面啦。

arr2是指针数组,数组名是一级指针的地址,函数的参数就要用二级指针来接收。

2.二维数组传参

现在有一个二维数组:

int main() {   
    int arr[3][5] = { 0 };  
 	test(arr);//二维数组传参  
 	return 0;  
}

要设计函数test,有以下几种方式,看一下可不可行:

(1)用数组接收

void test(int arr[3][5]) { 
	//可以   
    //与下面传上来的数组保持一致,是最中规中矩的写法  
}  

数组传参,那么函数的参数部分可以写为数组。


同样,用数组来接收,可以省略行的部分,如下:

void test(int arr[][5]) { 
    //可以   
	//二维数组传参,函数形参的设计只能省略第一个[]的数字。 
}  

但是下面的不可以:

void test(int arr[3][]) { 
    //不行   //行可以省略,列不能省略  
}  

因为对一个二维数组,可以不知道有多少行,但是必须知道有多少列(一行有多少个元素)。

数组行可以省略,列不能省略!

(2)用指针接收

传上去的数组名是首元素地址,那么就可以用指针来接收。

<1> 第一种写法

arr是二维数组数组名,那么这样写行不行呢?

void test(int* arr) { 
    //整型指针,不行    
}  

报警告:int*int[3][5]间接级别不同。

传上来的是一个二维数组arr,二维数组的数组名表示的是首元素地址,首元素是第一行(可以看成一个一维数组)。

那么二维数组数组名表示的是第一个一维数组的地址。

如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r70IBHAT-1672930345362)(D:\Typora图片\image-20230105105620189.png)]

传上来的是一个一维数组的地址,不能存放到整型指针里面去。整型指针是用来存放整型变量的地址的。

所以上面写法不行!


<2> 第二种写法

那究竟该如何书写呢?

这样行不行?

void test(int** arr) { 
    //二级指针,不行   
    //参数部分写的是二级指针,存放的是一级指针变量的地址   
    //刚才传来的是一个一维数组的地址!不能放到二级指针里面去。  
}  

上面说了,数组名arr是首元素的地址,是第一行的地址,第一行是一个一维数组。

那么arr就是第一行的地址,即一维数组的地址。

一维数组的地址怎么能放到二级指针里面去?

二级指针是用来存放一级指针变量的地址的。

*数组名是第一行的地址,**数组名是首元素。

*形参得到一个int*指针(已经不是一行的信息了),**形参直接跑到指针指向的不知道哪里去了。

所以这种写法也不行!


<3> 第三种写法

这种写法也不正确:

void test(int* arr[5]) { 
    //指针数组,不行   
    //arr是数组,5个元素,每个元素是int*  
} 

指针数组里面存的是指针,而不能存放地址。

这种写法也不行!


<4> 第四种写法

这种写法才是正确的:

void test(int(*arr)[5]) { 
    //数组指针,可以   //传过去的是第一行的地址,第一行是一维数组(5个整型)。 
    //arr先和*结合,是指针,指向的数组(5个元素,每个元素是int类型)。 
}

刚才说了,arr就是数组第一行的地址,即一维数组的地址。

第一行,是由5个整型构成的一维数组。

首先确定下来,是用指针接收,那么就先用小括号括起来,即:(*arr)

然后再写这个指针类型,这个指针接收的是一个一维数组的地址,数组里面有5个int类型的元素。

那么指针类型就可以用int [5]表示。

即:int (*arr)[5],这个指针有能力指向二维数组的首元素(第一行)。

三、指针参数

1.一级指针传参

(1)写法

直接来看一段代码:

int main() {
   int arr[10] = { 1,2,3,4,5,6,7,8,9 };	//数组arr有10个元素,每个元素是int类型
   int* p = arr;	//数组名arr是首元素地址,我们把它放到指针里面去,p是指针
   int sz = sizeof(arr) / sizeof(arr[0]);	//sz是元素个数
   //一级指针p,传给函数,那么函数应该用指针来接收
   print(p, sz);
   return 0;
}

一级指针p,传给函数,那么函数应该用指针(int* p)来接收。

那么函数的参数部分就很好写:

 void print(int* p, int sz) {//p为指针,sz为个数
  	int i = 0;
 	for (i = 0; i < sz; i++) {
  		printf("%d\n", *(p + i));
  	}
}

📂 思考:当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

(2)案例一

参数部分是一级指针,那传上去的可能是什么呢?

void test1(int* p){
    
}
// test1函数能接收什么参数?

①既然参数部分是int*指针类型,那么一定可以接收地址。

那么是可以接收地址的,如下:

 int a = 10;
 test1(&a);//传地址过去

②同样,也可以直接传递一个指针过去,如下:

 int* p1 = &a;
 test1(p1);//p1本身就是指针

(3)案例二

字符指针也是类似。

比如:

 void test2(char* pa){
     
 }
// test2函数能接收什么参数?

①直接传一个字符的地址

char ch = 'w';
test2(&ch);//传字符变量的地址

②还可以直接传字符指针的地址

 char* pc = &pca;
 test2(pc);//pc本身就是指针

(4)总结

🍰总结

如果函数的参数部分,写的是一级指针。那么可以传一个变量的地址上去,也可以传一个存放地址的一级指针变量

2.二级指针传参

(1)写法

直接看一段代码:

int main() {
  	int n = 10;	//整型变量n
  	int* p = &n;	//p为一级指针,将n的地址存放到p里面
 	int** pp = &p;	//pp为二级指针,将p指针的地址存放进pp里面
  	test(pp);	//传一个二级指针变量上去
 	test(&p);
   	return 0;
}

test(&p);传了一个一级指针p的地址上去,需要拿二级指针(int** ptr)来接收。

test(pp);传了一个**二级指针变量(pp)**上去,自然要拿一个二级指针(int** ptr)来接收。

如下:

void test(int** ptr) {
 	 printf("num=%d\n", **ptr);
}

二级指针进行传参的时候,参数部分可以直接设计为二级指针。

📂 **思考:**当一个函数的参数部分为二级指针的时候,函数能接收什么参数?

(2)案例

上面说明了,参数部分是二级指针(int** p)的时候。

void test(int** p) {
  
}

传上去的可能是:

一级指针变量的地址

int* ptr;
test(&ptr);	//一级指针变量的地址传过去

二级指针变量本身

int** pp = &ptr;
test(pp);	//二级指针传过去

一级指针数组

除了上面两种,还有其他可能的。

既然函数参数部分是二级指针,无非就是接收一级指针变量的地址或者二级指针本身。

如果现在有一个一级指针数组arr,那么此时的数组名arr是首元素地址。

首元素是int*类型,那么int*元素的地址,需要用二级指针变量来接收。如下:

int* arr[10];	//一级指针数组arr,10个元素,每个元素类型是int*
test(arr);	//数组名是首元素地址,即int的地址

所以,传一个存放一级指针的数组的数组名(指针数组),也是可以的。


写在最后:
这一节看着很简单,不要轻视,认真对待。
整理笔记、码字不容易,多多支持~
拜拜~

请添加图片描述

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

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

相关文章

基于Python tensorflow2.3实现的水果识别系统源码+模型+数据集,卷积神经网络的入门案例

水果识别-基于tensorflow2.3实现 水果识别是卷积神经网络的入门案例&#xff0c;这里我将模型的训练、测试、保存以及使用整合在了一起&#xff0c;至于原理部分&#xff0c;大家可以参考知乎或者B站上的回答&#xff0c;在这里我就不赘述了 完整代码下载地址&#xff1a;基于…

计算机网络实验---验证性实验

实验一/ipconfig 实作一 实作二 实验二/ping 实作一 实作二 实验三/tracert 实作一 实作二 实验四/ARP 实作一 实作二 实作二 实验五/DHCP 实作一 实验六/netstat 实作一 实作二 实验七/DNS 实作一 实作二 实作二 实验八/cache 实作一 实作二 总结 实验一/ipconfig 实…

[Leetcode] 二叉树的遍历

转载自&#xff08;有删减和少量改动&#xff09; 图解二叉树的四种遍历 https://leetcode.cn/problems/binary-tree-preorder-traversal/solution/tu-jie-er-cha-shu-de-si-chong-bian-li-by-z1m/1. 相关题目144.二叉树的前序遍历 https://leetcode.cn/problems/binary-tree-p…

【SpringMVC 入门教程】

SpringMVC_day02 &#x1f308;博客主页&#xff1a;屠一乐的博客 &#x1f4c5; 发文时间&#xff1a;2023.1.5 &#x1f388; 一定存在只有你才能做成的事 &#x1f339; 博主水平有限&#xff0c;如有错误&#xff0c;欢迎指正 欢迎各位&#x1f44d;收藏&#x1f48e;评论✉…

MacBookPro安装mysql遇到的几个问题

用Mac的好处是不用开关机&#xff0c;无弹窗无广告&#xff0c;坏处是在安装某些第三方的软件时&#xff0c;总是和视频教程上的winows版不一致&#xff0c;需要自己上网找资料尝试怎么安装。今天学python&#xff0c;需要安装mysql&#xff0c;幸好网上有一些文章&#xff0c;…

Vulnhub靶机:MISDIRECTION_ 1

目录介绍信息收集主机发现主机信息探测网站探测反弹shell方式1&#xff1a;使用nc方式2&#xff1a;使用bash方式3&#xff1a;使用MSF提权sudo提权passwd提权docker提权参考介绍 系列&#xff1a;Misdirection&#xff08;此系列共1台&#xff09; 发布日期&#xff1a;2019 …

【ClickHouse】从Mysql迁移到ClickHouse大全

从关系型的数据库(Mysql)升级到列式管理的联机分析型数据库(ClickHouse)&#xff0c;这不亚于是小米加步枪升级为加特林机关枪的性能提升了&#xff0c;查询能力等确实是大大的提升了&#xff0c;这出现了一个问题我们之前存储在Mysql里的历史数据怎么往ClickHouse里面迁移呢&a…

访问者模式Visitor

1.意图&#xff1a;表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的操作。 2.结构 Visitor&#xff08;访问者&#xff09;为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请…

本地机器 Google Colab 通过 SSH 连接远程服务器

1. 情景描述 我自己笔记本配置太垃圾&#xff0c;想要用学校的深度学习服务器在Colab上跑程序。 2. 环境描述 远程服务器 (Ubuntu)&#xff1a; 用pip安装 jupyter notebook 以及 jupyter_http_over_ws 拓展包 (前提有python环境和pip) pip install notebookpip install j…

Android设计模式详解之外观模式

前言 外观模式也称门面模式&#xff0c;在开发过程中的运用频率非常高&#xff1b; 定义&#xff1a;要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行&#xff1b;门面模式提供一个高层次的接口&#xff0c;使得子系统更易于使用&#xff1b; 使用场景&#…

6.3 Docker

目录 6.3.1 Docker概述 6.3.1.1 什么是Docker 6.3.1.2 Docker组成 6.3.2 Docker的安装 6.3.2.1 下载Docker依赖的环境 6.3.2.2 指定Docker镜像源 6.3.2.3 安装Docker 6.3.2.4 启动Docker并测试 6.3.3 Docker的中央仓库 6.3.4 Docker操作 6.3.4.1 镜像操作 6.3.4.…

从url获取参数并转为对象

const getParameters URL > JSON.parse({"${decodeURI(URL.split("?")[1]).replace(/"/g, \\").replace(/&/g, ",").replace(//g, ":")}"})getParameters("https://www.google.com.hk/search?qjsmd&neww…

【深度学习】李宏毅2021/2022春深度学习课程笔记 - Self-supervised Learning(自监督式学习)

文章目录一、芝麻街与进击的巨人二、Self-supervised Learning三、BERT3.1 Masking Input3.2 Next Sentence Prediction3.3 GLUE 任务集3.4 How to use BERT3.4.1 Case13.4.2 Case23.4.3 Case33.4.4 Case43.5 Training BERT is challenging!3.6 Pre-Training a Seq2Seq Model3.…

ERP是什么意思?

“ERP到底是一个怎么样的存在&#xff1f;为何有那么多的方面&#xff1f;如何学习&#xff1f;” 本文从ERP起源讲起&#xff0c;结合制造业离散制造与流程制造的ERP系统区别&#xff0c;详解ERP概念。 文章有点长&#xff0c;但如果你耐心看完&#xff0c;相信你会对ERP有一…

elasticsearch 基本语法(常见的RESTFUL API)

一 . ES的基本语法 文章目录一 . ES的基本语法1.Query String 语法2.Query DSL 语法3. Full-text queries 全文检索4. Phrase search 短语搜索5.Query and filter 查询和过滤6. Compound queries 查询7.HighLight search(高亮显示)测试数据内容&#xff1a;PUT /product/_doc/1…

科研试剂 Dextran-DBCO;葡聚糖-二苯并环辛烯;生物可降解高分子聚合物

DBCO修饰的葡聚糖聚 Dextran-DBCO 葡聚糖-二苯并环辛烯 名称&#xff1a;DBCO修饰葡聚糖 英文名称&#xff1a;Dextran-DBCO 外观状态&#xff1a;白色粉末 溶剂&#xff1a;DMSO等常规有机溶剂。 性状&#xff1a;基于不同的分子量&#xff0c;呈白色/类白色固体粉末&…

python爬虫(一)

一、理论 &#xff08;1&#xff09;URL管理器&#xff1a;网页之间的链接很复杂&#xff0c;a指向b&#xff0c;b指向a&#xff0c;如果不对其进行管理则可能导致重复爬取、循环爬取&#xff0c;因此单独用该模块进行管理。URL管理器有两个功能&#xff0c;分别是URL队列管理&…

神策营销云平台化应用实践

营销云是一个业务系统&#xff0c;需要贴合客户的实际业务场景&#xff0c;以平台化 分层设计撬动场景发挥价值主张。本文将详细介绍神策营销云在数字化转型浪潮中的沉淀。点击文末“阅读原文”立即观看完整版演讲回放。一、神策营销云产品理念“营销云是一个业务系统”&#…

规范有效的需求变更管理,分7步走。

1、建立需求基线 需要提前建立需求基线&#xff0c;需求基线是需求变更的依据&#xff0c;并需制定双方皆认可的需求变更流程。 需对用户需求进行明确分析&#xff0c;颗粒度越小越好。基准文件定位范围越详细&#xff0c;双方对需求越清晰&#xff0c;用户交流顺畅&#xff0c…

Go语言context包源码剖析

context包的作用 context包是在go1.7版本中引入到标准库中的 context可以用来在goroutine之间传递上下文信息&#xff0c;相同的context可以传递给运行在不同goroutine中的函数&#xff0c;上下文对于多个goroutine同时使用是安全的&#xff0c;context包定义了上下文类型&am…