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

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

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

地址,指针,指针变量是什么?他们的区别?符号(*)在不同位置的解释?_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;}}
}

相关文章:

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

关于地址&#xff0c;指针&#xff0c;指针变量可以参考我的这篇文章&#xff1a; 地址&#xff0c;指针&#xff0c;指针变量是什么&#xff1f;他们的区别&#xff1f;符号&#xff08;*&#xff09;在不同位置的解释&#xff1f;_juechen333的博客-CSDN博客https://blog.csd…...

k8s中的PV和PVS

前言&#xff1a;容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;kubelet 会重启它&#xff0c;但是容器中的文件将丢失——容器以干净的状态&#xff08;镜像最初的状态&#xff09;…...

【云原生】Gateway网关选型

网关一般分为流量网关和业务网关&#xff0c;流量网关负责接入所有的流量&#xff0c;并分发给不同的子系统&#xff0c;那在具体的业务接入之前&#xff0c;还有一层业务网关。流量网关提供全局性的、与后端业务应用无关的策略&#xff0c;例如 HTTPS证书卸载、Web防火墙、全局…...

QML Button详解

1.Button简介 Button表示用户可以按下或单击的按钮控件。按钮通常用于执行一个动作&#xff0c;或回答一个问题。典型的按钮有确定、应用、取消、关闭、是、否和帮助。 Button继承自AbstractButton&#xff0c;提供了以下几种信号。 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设置

问题 如果读者熟悉我&#xff0c;应该会发现我经常使用 VSCode 作为主力编辑器&#xff0c;但随着我安装的 VSCode 的插件逐渐增加&#xff0c;我发现对于部分较小的任务使用 VSCode 过于笨重&#xff0c;比如简单的 Markdown 文件编辑工作。 在经过一系列寻找后&#xff0c;…...

c语言经典例题-选择结构程序设计进阶

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 快递费用计算&#xff1a; 题目&#xff1a; 代码思路&#xff1a; 代码表示&#xff1a; 计算一元二…...

NOI 2023春季测试 游记

怎么说&#xff0c;没遇到大波折即幸运。 Day 0 睡到下午三点&#xff0c;然后列了一堆复习计划&#xff0c;大概是左偏树等一些早就忘没的科技。 但是沉迷打块&#xff0c;最后基本什么计划也没完成。 白天睡多了&#xff0c;晚上睡不着&#xff0c;大概半梦半醒过了一整夜…...

【VC 7/8】vCenter Server 基于文件的备份和还原Ⅱ——使用 FTP 协议备份 VC(VAMI 英文)

目录2. 备份 vCenter Server2.1 使用 FTP 协议备份 VC&#xff08;1&#xff09;登录 vCenter Server 管理界面&#xff08;2&#xff09;进入Backup页面&#xff08;3&#xff09;配置 Backup Schedule&#xff08;4&#xff09;开始备份&#xff08;5&#xff09;备份成功&am…...

Python基础—文件操作(二)

Python基础—文件操作(二) CSV格式文件 逗号分隔值&#xff0c;以纯文本形式存储表格数据 由任意数目的记录组成&#xff0c;记录间以换行符分隔 每条记录由字段组成&#xff0c;字段间用逗号或制表符分隔 每条记录都有同样的字段序列 如有列名&#xff0c;位于文件第一行 每条…...

学校的班级个数【并查集基础应用,Java实现】

题目描述 现有一个学校&#xff0c;学校中有若干个班级&#xff0c;每个班级中有若干个学生&#xff0c;每个学生只会存在于一个班级中。如果学生A和学生B处于一个班级&#xff0c;学生B和学生C处于一个班级&#xff0c;那么我们称学生A和学生C也处于一个班级。 现已知学校中共…...

WSL2使用Nvidia-Docker实现CUDA版本自由切换

众所周知&#xff0c;深度学习的环境往往非常麻烦&#xff0c;经常不同的项目所依赖的 torch、tensorflow 包对 CUDA 的版本也有不同的要求&#xff0c;Linux 下进行 CUDA 的管理比较麻烦&#xff0c;是一个比较头疼的问题。 随着 WSL2 对物理机显卡的支持&#xff0c;Nvidia-…...

pygame9 扫雷游戏2

一、响应鼠标左键事件 pygame.MOUSEBUTTONDOWN 表示鼠标事件发生&#xff0c; pygame.mouse.get_pressed()[0] 确认是鼠标左键被按下 pygame.mouse.get_pos() 获取到鼠标按下时的坐标值。 因此&#xff0c;我们可以在事件逻辑中例用此三个函数判断鼠标事件及对应的坐标&#x…...

逻辑电路代数运算(上)

逻辑代数L是一个封闭的代数系统&#xff0c;由一个逻辑变量集K&#xff0c;常量0和1&#xff0c;以及与或非三种基本运算构成。 参与逻辑运算的变量叫逻辑变量&#xff0c;用字母A&#xff0c;B……表示。每个变量的取值非0 即1。 0、1不表示数的大小&#xff0c;而是代表两种不…...

Rabbit快速入门

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

【react+ts- forwardRef】

reactts- forwardRef1. 学习资料2. 普通input透传2.1 TS版本2.2 JS版本3. TS-Antd-Form组价透传引用传递&#xff08;Ref forwading&#xff09;是一种通过组件向子组件自动传递 引用ref 的技术。对于应用者的大多数组件来说没什么作用。但是对于有些重复使用的组件&#xff0c…...

计算机网络-- 网络层(day06)

文章目录网络层思维导图IPv4地址的应用规划定长的子网掩码变长的子网掩码VLSMIP数据报的发送和转发过程主机发送IP数据报路由器转发IP数据报静态路由选择动态路由选择路由选择协议概述常见的路由选择协议路由器的基本结构路由信息协议RIP的基本工作原理开放最短路径优先OSPF的基…...

docker 镜像

一、介绍 镜像:是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码,运行时需要的库,环境变量和配置文件等)这个打包好的运行环境就是image镜像文件。 只有通过这个镜…...

JUC并发编程与源码分析笔记11-Java对象内存布局和对象头

先从阿里及其它大厂面试题说起 你觉得目前面试&#xff0c;你还有那些方面理解的比较好&#xff0c;我没问到的&#xff0c;我说了juc和jvm以及同步锁机制那先说juc吧&#xff0c;说下aqs的大致流程cas自旋锁&#xff0c;是获取不到锁就一直自旋吗?cas和synchronized区别在哪…...

JavaSE之集合篇

文章目录前言一、集合概述集合继承结构图二、Collection接口中常用方法2.1Collection中存放什么元素&#xff1f;2.2常用方法2.3迭代器三、List接口中常用的方法四、ArrayList初始化容量及扩容五、Vector六、Map接口常用方法七、Properties前言 由于在刷题过程中&#xff0c;经…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...