浅学指针(2)数组函数传值调用

系列文章目录

文章目录

  • 系列文章目录
  • 前言
  • 1. 指针的使⽤和传址调⽤
    • 结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实 参。
    • 那么这个时候,就要搬出指针大哥,在main函数中将a和b的地址传递给Swap函数,Swap函数⾥边通过地址间接的操作main函数中的a和b,像是把家(地址)搬到函数中,直接改变家里的东西(a, b的值)。
  • 2 .数组名的理解
    • 所以说:数组名就是数组⾸元素(第⼀个元素)的地址。
  • 3. 使⽤指针访问数组
  • 4 . 一维数组函数传参形本质
    • 接下来进入重点,⾸先从⼀个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把函数传给⼀个函数后,函数内部求数组的元素个数吗?
  • 5. ⼆级指针
    • 总结:2级指针是存放一级指针的地址
  • 6. 指针数组
    • 指针数组是存放指针的数组
    • 但是并非是2维数组,原因是模拟的数组并不连续,而数组在内存上是连续存放的。


前言

1. 指针的使⽤和传址调⽤

学习指针的⽬的是使⽤指针解决问题,那什么问题,⾮指针不可呢?

案例:写⼀个函数,交换两个整型变量的值
代码如下:

#include <stdio.h>
void Swap1(int x, int y)
{
 	int tmp = x;
 	x = y;
 	y = tmp;
}
int main()
{
 	int a = 0;
 	int b = 0;
 	scanf("%d %d", &a, &b);
 	printf("交换前:a=%d b=%d\n", a, b);
 	Swap1(a, b);
 	printf("交换后:a=%d b=%d\n", a, b);
 return 0;
}

输出结果:
在这里插入图片描述
这是为什么呢?
在这里插入图片描述

我们发现在main函数内部,创建了a和b,a的地址是0x00cffdd0,b的地址是0x00cffdc4,在调⽤Swap1函数时,将a和b传递给了Swap1函数,在Swap1函数内部创建了形参x和y接收a和b的值,但是x的地址是0x00cffcec,y的地址是0x00cffcf0,x和y确实接收到了a和b的值,不过x的地址和a的地址不⼀样,y的地址和b的地址不⼀样,相当于x和y是独⽴的空间,那么在Swap1函数内部交换x和y的值,⾃然不会影响a和b,当Swap1函数调⽤结束后回到main函数,a和b的没法交换。Swap1函数在使⽤的时候,是把变量本⾝直接传递给了函数,这种调⽤函数的⽅式我们之前在函数的时候就知道了,这种叫传值调⽤。

结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实
参。

所以Swap是失败的了。

那么这个时候,就要搬出指针大哥,在main函数中将a和b的地址传递给Swap函数,Swap函数⾥边通过地址间接的操作main函数中的a和b,像是把家(地址)搬到函数中,直接改变家里的东西(a, b的值)。

代码展示:

#include<stdio.h>
void Swap2(int*px, int*py)
{
 	int tmp = 0;
 	tmp = *px;
 	*px = *py;
 	*py = tmp;
}
int main()
{
 	int a = 0;
 	int b = 0;
 	scanf("%d %d", &a, &b);
 	printf("交换前:a=%d b=%d\n", a, b);
 	Swap1(&a, &b);
 	printf("交换后:a=%d b=%d\n", a, b);
 return 0;
}

输出结果:
在这里插入图片描述
我们可以看到实现成Swap2的⽅式,顺利完成了任务,这⾥调⽤Swap2函数的时候是将变量的地址传递给了函数,这种函数调⽤⽅式叫:传址调⽤。

2 .数组名的理解

如下代码:

#include <stdio.h>
int main()
{
 	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
 	printf("&arr[0] = %p\n", &arr[0]);
 	printf("arr = %p\n", arr);
 	return 0;
}

输出结果:
在这里插入图片描述

所以说:数组名就是数组⾸元素(第⼀个元素)的地址。

但是有两个例外:

• sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,
单位是字节
• &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素
的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。

还有一点,arr和&arr有啥区别:

