C/C++中多维数组做参数情况的详细解释

我大二刚学完C语言,之后用来写矩阵分析的时候想把二维矩阵直接传到函数里,结果出现了问题:形参实参类型不一致,无法通过编译!随后我就尝试各种方法(改变形参或者实参的格式),虽然最后通过了不过当时还是没理解原理。

后来自己把原因分析出来了,现在把它写出来,希望对碰到同样问题的朋友有所帮助。

转载请注明出处,谢谢!

几个跟参数有关的知识:C/C++的函数形参可以是普通类型、指针、引用。传值方式有两种:值传递(包括指针)、引用。  传参时从左往右,结合时从右往左,这个很重要(函数默认值与此有关)。 

参数是指针时,我们一般通过两种方式实现读写:①移动指针 p++  ② p+i(目标位置)或者 p[i],等同于寻址的方式实现,他们实现时在内存里的操作: 一维 p+0(p[0]) p+1(p[1]) p+2(p[2]) ······ p+(n-1)  (p[n-1]) 由于作图不太方便,下面的讲解就不附图了。

1、一维数组(指针)  

做参数 一般指针做参数我就不多说了,专门搜这种问题的人应该都懂。

下面说一下一维数组: 一般传参情况:字符串、整型数组(举个特例,实际上字符串是字符型数组)。 字符串,我们一般用下面这种方式: 


bool PrintStr(char* str)//char str[]也一样
{
	if (NULL == str || "" == str)
	{
		return false;
	}
	for (int i = 0; i < strlen(str);i++)//就不考虑效率了,注意不要用sizeof
	{
		cout << str[i] << "  ";
	}
	while ('\0' != *str)//通过指针
	{
		cout << *str++ << "  ";
	}
	return true;
}



2、二维数组做参数



在一维中我们看到,遍历数组时必须有终止条件,可以是某种标志也可以规定移动次数。
当到二维的时候这种情况就更为复杂。很多人定义函数的时候将函数定义为双重指针,传参的时候直接把二维数组名放进去,例如:


//matrix 一维矩阵,m 矩阵行数,n矩阵列数
bool PrintMatrix(int** matrix,int m,int n)
{
	return true;
}


int main(void)
{
	int arr[3][3] = {1,2,3,4,5,6,7,8,9};
	
	PrintMatrix(arr,3,3);
	return 0;
}

这时候会提示错误:无法从int[3][3]转为int**,类型不兼容!

当然会不兼容!
函数传参的时候并不是你想的那样,他需要知道传入参数的特征:二维数组,数组每一维占多大。因为在函数里面读写实际是以*(p+i) 或者 p++的形式操作的。
二维数组如果那样操作会怎么样?我从第一行跳到第二行,你会这么写  p+1 或者 p++,可是函数怎么操作?
int**p,p+1每次移动sizeof(int*) ==4个字节,*p+1每次会移动sizeof(int)个字节;int p[3][3],p+1每次移动sizeof(p[0]) ==3*4个字节,*p+1每次会移动sizeof(int)个字节。它们是不能等同看待的,否则很容易出现内存错误,甚至系统崩溃。

所以在定义函数的时候如果是一维就可以省略,因为指针是按照sizeof(指针类型)移动;而在二维的时候则必须告诉函数一维以后的数据布局,这样它才不会读写错误甚至越界,一维部分也可以省略。

从抽象而且直接的角度,你也可以这么理解:一维的在内存中线性排列,读写的时候也是线性操作,所以通过了。当你需要处理的内容是非线性的时候,不仅仅要告诉函数我的内容是非线性的,还要告诉他非线性的特征:二维数组,数组每一维特征(空间大小)

例如:

#define M 3
#define N 3
//matrix 一维矩阵,m 矩阵行数,n矩阵列数;
//M、N必须是常数,而且N必须和传入的参数一致
bool PrintMatrix(int matrix[M][N], int m, int n)
{
	return true;
}
//matrix 一维矩阵,m 矩阵行数,n矩阵列数
//M甚至可以省略,因为有类型int
bool PrintMatrix(int matrix[][N], int m, int n)
{
	return true;
}


//matrix 一维矩阵,m 矩阵行数,n矩阵列数
//当然可以这么写,它本来就是这个样子!
bool PrintMatrix(int (*matrix)[N], int m, int n)
{
	return true;
}

按照上面的方式完美通过,Perfect!


3、多维数组做参数



多维数组和二维数组类似,只不过需要多加几个说明:

例如:int p[M][N][K] ,p[0][0][0+1] 指针移动移动一个类型长度4byte==sizeof(int),p[0][0+1][0] 指针移动一个维 K*sizeof(int),p[0+1][0][0]指针移动二维N*(K*sizeof(int))。

#define M 3
#define N 3
#define K 3
bool PrintMatrix(int(*matrix)[N][K], int m, int n,int k)
{
	return true;
}


4、总结



通过上面分析可以看出多维指针比较复杂,很容易出错。所以实际用的时候一般用其它方法绕过这个问题:数据整理为一维,处理完后再转成原形式;用结构体或类;一维一维的处理等。

PS:今天登陆发现编码出问题,重新编辑了一下



C语言二维数组可以用作参数传递给函数。传递二维数组的方法有两种:传递整个二维数组和传递二维数组的一行。 如果要传递整个二维数组函数,可以使用指针来操作。在函数参数列表,可以声明一个指向二维数组指针。例如,如果要传递一个3x3的二维数组,可以使用以下函数原型: void function(int arr[][3]) 通过指针解引用,可以在函数内部对二维数组进行操作。 如果要传递二维数组的一行给函数,可以使用指针数组来实现。指针数组是一个存储了指向一维数组指针数组。在函数参数列表,可以声明一个指向指针数组指针。例如,如果要传递一个3x3的二维数组的第一行,可以使用以下函数原型: void function(int *arr[]) 在函数内部,可以通过指针解引用来对一维数组进行操作。 无论是传递整个二维数组还是传递二维数组的一行,都可以在函数内部对二维数组进行修改,并且修改后的值在函数外部也会生效。这是因为在C语言数组的传递是通过指针来实现的,传递数组时传递的是数组的首地址,所以在函数内部对数组的修改直接作用于原数组。 总结来说,C语言可以使用二维数组作为函数参数,既可以传递整个二维数组,也可以传递二维数组的一行。通过指针解引用,可以在函数内部对二维数组进行操作,并且修改后的值在函数外部也会生效。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值