直接上代码

#include <stdio.h>

void func(int **b)
{
	printf("%d\n", b[0][0]);
}

int main(void)
{
	int b[][2] = {
		{1, 2},
		{3, 4},
	};

	func(b);
}

编译运行

$ gcc -Wall main.c ;./a.out

不出预料,出错了:

main.c:3:6: note: expected ‘int **’ but argument is of type ‘int (*)[2]’
void func(int **b)
     ^
Segmentation fault (core dumped)

解释: ‘int **‘‘int (*)[]’ 是并不相同的两种类型,前者是指向指针的指针,后者是指向数组的指针。‘int (*)[2]’ 就是指向元素数为 2 的数组的指针。
它们作为二维数组时的区别就是,‘int **‘ 不能说明列的大小,C 程序并不关心行,但是列的大小不确定时,就不能确定指针所指的对象和占用的存储空间,所以访问二维数组时就会出错。

根据提示,把参数 b 换为 ‘int (*)[2]’,2 即为二维数组 b 的列数:

void func(int (*b)[2])
{
	/* ... */
}

编译运行:

1

正常了。但是,如果要传入的数组 b 的列数不确定怎么办呢,这时如何定义函数 func()?很自然的想到增加一个参数:

void func(int (*b)[], int col)
{
	printf("%d\n", b[0][col - 1]);
}

int main(void)
{
	int b[][2] = {/* ... */};

	func(b, 2);
}

然后:

main.c:5:2: error: invalid use of array with unspecified bounds
  printf("%d\n", b[0][col]);
  ^

实际上,原因已经说明过了,因为 ‘int (*)[]’ 没有包含列数,所以没有办法确定数组边界。那么,就只能构造一个有边界的二维数组了:

void func(int (*b)[], int col)
{
	int (*a)[col] = b;

	printf("%d %d\n", a[0][0], a[0][col - 1]);
}

运行 OK:

1 2

用这个办法,就可以将大小可变的矩阵作为参数传递了。 例: 稀疏矩阵压缩及转置