#include <stdio.h>
int main()
{
 	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
 	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[0]和&arr[0]+1相差4个字节,arr和arr+1 相差4个字节,是因为&arr[0] 和 arr 都是⾸元素的地址,+1就是跳过⼀个元素。
但是&arr 和 &arr+1相差40个字节,这就是因为&arr是数组的地址+1 操作是跳过整个数组的。到这⾥⼤家应该搞清楚数组名的意义了吧。

3. 使⽤指针访问数组

有了前面知识,我们便可以使用指针访问数组啦!其实数组也相当于指针,如:*(p + 1)= arr[1],扩展
在这里插入图片描述
数组名arr是数组⾸元素的地址,可以赋值给p,其实数组名arr和p在这⾥是等价的。那我们可以使⽤arr[i]可以访问数组的元素,那p[i]是否也可以访问数组呢?`

#include <stdio.h>
int main()
{
 	int arr[10] = {0};
 	//输⼊
 	int i = 0;
 	int sz = sizeof(arr)/sizeof(arr[0]);
 	//输⼊
 	int* p = arr;
 	for(i=0; i<sz; i++){
 		scanf("%d", p+i);
 		//scanf("%d", arr+i);//也可以这样写
 	}
 	//输出
 	for(i=0; i<sz; i++){
 		printf("%d ", p[i]);
 	}
 return 0;
}

在第18⾏的地⽅,将*(p+i)换成p[i]也是能够正常打印的,所以本质上p[i] 是等价于 *(p+i)。

4 . 一维数组函数传参形本质

接下来进入重点,⾸先从⼀个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把函数传给⼀个函数后,函数内部求数组的元素个数吗?

展示如下:

#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) 计算的是⼀个地址的⼤⼩(单位字节)⽽不是数组的⼤⼩(单位字节)。正是因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的。

总结:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式.

5. ⼆级指针

在这里插入图片描述
要理解如下:

int main()
{
	int a = 30;
	int * pa = &a;//取出a的地址 * 表示pa是指针,指针的类型是int类型
	int * * ppa = &p;//ppa前的*表示ppa是指针,指针的类型是int *类型
}

2级指针的解引用
对上面案例分析,像是扒白菜一样,一层一层来,如下展示:
在这里插入图片描述

最终得到结果

总结:2级指针是存放一级指针的地址

6. 指针数组

指针数组是存放指针的数组

在这里插入图片描述
在这里插入图片描述
结合如上知识,那么指针是可以模拟数组的
扩展:指针数组模拟⼆维数组

#include <stdio.h>
int main()
{
 	int arr1[] = {1,2,3,4,5};
 	int arr2[] = {2,3,4,5,6};
 	int arr3[] = {3,4,5,6,7};
 	//数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
 	int* parr[3] = {arr1, arr2, arr3};
 	int i = 0;
 	int j = 0;
 	for(i=0; i<3; i++){
 		for(j=0; j<5; j++){
 			printf("%d ", parr[i][j]);
 		}
 		printf("\n");
 	}
  return 0;
}

图来展示:
在这里插入图片描述

parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型⼀维数组,parr[i][j]就是整型⼀维数组中的元素。

但是并非是2维数组,原因是模拟的数组并不连续,而数组在内存上是连续存放的。

都看到这里了,那就点个赞吧,学习大家

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端 计算机基础篇 ( 二 )

文章目录 websockt及原理ipv4和ipv6的区别线程和进程的区别cdn原理缓存所涉及的http状态码缓存的时候设置 no-store和no-cache和max-age0这几个有什么区别token一般存放在哪儿怎么设置强缓存和协商缓存强缓存&#xff1a;1. 使用 Cache-Control 头字段&#xff1a; 协商缓存&am…

解决:ImportError: cannot import name ‘Sequence‘ from ‘collections‘

解决&#xff1a;ImportError: cannot import name ‘Sequence‘ from ‘collections‘ 背景 在使用之前的代码时&#xff0c;报错&#xff1a; File “G:\research\code\MicroDE_py\plot_bcic_iv_4_ecog_trial.py”, line 262, in from skorch.helper import predefined_spl…

U盘启动制作工具Rufus

U盘启动制作工具Rufus 下载U盘启动制作工具Rufus&#xff0c;进入Rufus官网&#xff1a;http://rufus.ie/en/&#xff0c;打开之后往后滑动&#xff0c;找到download即可点击下载。 需要插入U盘 首先需要插入U盘&#xff0c;如果U盘有重要文件一定要备份&#xff0c;然后右键…

vue+SpringBoot的图片上传

前端VUE的代码实现 直接粘贴过来element-UI的组件实现 <el-uploadclass"avatar-uploader"action"/uploadAvatar" //这个action的值是服务端的路径&#xff0c;其他不用改:show-file-list"false":on-success"handleAvatarSuccess"…

不做机器视觉工程师,转行,转岗的建议与想法

正所谓外行看热闹&#xff0c;内行看门道。提前咨询前辈们&#xff0c;多问问&#xff0c;多看看。要做就做&#xff0c;一定要提前做好防范。 无论你是要转行或者是转岗&#xff0c;看你有没有本钱和试错成本 有些人&#xff0c;家庭好&#xff0c;可以一直去试错和从头再来。…

【python爬虫】scrapy在pycharm 调试

scrapy在pycharm 调试 1、使用scrapy创建一个项目 scrapy startproject tutorial 2、在朋友pycharm中调试scrapy 2.1 通过文件run.py调试 在根目录下新建一个文件run.py&#xff08;与scrapy.cfg文件的同一目录下&#xff09;, debug ‘run’即可 # -*- coding:utf-8 -*- …

MIT_线性代数笔记:列空间和零空间

目录 前言子空间综述列空间 Column space零空间&#xff08;或化零空间&#xff09;Nullspaceb 值的影响 Other values of b 前言 本节继续研究子空间&#xff0c;特别是矩阵的列空间&#xff08;column space&#xff09;和零空间&#xff08;nullspace&#xff09;。 子空间…

牛客 HJ106 字符逆序 golang实现

牛客题目算法连接 题目 golang 实现 package mainimport ("fmt""bufio""os" )func main() {str, _ : bufio.NewReader(os.Stdin).ReadString(\n)if len(str) 0 {return } else {newstr:""strLen:len(str)-1for i:strLen;i>0;i-…

数据结构与算法【B树】的Java实现+图解

目录 B树 特性 实现 节点准备 大体框架 实现分裂 实现新增 实现删除 完整代码 B树 也是一种自平衡的树形数据结构&#xff0c;主要用于管理磁盘上的数据管理&#xff08;减少磁盘IO次数&#xff09;。而之前说的AVL树与红黑树适合用于内存数据管理。存储一个100w的数…

4.常见面试题--操作系统

特点&#xff1a;并发性、共享性、虚拟性、异步性。 Windows 和 Linux 内核差异 对于内核的架构⼀般有这三种类型&#xff1a; ● 宏内核&#xff0c;包含多个模块&#xff0c;整个内核像⼀个完整的程序&#xff1b; ● 微内核&#xff0c;有⼀个最⼩版本的内核&#xff0…

docker国内镜像加速

创建或修改 /etc/docker/daemon.json 文件&#xff0c;修改为如下形式 {"registry-mirrors": ["https://registry.docker-cn.com","http://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn"] } Docker中国区官方镜像htt…

【广州华锐互动】VR线上课件制作软件满足数字化教学需求

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术在教学领域的应用逐渐成为趋势。其中&#xff0c;广州华锐互动开发的VR线上课件制作软件更是备受关注。这种工具为教师提供了便捷的制作VR课件的手段&#xff0c;使得VR教学成为可能&#xff0c;极大地丰…

python cv2.imread()和Image.open()的区别和联系

文章目录 1. cv2.imread()1.1 cv2.imread参数说明1.2 注意事项 2. Image.open()3. cv2.imread()与Image.open()相互转化3.1 cv2.imread()转成Image.open()&#xff1a;Image.fromarray()3.2 Image.open()转成cv2.imread()&#xff1a;np.array() 1. cv2.imread() cv2.imread()…

MyBatisPlus总结

MyBatis-Plus时Mybatis的Best Partner MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 特性 无侵入损耗小强大的 CR…

Linux(Centos)上使用crontab实现定时任务(定时执行脚本)

场景 Windows中通过bat定时执行命令和mysqldump实现数据库备份&#xff1a; Windows中通过bat定时执行命令和mysqldump实现数据库备份_mysqldump bat-CSDN博客 上面讲windows中使用bat实现定时任务的方式&#xff0c;如果是在linux上可以通过crontab实现。 cron是服务名称。…

Navicat 技术指引 | 适用于 GaussDB 的查询编辑器

Navicat Premium&#xff08;16.2.8 Windows版或以上&#xff09; 已支持对 GaussDB 主备版的管理和开发功能。它不仅具备轻松、便捷的可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结构同步、协同合作、数据迁移等&#xff09;&#xff0c;这…

【开源】基于Vue.js的海南旅游景点推荐系统的设计和实现

项目编号&#xff1a; S 023 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S023&#xff0c;文末获取源码。} 项目编号&#xff1a;S023&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四…

海报设计必备:揭秘5款炙手可热的设计工具

1.即时设计&#xff1a;能实现在线协作的海报设计软件 即时设计作为 2020 年上线的国产设计工具&#xff0c;目前已经有了超百万的注册用户&#xff0c;获得了广大设计师的一致好评。与其他传统海报设计软件相比&#xff0c;即时设计具有这几个优点&#xff1a;一是所有功能都…

【DevOps】Git 图文详解(九):工作中的 Git 实践

本系列包含&#xff1a; Git 图文详解&#xff08;一&#xff09;&#xff1a;简介及基础概念Git 图文详解&#xff08;二&#xff09;&#xff1a;Git 安装及配置Git 图文详解&#xff08;三&#xff09;&#xff1a;常用的 Git GUIGit 图文详解&#xff08;四&#xff09;&a…

【算法】缓存淘汰算法

目录 1.概述2.代码实现2.1.FIFO2.2.LRU2.3.LFU2.4.Clock2.5.Random 3.应用 1.概述 缓存淘汰策略是指在缓存容量有限的情况下&#xff0c;当缓存空间不足时决定哪些缓存项应当被移除的策略。缓存淘汰策略的目标是尽可能地保持缓存命中率高&#xff0c;同时合理地利用有限的缓存…