用数组名作函数参数的详解,以及形参实参采用数组名,形参实参采用指针变量的几种情况解析

news2024/11/15 8:00:36

关于地址,指针,指针变量可以参考我的这篇文章:

地址,指针,指针变量是什么?他们的区别?符号(*)在不同位置的解释?_juechen333的博客-CSDN博客icon-default.png?t=N176https://blog.csdn.net/qq_57342311/article/details/129225045

目录

一、引入

1.1实例

1.2解释

1.3变量名和数组名作函数参数的比较

二、程序举例

2.1引入

三、总结

3.1归纳

3.2用指针变量作实参、形参举例

3.3用指针变量作实参,数组名作形参举例


一、引入

1.1实例

#include<stdio.h>
int main()
{
	void fun(int arr[], int n);		//对fun函数进行声明
	int array[10];		//定义array数组
	...					//一系列操作
	fun(array, 10);		//用数组名作函数参数
	...					//一系列操作
	return 0;
}

void fun(int arr[], int n)	//定义fun函数
{
	...		//一系列操作
}

array 是实参数组名,arr 为形参数组名,当用数组名作参数时,如果形参数组中各元素的值发生变化,实参数组元素的值随之变化。这究竟为什么呢?请继续往下看。

1.2解释

(1)先看数组元素作实参时的情况

如果已定义一个函数

void swap(int x, int y);

假设函数的作用是将两个形参( x , y )的值交换,进行函数调用

swap (a[1],a[2]);

用数组元素 a[1] 和 a[2] 作实参的情况,与用变量作实参时一样,是 “值传递” 方式,将 a[1] 和 a[2] 的值单向传递给 x 和 y 。当 x 和 y 的值改变时,a[1] 和 a[2] 的值并不改变。

(2)再看用数组名作函数参数的情况

实参数组名代表该数组首元素的地址,而形参是用来接收从实参传递过来的数组首元素地址的。因此,形参应该是一个指针变量(只有指针变量才能存放地址)。实际上,C编译都是将形参数组名作为指针变量来处理的。例如:

fun(int arr[],int n);

但在程序编译时是将 arr 按指针变量处理的,相当于将函数 fun 的首部写成

fun(int* arr,int n);

以上两种写法是等价的。在该函数被调用时,系统会在 fun 函数中建立一个指针变量 arr,用来存放从主调函数传递过来的实参数组首元素的地址。如果在fun函数中用运算符 sizeof 测定 arr 所占的字节数,可以发现 sizeof(arr) 的值为 4 (用 VisualC++ 时)。这就证明了系统是把 arr 作为指针变量来处理的(指针变量在 Visual C++ 中占4个字节)。

当 arr 接收了实参数组的首元素地址后,arr 就指向实参数组首元素,也就是指向 array[0]。因此,*arr 就是 array[0]。arr+1 指向 array[1],arr+ 2 指向 array[2],arr+3 指向 array[3]。也就是说,*(arr+1),*(arr+2), *(arr+3) 分别是 array[1],array[2],array[3]。

根据前面介绍过的知识,*(arr+i) 和 arr[i] 是无条件等价的。

因此,在调用函数期间,arr[0] 和 *arr 以及 array[0] 都代表数组 array 序号为 0 的元素,依此类推,arr[3],*(arr+ 3),array[3] 都代表 array 数组序号为 3 的元素。

1.3变量名和数组名作函数参数的比较

实参类型要求的形参类型传递的信息能否改变实参的值
变量名变量名变量的值不能
数组名数组名或指针变量实参数组首元素的地址

说明: C 语言调用函数时虚实结合的方法都是采用 “值传递” 方式,当用变量名作为函数参数时传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组首元素地址,因此传递的值是地址,所以要求形参为指针变量。

在用数组名作为函数实参时,既然实际上相应的形参是指针变量,为什么还允许使用形参数组的形式呢?这是因为在 C 语言中用下标法和指针法都可以访问一个数组(如果有一个数组 a,则 a[i] 和 *(a+i) 无条件等价),用下标法表示比较直观,便于理解。因此许多人愿意用数组名作形参,以便与实参数组对应。从应用的角度看,用户可以认为有一个形参数组,它从实参数组那里得到起始地址,因此形参数组与实参数组共占同一段内存单元,在调用函数期间,如果改变了形参数组的值,也就是改变了实参数组的值。在主调函数中就可以利用这些已改变的值。

注意:实参数组名代表一个固定的地址,或者说是指针常量,但形参数组名并不是一个固定的地址,而是按指针变量处理。

二、程序举例

2.1引入

将数组 a 中 n 个整数按相反顺序存放,实参用数组名 a,形参可用数组名,也可用指针变量名。

