C语言 用数组名作函数参数

当用数组名作函数参数时,如果形参数组中各元素的值发生变化,实参数组元素的值随之变化。

1.数组元素做实参的情况:

如果已经定义一个函数,其原型为

void swap(int x,int y);

假设函数的作用是将两个形参(x,y)进行交换,现在有以下的函数调用:

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

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

2.数组名作函数形参的情况:

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

例如:定义一个函数fun,fun函数的形参写成数组的形式:

void fun(int arr[],int n);

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

void fun(int *arr,int n);

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

void fun(int arr[], int n)
{int s = sizeof(arr);printf("arr所占字节数为:%d\n", s);
}
int main()
{int brr[10];fun(brr, 10);return 0;}

运行结果:
在这里插入图片描述
当arr接收了实参数组的首元素地址后,arr就指向实参数组的首元素,也就是指向了brr[0]。因此,arr就是brr[0]。arr+1指向brr[1],arr+2指向brr[2],arr+3指向brr[3].也就是说,*(arr+1)*(arr+2)*(arr+3)分别是brr[1],brr[2],brr[3]。*(arr+i)arr[i]是无条件等价的。因此在调用函数期间,arr[0]和arr以及brr[0]都代表数组brr序号为0的元素。

【注意】

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

在函数调用进行虚实结合后,形参的值就是实参数组首元素的地址。在函数指向期间,它可以在被赋值。

【例】定义一个数组名作形参的函数,通过调用这个函数改变实参数组的值

int fun(int arr[], int n)
{//int s = sizeof(arr);//printf("arr所占字节数为:%d\n", s);int t;t = arr[1];arr[1] = arr[2];arr[2] = t;return arr[0];
}
int main()
{int brr[10] = { 1,3,2,4,5,6,7,8,9,10 };fun(brr, 10);for (int i = 0; i < 10; i++){printf("%d  ", brr[i]);}return 0;}

运行结果:

在这里插入图片描述

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

3.变量名做函数参数和用数组名做函数参数的比较

(1)当实参类型是变量名时,要求形参的类型也是变量名,通过形参传递的信息是变量的值,通过函数调用不能改变实参变量的值。

(2)当实参类型是数组名时,要求形参的类型是数组名或者指针变量,通过形参传递的信息是实参数组首元素的地址,通过函数调用能改变实参变量的值。

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

4.数组名和指针变量作为函数的形参

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

【例】将数组a中n个整数按相反顺序存放,用一个函数inv来实现交换。实参用数组名a,形参可用数组名,也可用指针变量。

