第6章 数组第4篇——指针、数组作为函数参数传递的方式

本文深入探讨了C语言中数组和指针作为函数参数的各种传递方式,包括一维数组、二维数组和多级指针的使用技巧。详细讲解了不同类型的参数如何正确传递,以及在函数调用过程中地址和值传递的区别。

说明:
(1)专题的目录是按照C语言中文网中的知识点顺序排列的,方便自己整体的知识笔记的归纳总结。
(2)本专题下面的博客全部用 专题六 开始
(3)怕什么真理无穷,进一步有进一步的欢喜。——胡适、
(4)参考:
博文01:https://blog.csdn.net/qq_21834027/article/details/85705266
博客02:https://blog.csdn.net/Laoynice/article/details/79196993

函数参数的传递:(实参传给形参)

(1)一般来说形参是什么就传给什么就行了。
(2)传递方向:实参传给形参, 好像只能实参传给形参。
(2)一般来数参数的传递是值传递,也就是说实参传给形参,形参发生改变时实参并不会改变(单向),但是数组在传递的时候是地址传递,只要形参发生了变化,实参也会发生变化(双向)。

博客01:

指针作为函数参数传递一维数组 (4种形式)

C 语言中声明了一个数组TYPE array[n],则数组名称array 就有了两重含义:
第一,它代表整个数组,它的类型是TYPE[n];
第二,它是一个常量指针,该指针的类型是TYPE*,该指针指向的类型是TYPE。

因此,指针作为函数参数传递一维数组有4种形式:
这里函数形参是数组 ,函数的实参是指针。

#include <stdio.h>
#define N 3
float average1(float * g); 
float average2(float grade[N]); 
int main()
{
	float grade[N]={60,75,80};	
	float * a = grade; //数组名类型是float *
	printf("学生的平均成绩是:%.3f\n",average1(grade)); //数组名传递给指针
	printf("学生的平均成绩是:%.3f\n",average2(grade)); //数组名传递给数组名
	printf("学生的平均成绩是:%.3f\n",average2(a));     //指针传递给数组名
	printf("学生的平均成绩是:%.3f\n",average1(a));     //指针传递给指针
}
float average1(float * g) //定义float *型的指针参数
{
	float *a=g; 
	float ave,sum=0;  
	for(;g<a+N;g++) {
		sum+=*g;	}
	return ave=sum/N;		
}
float average2(float grade[N])
{
	float ave,sum=0;  
	for(int i=0;i<N;i++){
		sum+=grade[i];}	
	return ave=sum/N;		
}

二维数组和二级指针的传递

1、定义指针变量int *型与二维数组的关系
在一维数组中,数组名表示的是数组第一个元素的地址,二维数组就是一维数组,例如:二维数组 a[3][4],就是有三个元素 a[0]、a[1]、a[2]的一维数组,所以数组 a 的第一个元素不是 a[0][0],而是 a[0],所以数组名 a 表示的不是元素a[0][0]的地址,而是 a[0]的地址,即:
a == &a[0];
而 a[0] 又是 a[0][0]的地址,即:

a[0] == &a[0][0];
1
所以二维数组名 a 和元素 a[0][0]的关系是:

a == &(&a[0][0]);
1
即二维数组名 a 是地址的地址,必须两次取值才可以取出数组中存储的数据。对于二维数组a[M][N],数组名 a 的类型为int()[N],所以如果定义了一个指针变量 p:int p;并希望这个指针变量指向二维数组 a,那么不能把 a 赋给 p,因为它们的类型不一样。要么把&a[0][0]赋给 p,要么把 a[0] 赋给 p,要么把a 赋给 p。因为 a==&(&a[0][0]),所以 a==(&(&a[0][0]))==&a[0][0]。
2、定义指针变量 int(
)[N] 型与二维数组的关系
当指针变量 p 定义成 int(*)[N] 型,这时就可以把 a 赋给 p。p == a;
那么此时p以“行”为单位 指向元素a[i][j]。数组名 a 代表第一个元素 a[0]的地址,则a+1就代表元素 a[1]的地址,即a+1==&a[1];a+2就代表 a[2]的地址,即 a+2==&a[2]……a+i就代表 a[i]的地址,即

a+i == &a[i];
p+i == &a[i];
(p+i) == a[i]; //等式两边作“”运算
*(p+i) + j == &a[i][j]; //等式两边同时加上j行

(1)当二级指针(例如:类型为int **)作为函数形参时,能作为函数实参的是二级指针,指针数组(例如:类型为int []),一级指针的地址 (例如:类型为int **)
(2)当数组指针作为函数形参时,能作为函数实参的是二维数组(例如:类型为int(
)[N]),数组指针(例如:类型为int(*)[N])
(3)当二维数组作为函数形参时,能作为函数实参的是二维数组,数组指针
(4)当指针数组作为函数形参时,能作为函数实参的是指针数组,二级指针,一级指针的地址

#include <stdio.h>
#include <stdlib.h>

