C语言如何给函数传二维数组?

很多人都遇到过函数不能接收二维数组的问题,网上的很多方法都特别麻烦。那么,有没有一种办法,可以像传一维数组那样传二维数组呢?有的。如果不想看分析的话,可以直接在目录中点“总结”

目录

问题引入

分析

直接使用指针?

强制转换类型?

转指针类型?

怎么在C++中使用?

总结


问题引入

C语言中,直接让函数接收二维数组的时候会报错

代码如下

void test(int a[][], int x_len, int y_len){
	for(int y = 0; y < y_len; y++){
		for(int x = 0; x < x_len; x++){
			printf("%d ", a[x][y]);
		}
		printf("\n");
	}
	return;
}

报错:

error: array type has incomplete element type
 void test(int a[][], int x_len, int y_len){

难道我们没有办法了吗?

分析

直接使用指针?

我们知道,数组名本身是个地址。如果让函数接收一个指针型变量,是不是就解决了?

代码如下

void test(int *a, int x_len, int y_len){
	for(int y = 0; y < y_len; y++){
		for(int x = 0; x < x_len; x++){
			printf("%d ", a[x][y]);
		}
		printf("\n");
	}
	return;
}

没想到还会报错

error: subscripted value is neither array nor pointer nor vector
    printf("%d ", a[x][y]);

强制转换类型?

看了报错信息,我想,是不是可以在访问的时候转换数据类型,让程序知道这是一个二维数组而不是指针型变量?

代码如下

void test(int *a, int x_len, int y_len){
	for(int y = 0; y < y_len; y++){
		for(int x = 0; x < x_len; x++){
			printf("%d ", ((int [y_len][x_len])a)[x][y]);
		}
		printf("\n");
	}
	return;
}

但是还会报错

error: cast specifies array type
    printf("%d ", ((int [y_len][x_len])a)[x][y]);

看来转不了类型

转指针类型?

我们知道,对指针定义时,int *中的"int"是对指针型变量存储的地址的访问规则,所以,我们新建一个指针型变量,改变它的访问规则,但是还是存储同一块地址空间,是不是就解决了?

代码如下

void test(int *a, int x_len, int y_len){
	int (*a_tmp)[y_len][x_len] = a;
	for(int y = 0; y < y_len; y++){
		for(int x = 0; x < x_len; x++){
			printf("%d ", a_tmp[x][y]);
		}
		printf("\n");
	}
	return;
}

我们编译一下,看到编译器提示

warning: initialization from incompatible pointer type
  int (*a_tmp)[y_len][x_len] = a;

这块只报了个警报,不是错误。所以我们可以看一下程序能不能运行正确

在main函数里写

int main(void){
	int a[4][4] = {
		{1, 2, 3, 4},
		{5, 6, 7, 8},
		{9, 10, 11, 12},
		{13, 14, 15, 16}
	};
    test(a, 4, 4);
	return 0;
}

程序运行结果:

6487504 6487568 6487632 6487696
6487520 6487584 6487648 6487712
6487536 6487600 6487664 6487728
6487552 6487616 6487680 6487744

很明显,这不是我们想要的数据。到底是哪错了呢?

我们知道,数组的名字就是数组的首地址,所以我们可以用int *表示int [](这种表示方法必须提前申请好空间并知道数组长度)。在这里面,我们写的是int (*)[][],可以表示int [][][],是三维数组,直接通过a_tmp[x][y]访问时,自然会出现问题。所以我们只需要改一下

void test(int *a, int x_len, int y_len){
	int (*a_tmp)[x_len] = a;
	for(int y = 0; y < y_len; y++){
		for(int x = 0; x < x_len; x++){
			printf("%d ", a_tmp[x][y]);
		}
		printf("\n");
	}
	return;
}

程序结果如下:
 

1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16

可以看到,我们成功地访问了数据。但是这些警告意味着不能在C++中使用

将编译命令改为:

gcc -x c++ test.c

表示语言为c++(gcc还可以编译java等语言) 

编译器报错:

error: cannot convert 'int*' to 'int (*)[x_len]' in initialization
  int (*a_tmp)[x_len] = a;
error: cannot convert 'int (*)[4]' to 'int*' for argument '1' to 'void test(int*, int, int)'
  test(a, 4, 4);

因为C语言的警告在C++中很可能是错误(C++表示,把警告变成错误,程序运行时就不会出错,即使程序员知道这不会出错)

怎么在C++中使用?

C++引入了泛型的概念,直接用就好了

将函数test改为

template<typename T>
void test(T a, int x_len, int y_len){
	for(int y = 0; y < y_len; y++){
		for(int x = 0; x < x_len; x++){
			printf("%d ", a[x][y]);
		}
		printf("\n");
	}
	return;
}

将main函数改为

int main(void){
	int a[4][4] = {
		{1, 2, 3, 4},
		{5, 6, 7, 8},
		{9, 10, 11, 12},
		{13, 14, 15, 16}
	};
	test<int [4][4]>(a, 4, 4);
	return 0;
}

运行结果:

1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16

泛型的概念不是本章的重点,这里不展开讲

总结

在C语言里,可以通过指针接收二维数组,代码如下:

void test(int *a, int x_len, int y_len){
	int (*a_tmp)[x_len] = a;
	for(int y = 0; y < y_len; y++){
		for(int x = 0; x < x_len; x++){
			printf("%d ", a_tmp[x][y]);
		}
		printf("\n");
	}
	return;
}

只需要在第一行加入

int (*a_tmp)[x_len] = a;

然后接下来就可以用a_tmp作为二维数组操作了

当然,这句话会引起警告,但警告不是错误。

警告信息是这样的:

warning: ……

错误是这样的:

error: ……

对于C++,我们可以用泛型传参,但不能像C语言那样

template<typename T>
void test(T a, int x_len, int y_len){
	for(int y = 0; y < y_len; y++){
		for(int x = 0; x < x_len; x++){
			printf("%d ", a[x][y]);
		}
		printf("\n");
	}
	return;
}

但是,调用函数时就应该像这样:

test<int [4][4]>(a, 4, 4);

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值