zoukankan      html  css  js  c++  java
  • 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 ('' != *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:今天登陆发现编码出问题,重新编辑了一下



  • 相关阅读:
    问题:Controller中Response的用法
    C#中字符串前缀@和$
    C#中Viewbag和ViewData的区别
    C#中Session和Cache的区别
    try catch捕获异常
    C#开发中,添加错误日志功能,并自定义错误页面
    数据库索引中,聚集索引和非聚集索引有何区别?
    String和StringBuilder的区别?
    C#函数,引用类型作为值参数,改变参数值后,形参也会改变.重新给实参赋值后,形参则不会改变.
    jQuery操作radio选中和取值
  • 原文地址:https://www.cnblogs.com/qingchuwudi/p/12077744.html
Copyright © 2011-2022 走看看