我大二刚学完C语言,之后用来写矩阵分析的时候想把二维矩阵直接传到函数里,结果出现了问题:形参实参类型不一致,无法通过编译!随后我就尝试各种方法(改变形参或者实参的格式),虽然最后通过了不过当时还是没理解原理。 后来自己把原因分析出来了,现在把它写出来,希望对碰到同样问题的朋友有所帮助。 转载请注明出处,谢谢! 几个跟参数有关的知识:C/C++的函数形参可以是普通类型、指针、引用。传值方式有两种:值传递(包括指针)、引用。 传参时从左往右,结合时从右往左,这个很重要(函数默认值与此有关)。 参数是指针时,我们一般通过两种方式实现读写:①移动指针 p++ ② p+i(目标位置)或者 p,等同于寻址的方式实现,他们实现时在内存里的操作: 一维 p+0(p[0]) p+1(p[1]) p+2(p[2]) ······ p+(n-1) (p[n-1]) 由于作图不太方便,下面的讲解就不附图了。 1、一维数组(指针) 做参数 一般指针做参数我就不多说了,专门搜这种问题的人应该都懂。 下面说一下一维数组: 一般传参情况:字符串、整型数组(举个特例,实际上字符串是字符型数组)。 字符串,我们一般用下面这种方式:
[cpp] view plain copy
- bool PrintStr(char* str)//char str[]也一样
- {
- if (NULL == str || "" == str)
- {
- return false;
- }
- for (int i = 0; i < strlen(str);i++)//就不考虑效率了,注意不要用sizeof
- {
- cout << str << " ";
- }
- while ('\0' != *str)//通过指针
- {
- cout << *str++ << " ";
- }
- return true;
- }
2、二维数组做参数
在一维中我们看到,遍历数组时必须有终止条件,可以是某种标志也可以规定移动次数。
当到二维的时候这种情况就更为复杂。很多人定义函数的时候将函数定义为双重指针,传参的时候直接把二维数组名放进去,例如:
[cpp] view plain copy
- //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(指针类型)移动;而在二维的时候则必须告诉函数一维以后的数据布局,这样它才不会读写错误甚至越界,一维部分也可以省略。 从抽象而且直接的角度,你也可以这么理解:一维的在内存中线性排列,读写的时候也是线性操作,所以通过了。当你需要处理的内容是非线性的时候,不仅仅要告诉函数我的内容是非线性的,还要告诉他非线性的特征:二维数组,数组每一维特征(空间大小)。 例如:
[cpp] view plain copy
- #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))。
[cpp] view plain copy
- #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:今天登陆发现编码出问题,重新编辑了一下
|