(1)形参用数组名

#include<stdio.h>
int main()
{
	void inv(int x[], int n);	//函数声明
	int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (int i = 0; i < 10; i++)	//输出未交换时数组各元素的值
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	inv(a, 10);		//调用函数
	for (int i = 0; i < 10; i++)	//输出交换后数组各元素的值
	{
		printf("%d ", a[i]);
	}
}

void inv(int x[], int n)	//形参x是数组名
{
	int temp;
	for (int i = 0; i < (n - 1) / 2; i++)
	{
		int j = n - 1 - i;
		temp = x[i];
		x[i] = x[j];
		x[j] = temp;
	}
}

运行结果:

分析:

程序分析:在main函数中定义整型数组 a,并赋予初值。函数 inv 的形参数组名为 x。在定义 inv 函数时,可以不指定形参数组 x 的大小(元素的个数)。因为形参数组名实际上是一个指针变量,并不是真正地开辟一个数组空间(定义实参数组时必须指定数组大小,因为要开辟相应的存储空间)。inv 函数的形参 n 用来接收需要处理的元素的个数。在 main 函数中有函数调用语句 “inv(a,10);",表示要求对 a 数组的 10 个元素实行题目要求的颠倒排列。如果改为 “inv(a,5);",则表示要求将 a 数组的前 5 个元素实行颠倒排列,此时,函数 inv 只处理5个数组元素。

(2)形参用指针变量名

#include<stdio.h>
int main()
{
	void inv(int* x, int n);	//函数声明
	int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (int i = 0; i < 10; i++)	//输出未交换时数组各元素的值
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	inv(a, 10);		//调用函数
	for (int i = 0; i < 10; i++)	//输出交换后数组各元素的值
	{
		printf("%d ", a[i]);
	}
}

void inv(int* x, int n)	//形参x是指针变量
{
	int temp;
	int* i = x;
	int* j = x + n - 1;
	for (; i < x + (n - 1) / 2; i++, j--)
	{
		temp = *i;
		*i = *j;
		*j = temp;
	}
}

运行结果:

三、总结

3.1归纳

如果有一个实参数组,要想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下 4 种情况。

(1)实参和形参都用数组名

int main()
{
	void f(int x[], int n);
	int a[10];
	...
	f(a, 10);	//实参用数组名
	...
}

void f(int x[], int n)	//形参用数组名
{
	...
}

(2)实参用数组名,形参用指针变量

int main()
{
	void f(int* x, int n);
	int a[10];
	...
	f(a, 10);	//实参用数组名
	...
}

void f(int* x, int n)	//形参用指针变量
{
	...
}

(3)实参和形参都用指针变量

int main()
{
	void f(int* x, int n);
	int a[10];
	int* p = a;
	...
	f(p, 10);	//实参用指针变量
	...
}

void f(int* x, int n)	//形参用指针变量
{
	...
}

(4)实参用指针变量,形参用数组名

int main()
{
	void f(int x[], int n);
	int a[10];
	int* p = a;
	...
	f(p, 10);	//实参用指针变量
	...
}

void f(int x[], int n)	//形参用数组名
{
	...
}

3.2用指针变量作实参、形参举例

改写(二)中的实例

#include<stdio.h>
int main()
{
	void inv(int* x, int n);	//函数声明
	int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = a;
	for (int i = 0; i < 10; i++)	//输出未交换时数组各元素的值
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	inv(p, 10);		//调用函数
	for (int i = 0; i < 10; i++)	//输出交换后数组各元素的值
	{
		printf("%d ", a[i]);
	}
}

void inv(int* x, int n)	//形参x是指针变量
{
	int temp;
	int* i = x;
	int* j = x + n - 1;
	for (; i < x + (n - 1) / 2; i++, j--)
	{
		temp = *i;
		*i = *j;
		*j = temp;
	}
}

运行结果:

3.3用指针变量作实参,数组名作形参举例

对数组 a[10] 由大到小进行排序,采用选择排序的算法

#include<stdio.h>
int main()
{
	void sort(int x[], int n);	//函数声明
	int a[10] = { 1,3,5,7,9,2,4,6,8,10 };
	int* p = a;
	for (int i = 0; i < 10; i++)	//输出未交换时数组各元素的值
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	sort(p, 10);		//调用函数
	for (int i = 0; i < 10; i++)	//输出交换后数组各元素的值
	{
		printf("%d ", a[i]);
	}
}

