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

【时时三省】(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.xdnf.cn/news/15329.html

相关文章:

  • MFC中BOOL类型,在某些操作系统中,-1不能被识别,一般是哪些原因?
  • C++-linux 7.文件IO(二)文件描述符、阻塞与非阻塞
  • 招投标——环保大数据平台售后服务计划
  • 现代数据平台能力地图:如何构建未来数据平台的核心能力体系
  • Spark 之 like 表达式
  • uni-app开发的页面跳转全局加载中
  • QT——信号与槽
  • git 访问 github
  • 《恋与深空》中黑白羽毛是谁的代表物?
  • python+Request提取cookie
  • ubuntu22.04下配置qt5.15.17开发环境
  • Elasticsearch9.x核心架构概述
  • 机器学习、深度学习、神经网络之间的关系
  • 多租户云环境下的隔离性保障:虚拟化、容器、安全组如何协同防护?
  • 高德开放平台携手阿里云,面向开发者推出地图服务产品MCP Server
  • Redis技术笔记-主从复制、哨兵与持久化实战指南
  • 工业场合需要千变万化的模拟信号,如何获取?
  • Servlet基础
  • priority_queue的使用和模拟实现以及仿函数
  • FatJar打包和FatJar启动配置文件修改。
  • 对偶原理与蕴含定理
  • [论文阅读] 人工智能 + 软件工程 | 用大语言模型+排名机制,让代码评论自动更新更靠谱
  • Ubuntu22.04 python环境管理
  • 深度解析:htmlspecialchars 与 nl2br 结合使用的前后端协作之道,大学毕业论文——仙盟创梦IDE
  • nginx:SSL_CTX_use_PrivateKey failed
  • 【HTTP版本演变】
  • Python 数据建模与分析项目实战预备 Day5 - 模型训练与评估
  • 九、官方人格提示词汇总(中-1)
  • (LeetCode 每日一题) 1290. 二进制链表转整数 (链表+二进制)
  • Kafka 时间轮深度解析:如何O(1)处理定时任务