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

【时时三省】(C语言基础)用数组名作函数参数

山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省

可以用数组名作函数的参数。

例如:

 array是实参数组名,arr为形参数组名。当用数组名作参数时,如果形参数组中各元素的值发生变化,实参数组元素的值随之变化。这究竟是什么原因呢?在学习指针以后,对此问题就容易理解了。

先看数组元素作实参时的情况。如果已定义一个函数,其原型为

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 ]的值并不改变。

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

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组首元素,也就是指向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的元素,

常用这种方法通过调用一个函数来改变实参数组的值。

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

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

注意:实参数组名代表一个固定的地址,或者说是指针常量,但形参数组名并不是一个固定的地址,而是按指针变量处理。在函数调用进行虚实结合后,形参的值就是实参数组首元素的地址。在函数执行期间,它可以再被赋值。

例如:

void fun ( arr [ ] , int n )

{

printf ( " % d\n " , * arr );

arr = arr + 3 ;

printf ( " % d\n " , * arr );

}

例题:

将数组a中n个整数按相反顺序存放。

解题思路:

将a [ 0 ]与a [ n-1 ]对换,再将a [ 1 ]与a [ n-2 ]对换……直到将a [ int ( n-1 ) / 2 ]与a [ n—int ( ( n-1 ) / 2 ) -1对换。今用循环处理此问题,设两个“位置指示变量”i和j,i的初值为0,j的初值为n—1。将a [i]与a[j]交换,然后使i的值加1,j的值减1,再将a [ i ]与a [ j ]对换,直到i = ( n-1 ) / 2为止。用一个函数inv来实现交换。实参用数组名a,形参可用数组名,也可用指针变量名。

编写程序:

运行结果: 

程序分析:

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

对这个程序可以作一些改动。将函数inv中的形参×改成指针变量。相应的实参仍为数组名a,即数组a首元素的地址,将它传给形参指针变量x,这时x就指向a [ 0 ]。x + m是a[m]元素的地址。设i和j以及p都是指针变量,用它们指向有关元素。i的初值为x,j的初值为x + n-1,使*i与* j交换就是使a [ i ]与a [ j ]交换。

修改程序:

运行结果与上面程序一样

归纳分析:

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

( 1 )形参和实参都用数组名,例如:

 由于形参数组名x接收了实参数组首元素a [ 0 ]的地址,因此可以认为在函数调用期间,形参数组与实参数组共用一段内存单元,这种形式比较好理解。

( 2 )实参用数组名,形参用指针变量。例如:

 实参a为数组名,形参x为int*型的指针变量,调用函数开始后,形参x指向a [ 0 ],即x =&a[0],通过x值的改变,可以指向a数组的任一元素。

( 3 )实参形参都用指针变量。例如:

 实参p和形参x都是int*型的指针变量。先使实参指针变量p指向数组a [ 0 ],p的值是& a [ 0 ]。然后将p的值传给形参指针变量x,x的初始值也是& a [ 0 ],通过x值的改变可以使x指向数组a的任一元素。

( 4 )实参为指针变量,形参为数组名。例如:

 实参p为指针变量,它指向a [ 0 ],形参为数组名x,编译系统把×作为指针变量处理。将a [ 0 ]的地址传给形参x,使×也指向a [ 0 ],也可以理解为形参数组x和a数组共用同一段内存单元,在函数执行过程中可以使x[i]的值发生变化,而x [i]就是a [ i ]。这样,main函数可以使用变化了的数组元素值。

例题:

用指针方法对10个整数按由大到小顺序排序。解题思路:在主函数中定义数组a存放10个整数,定义int*型指针变量p并指向a [ 0 ]。定义函数sort使数组a中的元素按由大到小的顺序排列。在主函数中调用sort函数,用指针变量p作实参。sort函数的形参用数组名。用选择法进行排序。

编写程序:

程序分析:

为了便于理解,函数sort中用数组名作为形参,用下标法引用形参数组的元素,这样的程序很容易看懂。当然也可以改用指针变量,这时sort函数的首部可以改为

sort ( int * x , int n )

形其他不改,程序运行结果不变。

可以看到,即使在函数sort中将x定义为指针变量,在函数中仍可用x [ i ]和x [ j ]这样的形式表示数组元素,它就是x + i和x + j所指的数组元素。

http://www.lryc.cn/news/588359.html

相关文章:

  • 75、【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例
  • 数电汇总——logisim的辛酸史
  • 【Python进阶】深度复制——deepcopy
  • stm32-Modbus主机移植程序理解以及实战
  • JSCPC 2025 江苏省赛
  • 制造业实战:数字化集采如何保障千种备件“不断供、不积压”?
  • Java从入门到精通!第五天(面向对象(二))
  • 《解锁音频处理新姿势:探索Librosa的无限可能》
  • HarmonyOS应用无响应(AppFreeze)深度解析:从检测原理到问题定位
  • ISO-IEC-IEEE 42010架构规范
  • 016 进程控制 —— 进程创建
  • ShenYu实战、问题记录
  • Spring Boot 自带的 JavaMail 集成
  • 文心一言 4.5 开源深度剖析:中文霸主登场,开源引擎重塑大模型生态
  • 分布式光伏并网中出现的电能质量问题,如何监测与治理?
  • 时序预测 | Pytorch实现CNN-LSTM-KAN电力负荷时间序列预测模型
  • MongoDB从入门到精通
  • [Nagios Core] 事件调度 | 检查执行 | 插件与进程
  • 【Linux】Linux 操作系统 - 28 , 进程间通信(四) -- IPC 资源的管理方式_信号量_临界区等基本概念介绍
  • Excel常用快捷键与功能整理
  • 《恋与深空》中黑白羽毛是谁的代表物?
  • 【前端】【分析】前端功能库二次封装:组件与 Hook 方式的区别与好处分析
  • 体验RAG GitHub/wow-rag
  • 国内MCP服务器搜索引擎有哪些?MCP导航站平台推荐
  • 基于cornerstone3D的dicom影像浏览器 第一章,新建vite项目,node版本22
  • 了解 Java 泛型:简明指南
  • yolo8+声纹识别(实时字幕)
  • ArkTs实现骰子布局
  • Pandas-特征工程详解
  • WinUI3开发_Combobox实现未展开时是图标下拉菜单带图标+文字