void sort(int x[], int n)
{
	for (int i = 0; i < n - 1; i++)		//i的取值范围[0,n-1)
	{
		int max_idx = i;	//记录最大数值所在位置
		for (int j = i + 1; j < n; j++)	//j的取值范围[1,n)
		{
			if (x[j] > x[max_idx]) { max_idx = j; }	//更新最大值所在位置
		}
		if (max_idx != i)	//进行交换
		{
			int temp;
			temp = x[i];
			x[i] = x[max_idx];
			x[max_idx] = temp;
		}
	}
}

运行结果:

上面 sort 函数中是用数组名作为形参,也可以用指针变量作为形参

void sort(int* x, int n)
{
	for (int i = 0; i < n - 1; i++)		//i的取值范围[0,n-1)
	{
		int max_idx = i;	//记录最大数值所在位置
		for (int j = i + 1; j < n; j++)	//j的取值范围[1,n)
		{
			if (*(x + j) > *(x + max_idx)) { max_idx = j; }	//更新最大值所在位置
		}
		if (max_idx != i)	//进行交换
		{
			int temp;
			temp = *(x + i);
			*(x + i) = *(x + max_idx);
			*(x + max_idx) = temp;
		}
	}
}

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

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

相关文章

Kali的安装与配置

虚拟机安装kali Kali下载 官网下载地址 注&#xff1a;下载VMware版本 百度网盘 提取码&#xff1a;Chen 创建虚拟机 将下载的压缩包放到合适的位置解压 双击运行虚拟机 登录 默认的账号密码都为kali 基本配置 修改root账户密码 打开命令行输入 sudo su root 输入kali 输…

【机器学习】验证集loss震荡(loss的其他问题)

训练过程中发现&#xff0c;train loss一直下降&#xff0c;train acc一直上升&#xff1b;但是val loss、val acc却一直震荡。loss一会上一会下&#xff0c;但是总体趋势是向下的。 “loss震荡但验证集准确率总体下降” 如何解决&#xff1f; 测试集准确率这样震荡是正常的吗…

python2.7/3.8版本安装教程

Wiondos-Python环境安装 Python2.7 下载地址 官网 速度比较慢 百度网盘 提取码:Chen 安装Python2.7 直接next 选择安装目录 注意这一步将最后一项勾选 安装完成 cmd中输入python 检查pip是否安装 cmd中输入pip --version Python3.8 下载地址 官网 速度比较慢 百度网…

蓝桥杯C/C++程序设计 往届真题汇总(进阶篇)

文章目录1. 最短路2. 数字三角形3. 递增序列4. 杨辉三角形5. 跳跃6. 路径7. 迷宫8. 装饰珠9. 明码10. 字串分值11. 作物杂交12. 承压计算13. 全球变暖14. 直线15. 平面切分1. 最短路 题目描述&#xff1a; 如下图所示&#xff0c;G是一个无向图&#xff0c;其中蓝色边的长度是…

线程池执行父子任务,导致线程死锁

前言&#xff0c; 一次线程池的不当使用&#xff0c;导致了现场出现了线程死锁&#xff0c;接口一直不返回。而且由于这是一个公共的线程池&#xff0c;其他使用了次线程池的业务也一直阻塞&#xff0c;系统出现了OOM&#xff0c;不过是幸好是线程同事测试出来的&#xff0c;没…

RPC通信原理解析

一、什么是RPC框架&#xff1f; RPC&#xff0c;全称为Remote Procedure Call&#xff0c;即远程过程调用&#xff0c;是一种计算机通信协议。 比如现在有两台机器&#xff1a;A机器和B机器&#xff0c;并且分别部署了应用A和应用B。假设此时位于A机器上的A应用想要调用位于B机…

第十一届蓝桥杯大赛青少组国赛Python真题2

第十一届蓝桥杯大赛青少组Python 真题 第二题 提示信息&#xff1a; 杨辉三角形&#xff0c;是二项式系数在三角形中的一种几何排列。中国南宋数学家杨辉在 1261 年所著的《详 解九章算法》一书有明确记载。欧洲数学家帕斯卡在 1654 年发现这一规律&#xff0c;所以又叫做帕斯卡…

Rabbit快速入门

入门案例 需求&#xff1a;使用简单模式完成消息传递 步骤&#xff1a; 创建工程&#xff08;生成者、消费者&#xff09; 分别添加依赖 编写生产者发送消息 编写消费者接收消息 3.1.2. 添加依赖 往heima-rabbitmq的pom.xml文件中添加如下依赖&#xff1a; <dependenc…

RabbitMQ的安装和配置

注意: 请使用资料里提供的CentOS-7-x86_64-DVD-1810.iso 安装虚拟机. 1. 安装依赖环境 在线安装依赖环境&#xff1a; yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c kernel-devel m4 ncurses-devel tk tc xz2. 安装Erlang 上…