void fun1(int **pp)
{
printf(“fun1\n”);
}
void fun2(int(*c)[5])
{
printf(“fun2\n”);
}
void fun3(int a[][5])
{
printf(“fun3\n”);
}
void fun4(int *pa[5])
{
printf(“fun4\n”);
}

int main()
{
int *pa[5]; //指针数组
int **pp = NULL; //二级指针
int *p = NULL; //一级指针
int a[5][5]; //二维数组
int b[5]; //一维数组
int(*c)[5] = &b; //数组指针
// 当二级指针作为函数形参时,能作为函数实参的是二级指针,指针数组,一级指针的地址
fun1(pa);
fun1(pp);
fun1(&p);
printf("\n");
// 当数组指针作为函数形参时,能作为函数实参的是二维数组,数组指针
fun2(a);
fun2©;
printf("\n");
// 当二维数组作为函数形参时,能作为函数实参的是二维数组,数组指针
fun3(a);
fun3©;
printf("\n");
// 当指针数组作为函数形参时,能作为函数实参的是指针数组,二级指针,一级指针的地址
fun4(pa);
fun4(pp);
fun4(&p);
printf("\n");
return 0;
}

博客02:

在学习C语言的过程中遇到数组作为参数传递的问题

一维数组:

#include <stdio.h>

int test2(int a[]){
for(int i=0;i<5;i++){
printf("%d",a[i]);
}
}
int main(){
int a[5] = {1,2,3,4,5},*p;
p = a;
test2(a);

}

这样我们可以很顺利的在test去遍历这个数组a,当然我们还可能传递指针:

int test1(int p){
for(int i=0;i<5;i++){
printf("%d",p[i]);//我们在这里还可以用)
(p+i)来输出数组中的值
}
}

int main(){
int a[5] = {1,2,3,4,5},*p;
p = a;
test1§;

}

一般来数参数的传递是值传递,也就是说实参传给形参,形参发生改变时实参并不会改变(单向),但是数组在传递的时候是地址传递,只要形参发生了变化,实参也会发生变化(双向)。
这样传递数组就会发现一个问题,我没有办法获取到数组的长度。获取数组的长度我们一般用:

sizeof(a)/sizeof(int)
int test2(int a[]){
int n = sizeof(a)/sizeof(int);
for(int i=0;i<n;i++){
printf("%d ",a[i]);
a[i]++;
}
}
我们会发现n的值一直是2!为什么会这样呢!?
因为,a是函数参数,到了本函数中,a只是一个指针(地址,系统在本函数运行时,是不知道a所表示的地址有多大的数据存储空间,这里只是告诉函数:一个数据空间首地址),所以,sizoef(a)的结果是指针变量a占内存的大小,一般在64位机上是8个字节。int类型是4个字节,所以,结果永远是2,因此,我们要向获取数组长度要怎么办呢?
我可以在初始化数组的地方获取到数组的长度,作为参数传递过来:

int test2(int a[],int n){
for(int i=0;i<n;i++){
printf("%d ",a[i]);
a[i]++;
}
}

int main(){
int a[5] = {1,2,3,4,5},*p;
int n = sizeof(a)/sizeof(int);
test2(a,n);

}

这样做我们可以获取到数组的长度。
二维数组:

二维数组作为参数传递是后我们不可以像以为数组那样直接,如:

void test1(int a[][]){

for(i = 0; i < 5; i++){
	for(j = 0; j < 5; j++){
		printf("%d ",a[i][j]);
	}
}

}

int main(){
int a[5][5],i,j;
for(i = 0; i < 5; i++){
for(j = 0; j < 5; j++){
a[i][j] = i*5 + (j +1);
}
}
test1(a);
return 0;
}

会发现编译都编译不通过,报“[Error] declaration of ‘a’ as multidimensional array must have bounds for all dimensions except the first”这个错,意思是多维数组的定义必须有一个除第一个之外的所有维度的边界,比如:

void test1(int a[][5]){

for(int i = 0; i < 5; i++){
	for(int j = 0; j < 5; j++){
		printf("%d ",a[i][j]);
	}
}

}
这样就OK了,但是我们是动态分配的数组不知道这个维度是多少的时候怎么办?这时候我们可以用指针当做一维数组来操作:
void test1(int *p,int n){
for(int i = 0; i < n; i++){
printf("%d ",p[j]);
}
}

int main(){
int a[5][5],i,j;
int p;
p = &a[0][0];
for(i = 0; i < 5; i++){
for(j = 0; j < 5; j++){
a[i][j] = i
5 + (j +1);
}
}
test1(p,25);
return 0;
}

这样我们发现不能更灵活的去定位到某一行某一列,这样我们需要手工改变寻址方式:
void test2(int m,int n,int **p){//m,n是行和列,
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
printf("%d ",*((int )p+ni+j));
}
}
}

int main(){
int a[5][5],i,j;

for(i = 0; i < 5; i++){
	for(j = 0; j < 5; j++){
		a[i][j] = i*5 + (j +1);
	}
}
test2(5,5,(int **)a);
return 0;	

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值