用数组名作函数参数的详解,以及形参实参采用数组名,形参实参采用指针变量的几种情况解析
关于地址,指针,指针变量可以参考我的这篇文章:
地址,指针,指针变量是什么?他们的区别?符号(*)在不同位置的解释?_juechen333的博客-CSDN博客
https://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;}}
}相关文章:
用数组名作函数参数的详解,以及形参实参采用数组名,形参实参采用指针变量的几种情况解析
关于地址,指针,指针变量可以参考我的这篇文章: 地址,指针,指针变量是什么?他们的区别?符号(*)在不同位置的解释?_juechen333的博客-CSDN博客https://blog.csd…...
k8s中的PV和PVS
前言:容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)…...
【云原生】Gateway网关选型
网关一般分为流量网关和业务网关,流量网关负责接入所有的流量,并分发给不同的子系统,那在具体的业务接入之前,还有一层业务网关。流量网关提供全局性的、与后端业务应用无关的策略,例如 HTTPS证书卸载、Web防火墙、全局…...
QML Button详解
1.Button简介 Button表示用户可以按下或单击的按钮控件。按钮通常用于执行一个动作,或回答一个问题。典型的按钮有确定、应用、取消、关闭、是、否和帮助。 Button继承自AbstractButton,提供了以下几种信号。 void canceled() //当按…...
【编程实践】什么是好/坏代码?非程序员的示例
What is good/bad code? An illustrated example for non-programmers 什么是好/坏代码?非程序员的示例 目录 What is good/bad code? An illustrated example for non-programmers什么是好/坏代码?非程序员的示例 So what is ‘Bad Code’, as a layperson?那么,作为…...
一个简单的Sublime设置
问题 如果读者熟悉我,应该会发现我经常使用 VSCode 作为主力编辑器,但随着我安装的 VSCode 的插件逐渐增加,我发现对于部分较小的任务使用 VSCode 过于笨重,比如简单的 Markdown 文件编辑工作。 在经过一系列寻找后,…...
c语言经典例题-选择结构程序设计进阶
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 快递费用计算: 题目: 代码思路: 代码表示: 计算一元二…...
NOI 2023春季测试 游记
怎么说,没遇到大波折即幸运。 Day 0 睡到下午三点,然后列了一堆复习计划,大概是左偏树等一些早就忘没的科技。 但是沉迷打块,最后基本什么计划也没完成。 白天睡多了,晚上睡不着,大概半梦半醒过了一整夜…...
【VC 7/8】vCenter Server 基于文件的备份和还原Ⅱ——使用 FTP 协议备份 VC(VAMI 英文)
目录2. 备份 vCenter Server2.1 使用 FTP 协议备份 VC(1)登录 vCenter Server 管理界面(2)进入Backup页面(3)配置 Backup Schedule(4)开始备份(5)备份成功&am…...
Python基础—文件操作(二)
Python基础—文件操作(二) CSV格式文件 逗号分隔值,以纯文本形式存储表格数据 由任意数目的记录组成,记录间以换行符分隔 每条记录由字段组成,字段间用逗号或制表符分隔 每条记录都有同样的字段序列 如有列名,位于文件第一行 每条…...
学校的班级个数【并查集基础应用,Java实现】
题目描述 现有一个学校,学校中有若干个班级,每个班级中有若干个学生,每个学生只会存在于一个班级中。如果学生A和学生B处于一个班级,学生B和学生C处于一个班级,那么我们称学生A和学生C也处于一个班级。 现已知学校中共…...
WSL2使用Nvidia-Docker实现CUDA版本自由切换
众所周知,深度学习的环境往往非常麻烦,经常不同的项目所依赖的 torch、tensorflow 包对 CUDA 的版本也有不同的要求,Linux 下进行 CUDA 的管理比较麻烦,是一个比较头疼的问题。 随着 WSL2 对物理机显卡的支持,Nvidia-…...
pygame9 扫雷游戏2
一、响应鼠标左键事件 pygame.MOUSEBUTTONDOWN 表示鼠标事件发生, pygame.mouse.get_pressed()[0] 确认是鼠标左键被按下 pygame.mouse.get_pos() 获取到鼠标按下时的坐标值。 因此,我们可以在事件逻辑中例用此三个函数判断鼠标事件及对应的坐标&#x…...
逻辑电路代数运算(上)
逻辑代数L是一个封闭的代数系统,由一个逻辑变量集K,常量0和1,以及与或非三种基本运算构成。 参与逻辑运算的变量叫逻辑变量,用字母A,B……表示。每个变量的取值非0 即1。 0、1不表示数的大小,而是代表两种不…...
Rabbit快速入门
入门案例 需求:使用简单模式完成消息传递 步骤: 创建工程(生成者、消费者) 分别添加依赖 编写生产者发送消息 编写消费者接收消息 3.1.2. 添加依赖 往heima-rabbitmq的pom.xml文件中添加如下依赖: <dependenc…...
【react+ts- forwardRef】
reactts- forwardRef1. 学习资料2. 普通input透传2.1 TS版本2.2 JS版本3. TS-Antd-Form组价透传引用传递(Ref forwading)是一种通过组件向子组件自动传递 引用ref 的技术。对于应用者的大多数组件来说没什么作用。但是对于有些重复使用的组件,…...
计算机网络-- 网络层(day06)
文章目录网络层思维导图IPv4地址的应用规划定长的子网掩码变长的子网掩码VLSMIP数据报的发送和转发过程主机发送IP数据报路由器转发IP数据报静态路由选择动态路由选择路由选择协议概述常见的路由选择协议路由器的基本结构路由信息协议RIP的基本工作原理开放最短路径优先OSPF的基…...
docker 镜像
一、介绍 镜像:是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码,运行时需要的库,环境变量和配置文件等)这个打包好的运行环境就是image镜像文件。 只有通过这个镜…...
JUC并发编程与源码分析笔记11-Java对象内存布局和对象头
先从阿里及其它大厂面试题说起 你觉得目前面试,你还有那些方面理解的比较好,我没问到的,我说了juc和jvm以及同步锁机制那先说juc吧,说下aqs的大致流程cas自旋锁,是获取不到锁就一直自旋吗?cas和synchronized区别在哪…...
JavaSE之集合篇
文章目录前言一、集合概述集合继承结构图二、Collection接口中常用方法2.1Collection中存放什么元素?2.2常用方法2.3迭代器三、List接口中常用的方法四、ArrayList初始化容量及扩容五、Vector六、Map接口常用方法七、Properties前言 由于在刷题过程中,经…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