【完整版】国内网络编译,Ambari 2.7.6 全部模块源码编译笔记

本次编译 ambari 2.7.6 没有使用科学上网的工具,使用的普通网络,可以编译成功,过程比 ambari 2.7.5 编译时要顺畅。 以下是笔记完整版。如果想单独查看本篇编译笔记,可参考:《Ambari 2.7.6 全部模块源码编译笔记》 该版本相对 2.7.5 版本以来,共有 26 个 contributors …

使用labelImg标注自己的VOC数据集

文章目录1.下载labelImg2.准备文件夹3.打开软件4.软件使用1.下载labelImg 步骤&#xff1a;WindowsR打开运行界面→输入cmd打开命令行窗口→输入pip install labelImg命令&#xff08;前提是python版本在3.0以上并安装anaconda&#xff0c;如果没有安装anaconda&#xff0c;输…

cmd窗口中java命令报错。错误:找不到或无法加载主类 java的jdk安装过程中踩过的坑

错误: 找不到或无法加载主类 HelloWorld 遇到这个问题时&#xff0c;我尝试过网上其他人的做法。有试过添加classpath&#xff0c;也有试过删除classpath。但是依然报错&#xff0c;这里javac可以编译通过&#xff0c;说明代码应该是没有问题的。只是在运行是出现了错误。我安装…

卷积神经网络的原理及实现

专栏&#xff1a;神经网络复现目录 卷积神经网络 本章介绍的卷积神经网络&#xff08;convolutional neural network&#xff0c;CNN&#xff09;是一类强大的、为处理图像数据而设计的神经网络。 基于卷积神经网络架构的模型在计算机视觉领域中已经占主导地位&#xff0c;当今…

【C3】进程休眠,时间和延时,延缓,/proc文件系统,内存分配,数据类型,/内核中断,通过IO内存访问外设

9.实现进程休眠&#xff1a;条件不够歇一歇&#xff0c;把CPU让给其他进程 有时候进程在读设备时&#xff0c;发现设备数据还没准备好&#xff0c;没办法正常读取设备。或在写设备时&#xff0c;发现设备缓冲区满&#xff0c;没办法正常写设备。在遇到这些情况时&#xff0c;进…

SpringCloud之 Eureka注册中心

文章目录Eureka注册中心一、服务注册与发现1.1 依赖导入①父工程 SpringCloud 版本管理②Eureka 服务端依赖③Eureka 客户端依赖1.2 服务注册①创建 Eureka 服务端的主类②设置 Eureka 服务端的配置文件③设置 Eureka 客户端的配置文件④关闭自我保护机制1.3 服务发现①远程调用…

计算机视觉废钢堆提取问题

计算机视觉废钢堆提取问题 背景介绍 在钢铁炼制中&#xff0c;废钢是非常重要的原料&#xff0c;不同等级废钢对于钢成品影响很大&#xff0c;因此需要对废钢进行正确分类。某废钢料场中&#xff0c;卸料区域布置了多个摄像头&#xff0c;用于拍摄卸料场中废钢堆&#xff0c;…

python 连接数据库

文章目录同步操作同步连Mysql同步连redis同步连mongodb异步操作异步连mysql异步连redis异步连mongodb同步操作 同步连Mysql python 连接mysql可以使用pymysql、mysqlclient等。 安装&#xff1a; # win pip install pymysql 连接mysql: # __author__ "laufing"…

Java各种锁

目录 一、读写锁(ReentrantReadWriteLock) 二、非公平锁(synchronized/ReentrantLock) 三、可重入锁/递归锁(synchronized/ReentrantLock) 四、自旋锁(spinlock) 五、乐观锁/悲观锁 六、死锁 1、死锁代码 2、死锁的检测(jps -l 与 jstack 进程号) 本文通过学习&#xff…

Spring——Spring介绍和IOC相关概念

Spring是以Spring Framework为核心&#xff0c;其余的例如Spring MVC&#xff0c; Spring Cloud&#xff0c;Spring Data&#xff0c;Spring Security SpringBoot的基础都是Spring Framework。 Spring Boot可以在简化开发的基础上加速开发。 Spring Cloud分布式开发 Spring有…

SAP MM学习笔记6-SAP要怎么学

SAP还是很复杂的&#xff0c;学习之前&#xff0c;了解学习技巧很重要。 根据前辈经验&#xff0c;SAP学习技巧大致总结为如下三个&#xff0c;供大家参考。 1&#xff0c;忘了自己技术者的身份&#xff0c;控制追求技术细节的冲动 软件行业经常听到一句话&#xff0c;什么都…