二维数组作为形参如何调用

         在做Leetcode第36题:有效的数独中,遇到这样一个问题:题目给出这样一个函数  bool isValidSudoku(char** board, int boardRowSize, int boardColSize),很显然三个形参分别是二维数组的数组名、行数和列数。在LeetCode中比较坑的是,不能进行调试,所以我要自己写主函数及输入,调用该函数来进行调试。问题就出在调用该函数这块,不知道如何对二维数组二级指针形式进行传参,看了很多关于此的博客以及书籍,下面在此进行总结下。

  • func (int str[2][2], int row, int col) 和 func (int str[][2], int row, int col)

#include <stdio.h>
#include <stdlib.h>
void func(int str[2][2],int row,int col)  //func(int str[][2],int row,int col)
{
       printf("%d",str[1][1]);
       //printf("%d",*(*(str + 1)+1));  //实现效果和上一条等价
       str[0][0] = -1;
}
int main()
{
       int a[2][2] = {1,2,3,4};
       func(a,2,2);
       printf(" %d",a[0][0]);
       getchar();
       return 0;
}

         这都是最标准的形式,一般正常都会马上想到这种形式。int a[][]这种分配是在栈上进行的,能够保证所有元素的地址空间连续。这样,array[i][j] 和 *(*(array +i) +j)是一样的,程序是知道array+i的i实际上偏移了i*N个单位。

  • func (int (*str)[2], int row, int col)

void func(int (*str)[2],int row,int col)
{
       printf("%d",str[1][1]);
       //printf("%d",*(*(str + 1)+1));   //和上一条代码等价
       str[0][0] = -1;
}
int main()
{
       int a[2][2] = {1,2,3,4};
       func(a,2,2);
       printf(" %d",a[0][0]);
       getchar();
       return 0;
}

        二维数组的实质是:以数组为元素的数组。a是一个有着2个数组类型元素的数组,它的每一个数组类型元素又是一个有着2个整型元素的数组。二维数组名a,等价于指向数组a[0]的指针,实际类型是int [2][2],在作为右值时可以被转化为int (*)[2]。int (*str)[2]这个语句的效果是,声明了 *str是一个拥有2个整型元素的数组,因此str就是一个指向这样数组的指针。str+i 程序知道实际上是偏移了i*col个单位,所以str[i][j] 和 *(*(str +i) +j)等价。

        但上面3种形式,无论是数组定义还是函数都不够泛用,两个维度在编译前就定好了,唯一可以做的就是把维度M、N声明为宏或者枚举类型,但这仍不能避免每次修改后都要重新编译。

  • func (int *str, int row, int col)

void func(int *str,int row,int col)
{
       printf("%d",*(str + 1*2 +1));   //人为解引用,输出str[1][1]
       *(str + 0*2 +0) = -1;
}
int main()
{
       int a[2][2] = {1,2,3,4};
       func(*a,2,2);  //二维数组名a,等价于指向数组a[0]的指针。*a等于数组a[0],数组名a[0]代表该数组的首元素地址
       printf(" %d",a[0][0]);
       getchar();
       return 0;
}

        虽然我们以表格形式显示二维数组,但实际上它们在计算机的内存中是按行主序连续存储的。这也导致了在二维数组a[2][2]中,使用下标array[1][0]和array[0][2]是访问的同一个元素,尽管后者的下标对于一个2*2矩阵来说是非法的,但这并不影响访问。调用这个函数时,需要把这个二维数组的首元素地址传给函数,并人为指导这个函数如何解引用,也就是把二维数组当做一维数组使。

  •  void func (int **str, int row, int col)

void func(int **str,int row,int col)
{
       printf("%d",str[1][1]);  //输出str[1][1]元素
       //printf("%d",*(*(str + 1)+1));   //和上一条代码等价
       str[0][0] = -1;
}
int main()
{
       int i;
       int **a;
       a = (int **)malloc(2 *sizeof(int *));
       for(i=0;i<2;i++)
              a[i] = (int *)malloc(2 *sizeof(int));

       a[0][0] = 1;
       a[0][1] = 2;
       a[1][1] = 3;
       a[1][1] = 4;
       func(a,2,2);

       printf(" %d",a[0][0]);
       getchar();
       return 0;
}

        上面一种虽然函数参数的限定降低了,但仍需要在栈上预先分配一定大小的二维数组,程序整体并不是完全的泛用。而我们在现实当中,经常要处理事先未知行数和列数的二维数组的函数 ,这也是为什么LeetCode要用二级指针的形式。 为了进一步提高泛用性,把二维数组空间的分配也动态化,使用malloc()在堆上分配空间。                                                                           

        我只是站在巨人的肩膀上,将我所看到写成这篇博客,有想更深入了解的,可以看看下面的资料。                                          c语言与陷阱  [美]Andrew koening 著    高巍 译                                                                                                                                        二维数组作为函数参数传递剖析:https://www.cnblogs.com/wuyuegb2312/archive/2013/06/14/3135277.html                                                                                                

 

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页