void inv(int x[], int n)//形参x是数组名
{int temp;int m = (n - 1) / 2;for (int i = 0; i <= m; i++){int j = n - 1 - i;//把x[i]和x[j]交换temp = x[i];x[i] = x[j];x[j] = temp;}return;
}
int main()
{int a[10] = { 1,2,3,4,5,6,7,8,9,10 };inv(a, 10);//调用inv函数进行交换for (int i = 0; i < 10; i++){printf("%d ", a[i]);}
}

运行结果:
在这里插入图片描述
结果分析:
在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中得形参x改成指针变量:

void inv(int *x, int n)
{int temp;//定义一个中间变量,用来交换两个变量得值int m = (n - 1) / 2;int* p;//定义一个指针变量pp = x + m;//p指向a[m]元素的地址int* i;//定义一个指针变量ii = x;//i指向数组首元素的地址int* j;//定义一个指针变量jj = x + n - 1;//j指向数组最后一个元素的地址for (i=x;i<=p;i++,j--){//交换i和j所指向的数组元素的值temp = *i;*i = *j;*j = temp;}return;
}
int main()
{int a[10] = { 1,2,3,4,5,6,7,8,9,10 };inv(a, 10);for (int i = 0; i < 10; i++){printf("%d ", a[i]);}
}

改写后,函数inv中得形参有数组名x[]变为了指针变量*x,相应的实参仍是数组名a,即数组a首元素的地址,将它传给形参指针变量x,这时x就指向a[0]。x+m是a[m]元素得地址。设i和j以及p都是指针变量,用它们指向有关元素。交换i和j所指向的数组元素的值,实际上就是交换a[i]和a[j]的值。

运行结果:
在这里插入图片描述

5.归纳分析

(1)形参和实参都用数组名
int fun(int x[],int n)
{...
}
int main()
{int a[10];...fun(a,10);...return 0;
}

由于形参数组名x接收了实参数组名首元素a[0]的地址,因此可以认为在函数调用期间,形参数组和实参数组共用一段内存单元,如图所示:
在这里插入图片描述

(2)实参用作数组名,形参用指针变量
void fun(int *x,int n)
{...
}
int main()
{int a[10];...fun(a,10);...return 0;
}

实参a为数组名,形参x为int *型的指针变量,调用函数开始后,形参x指向a[0],即x=&a[0],通过x值的改变,可以指向a数组的任一元素,如图所示:
在这里插入图片描述

(3)实参形参都用指针变量
void fun(int *x,int n)
{...
}
int main()
{int a[10];int *p=a;...fun(a,10)...return 0;
}

实参p和形参x都是int*型指针变量。先使用实参指针变量p指向数组元素a[0],p的值是&a[0]。然后将p的值传给形参变量x,x的初始值也是&a[0],通过x的值的改变可以使x指向数组a的任一元素,如图所示:
在这里插入图片描述

(4)实参为指针变量,形参为数组名
void fun(int x[],int n)
{...
}
int main()
{int a[10];int *p=a;...fun(p,10);...return 0;
}

实参p作为指针变量,它指向a[0]。形参为数组名x,编译系统把x作为指针变量处理,将a[0]的地址传给形参x,使x也指向a[0]。也可以理解为形参数组x和a数组共用同一内存单元,在函数执行过程中可以使x[i]的值发生变化,而x[i]就是a[i]。这样主函数可以使用改变了的数组元素值,如图所示:
在这里插入图片描述
【例】指针变量做实参

void inv(int* x, int n)
{int temp;int m = (n - 1) / 2;int* p;p = x + m;int* i;i = x;int* j;j = x + n - 1;for (i = x; i <= p; i++, j--){temp = *i;*i = *j;*j = temp;}return;
}
int main()
{int a[10];int* p = a;//指针变量p指向a[0]//输入数组a的元素for (int i = 0; i < 10; i++, p++){scanf("%d", p);}p = a;//将指针变量p重新指向a[0]inv(p, 10);//调用inv函数,实参是变量pfor (int i = 0; i < 10; i++){printf("%d ", a[i]);}return 0;
}

运行结果:
在这里插入图片描述
上面的main函数中的指针变量p是有确定值的。如果在main函数中不设数组,只设指针变量,就会出错。假如把主函数修改如下:

void inv(int* x, int n)
{int temp;int m = (n - 1) / 2;int* p;p = x + m;int* i;i = x;int* j;j = x + n - 1;for (i = x; i <= p; i++, j--){temp = *i;*i = *j;*j = temp;}return;
}
int main()
{int a[10];int* p;//输入数组a的元素for (int i = 0; i < 10; i++){scanf("%d", p+i);}inv(p, 10);//调用inv函数,实参是变量pfor (int i = 0; i < 10; i++){printf("%d ", *(p+i));}return 0;
}

编译时会出错,原因是指针变量p没有确定值,谈不上指向哪个变量:
在这里插入图片描述
因此,下面这样的使用是不正确的:

void fun(int x[],int n)
{...
}
int main()
{int *p;...fun(p,10);
}

【注意】如果指针变量做实参,必须先使指针变量有确定的值,指向一个已经定义的对象。

以上4种方法,实质上都是地址的传递。其中(3)和(4)两种只是形式上不同,实际上形参都是使用的指针变量。

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

//定义sort函数,x是形参数组名
void sort(int x[], int n)
{int temp;for (int i = 0; i < n-1; i++){for (int j = i + 1; j < n; j++){if (x[j]>x[i]){temp = x[i];x[i] = x[j];x[j] = temp;}}}
}
int main()
{int a[10];int* p = a;//指针变量p指向a[0]//输入10个整数for (int i = 0; i < 10; i++){scanf("%d", p++);}p = a;//指针变量p重新指向a[0]sort(p, 10);//调用sort函数//输出排序后的10个数组元素for (int i = 0; i < 10; i++){printf("%d ", *p);p++;}return 0;
}

运行结果:
在这里插入图片描述
如果sort函数中将x定义为指针变量,在函数中仍可以用x[i]和x[j]这样的形式表示数组元素,它就是x+i和x+j所指的数组元素。

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

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

相关文章

【css】组合器

组合器是解释选择器之间关系的某种机制。在简单选择器器之间&#xff0c;可以包含一个组合器&#xff0c;从而实现简单选择器难以达到的效果。 CSS 中有四种组合器&#xff1a; 后代选择器 (空格)&#xff1a;匹配属于指定元素后代的所有元素&#xff0c;示例&#xff1a;div …

GWJDN-400型2MHZ自动平衡高温介电温谱仪

GWJDN-400型2MHZ自动平衡高温介电温谱仪 关键词&#xff1a;介电常数&#xff0c;高温介电&#xff0c;自动平衡 主要功能&#xff1a; 材料介电常数测试仪 半导体材料的介电常数、导电率和C-V特性液晶材料:液晶单元的介电常数、弹性常数等C-V特性 性能特点: 温度&#xf…

【CSS】说说响应式布局

目录 一、是什么 二、怎么实现 1、媒体查询 2、百分比 3、vw/vh 4、小结 三、总结 一、是什么 响应式设计简而言之&#xff0c;就是一个网站能够兼容多个终端——而不是为每个终端做一个特定的版本。 响应式网站常见特点&#xff1a; 同时适配PC 平板 手机等…

yxBUG记录

1、 原因&#xff1a;前端参数method方法名写错。 2、Field ‘REC_ID‘ doesn‘t have a default value 问题是id的生成问题。 项目的表不是自增。项目有封装好的方法。调用方法即可。 params.put("rec_id",getSequence("表名")) 3、sql语句有问题 检…

Docker 快速安装 MinIO

概述 MinIO 是一款基于Go语言的高性能对象存储服务&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等。 拉取docker镜像 docker pull minio/minio创建宿主机数据目录&#xff08;共享数据卷&#xff09; 此…

Django进阶

1.模板 1.1 寻找html模板 TEMPLATES [{BACKEND: django.template.backends.django.DjangoTemplates,DIRS: [os.path.join(BASE_DIR, templates)],APP_DIRS: True,OPTIONS: {context_processors: [django.template.context_processors.debug,django.template.context_process…

【IDEA + Spark 3.4.1 + sbt 1.9.3 + Spark MLlib 构建鸢尾花决策树分类预测模型】

决策树进行鸢尾花分类的案例 背景说明&#xff1a; 通过IDEA Spark 3.4.1 sbt 1.9.3 Spark MLlib 构建鸢尾花决策树分类预测模型&#xff0c;这是一个分类模型案例&#xff0c;通过该案例&#xff0c;可以快速了解Spark MLlib分类预测模型的使用方法。 依赖 ThisBuild /…

会这个Python的测试员,工作都不会太差!

Python语言得天独厚的优势使之在业界的火热程度有增无减&#xff0c;尤其是在经历了互联网&#xff0c;物联网&#xff0c;云计算&#xff0c;大数据&#xff0c;人工智能等浪潮的推动下&#xff0c;其关注度&#xff0c;普适度一路走高。 对于测试人员来说&#xff0c;很多人…

科技感响应式管理系统后台登录页ui设计html模板

做了一个科技感的后台管理系统登录页设计&#xff0c;并且尝试用响应式布局把前端html写了出来&#xff0c;发现并没有现象中的那么容易&#xff0c;chrome等标准浏览器都显示的挺好&#xff0c;但IE11下面却出现了很多错位&#xff0c;兼容起来还是挺费劲的&#xff0c;真心不…

Linux系统中redis基础

本节主要学习redis的概述&#xff0c;安装目录结构&#xff0c;命令解析和redis登录更改&#xff0c;数据库的操作&#xff0c;和redis的持久化。 目录 一、概述 二、安装 1.编译安装 2.rpm安装 三、目录结构 四、命令解析 五、redis登陆更改 问题 解决办法 六、数据…

P11-Transformer学习1.1-《Attention Is All You Need》

Transformer目录:《Transformer Paper》1.0 CV Transformer必读论文5篇_汉卿HanQ的博客-CSDN博客 前文参考:Transformer1.0-预热_汉卿HanQ的博客-CSDN博客 全文1w3字左右&#xff0c;按照论文翻译个人理解精读&#xff0c;如果对你有所帮助&#xff0c;欢迎点个赞哦&#xff…

MQTT消息传输过程,网络断开后,断线重连及订阅消息恢复

1&#xff0c;首先要在网络失败的地方进行client重连 2&#xff0c;一定要设置发送超时&#xff0c;默认是-1&#xff0c;是不断进行发送的&#xff0c;会被长阻塞在这里&#xff0c;单位是ms 3&#xff0c;参考链接 https://vimsky.com/examples/detail/java-method-org.ec…

揭秘无人机在水利行业中如何应用

无人机的应用已经成为现代科技的重要组成部分&#xff0c;在水利行业中&#xff0c;无人机的应用同样发挥了极其重要的作用。无人机在水利行业中的应用&#xff0c;不仅提高了工作效率&#xff0c;还极大地降低了人力和物力成本&#xff0c;为水利工作注入了新的活力。 一、无人…

2023集成电路产业发展与产教融合高峰论坛会议顺利举行

8月5日&#xff0c;由中国半导体行业协会和市政府共同主办&#xff0c;天水师范学院、天水华天科技股份有限公司、杭州加速科技有限公司承办的2023集成电路产业发展与产教融合高峰论坛在天水举行。天水市委书记冯文戈&#xff0c;教育部学生服务与素质发展中心副主任方伟&#…

Flutter父宽度自适应子控件的宽度

需求&#xff1a; 控件随着金币进行自适应宽度 image.png 步骤&#xff1a; 1、Container不设置宽度&#xff0c;需要设置约束padding&#xff1b; 2、文本使用Flexible形式&#xff1b; Container(height: 24.dp,padding: EdgeInsetsDirectional.only(start: 8.dp, end: 5.d…

【知识图谱】图数据库Neo4jDesktop的安装图文详解(小白适用)

neo4j 的安装需要有jdk环境的支持。因此在安装Neo4j之前&#xff0c;需要安装Java JDK。 一.安装JDK 参考文章https://blog.csdn.net/weixin_41824534/article/details/104147067?spm1001.2014.3001.5502 二.Neo4j下载 进入Neo4j官网 选择下载中心 下滑选择Neo4j Deskto…

【学习笔记】生成式AI(ChatGPT原理,大型语言模型)

ChatGPT原理剖析 语言模型 文字接龙 ChatGPT在测试阶段是不联网的。 ChatGPT背后的关键技术&#xff1a;预训练&#xff08;Pre-train&#xff09; 又叫自监督式学习&#xff08;Self-supervised Learning&#xff09;&#xff0c;得到的模型叫做基石模型&#xff08;Founda…

Go重写Redis中间件 - Go实现Redis集群

Go实现Redis集群 这章的内容是将我们之前实现的单机版的Redis扩充成集群版,给Redis增加集群功能,在增加集群功能之前,我们先学习一下在分布式系统中引用非常广泛的技术一致性哈希,一致性哈希在我们项目里就应用在我们Redis集群的搭建这块 详解一致性哈希 Redis集群需求背…

实际工作中通过python+go-cqhttp+selenium实现自动检测维护升级并发送QQ通知消息(程序内测)

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 首先&#xff0c;今年比较忙没有多余时间去实操创作分享文章给大家&#xff0c;那就给大家分享下博主在实际工作中的一点点内容吧&#xff0c;就当交…

容器安全的常见风险与防护实践

运行在云平台上的容器产品&#xff0c;因为具备一个完整的可移植应用程序环境&#xff0c;能够帮助用户轻松地完成对应用程序的开关控制&#xff0c;提升应用程序的敏捷性&#xff0c;同时节约企业的IT建设成本。在巨大优势作用下&#xff0c;容器产品的采用率在2021年达到了新…