二维数组参数的五种形式
二维数组传参
一、背景
之前整理过好几篇关于二维数组传参的文章。
后面在一次考试过程中传二维数组的时候还是卡住了。
今天写leetcode的代码,又涉及到二维数组传参,leetCode939,示例代码如下
int minAreaRect(int** points, int pointsSize, int* pointsColSize) {
}
二、解析
按照题目形式二级指针,我尝试传递数组并使用二级指针接收,出现问题
因为实例代码传数组是二级指针,我在main函数中实名了一个二维数组,代码执行过程中会报错。代码如下:
int minAreaRect(int **points, int pointsSize, int *pointsColSize) {
for (int i = 0; i < pointsSize; i++) {
for (int j = 0; j < *pointsColSize; j++) {
printf("%d ", *(*(points + i) + j));
}
}
printf("\n");
return 0;
}
int main() {
int num[5][2] = {{1, 1},
{1, 3},
{3, 1},
{3, 3},
{2, 2}};
int pointsColSize = 2;
int result = minAreaRect((int**)num, sizeof(num) / sizeof(num[0]), &pointsColSize);
printf("result: %d\n", result);
}
// 打印信息
// 进程已结束,退出代码为 -1073741819 (0xC0000005)
出现问题。
这时候看之前写的文章。在文章二维数组的使用中,文章静态数组段落代码块line60行,也说明了静态数组不能转换成二级指针使用。
那我就是记错了。我之前一直以为静态数组可以转成二级指针,但是这是错误的。静态数组不能强制转换成二级指针。
并且也尝试搜了下其他文章。看到这篇文章,[转]二维数组和二级指针的传递问题,文章中提到了三种二维数组传参的方式。
一、二级指针使用方式
那么问题来了。什么情况可以使用二级指针传递数组?
有两种情况
1、数组是二级指针数组
2、数组是指针数组
下面是针对上述两种情况的代码演示
方式一、数组是二级指针数组
int main() {
int num[5][2] = {{1, 1},
{1, 3},
{3, 1},
{3, 3},
{2, 2}};
// 二级指针数组
int **numCopy = (int **) malloc(sizeof(int *) * 5); // 申请指针数组地址
for (int i = 0; i < 5; i++) {
numCopy[i] = (int *) malloc(sizeof(int) * 2); // 指针数组成员对应指针的内存申请
numCopy[i] = num[i];
}
// 申请好内存赋值
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 2; j++) {
numCopy[i][j] = num[i][j];
}
}
int pointsColSize = 2;
int result = minAreaRect((int**)numCopy, sizeof(num) / sizeof(num[0]), &pointsColSize);
printf("result: %d\n", result);
}
// 打印信息
// 1 1 1 3 3 1 3 3 2 2
// result: 0
方式二:指针数组形式
int main() {
int num[5][2] = {{1, 1},
{1, 3},
{3, 1},
{3, 3},
{2, 2}};
// 指针数组形式
int *numCopy[5];
for (int i = 0; i < 5; i++) {
//注意这边没有指针申请内存,但是下面语句将指针指向了静态数组地址。
numCopy[i] = num[i];
}
int pointsColSize = 2;
int result = minAreaRect((int**)numCopy, sizeof(num) / sizeof(num[0]), &pointsColSize);
printf("result: %d\n", result);
}
// 打印信息
// 1 1 1 3 3 1 3 3 2 2
// result: 0
上述两种形式其实都是讲指针转换成二级指针。
也就是指针才能转换成二级指针,数组名不能转成二级指针。
然后联想到自己平时写C++代码其实没怎么遇到这种情况。实际上其实对于C++代码而言,是不需要使用数组的,而更多的是使用vector容器,使用起来更加方便简单。
实际上对于上面的演示代码,读者可能很疑惑,为什么已经有了数组num了,为什么还要将静态数组num拷贝到指针对应内存中?
事实上确实没有这个必要。完全是用于演示,不过实际代码中会使用到,先构建二级指针指向的数组,或者构建指针数组,再传参。
关于二维数组解引用方式:
除了上述方式,下面形式也可以
int minAreaRect(int **points, int pointsSize, int *pointsColSize) {
for (int i = 0; i < pointsSize; i++) {
for (int j = 0; j < *pointsColSize; j++) {
printf("%d ", points[i][j]);
}
}
printf("\n");
return 0;
}
关于字符串保存在静态数据区的问题。
上述方式二中,数组成员对应的指针没有申请内存,而是指向了数组num对应的内存地址。
但是对于字符串而言,却不需要这一步。因为字符串本身就有内存,存储区域为静态数据区。
下面是演示代码:
int showStr(char **str, int strSize) {
for (int i = 0; i < strSize; i++) {
printf("%s\n", str[i]);
}
return 0;
}
int main() {
char *strArray[] = {"hello", "world", "kevin"};
showStr(strArray, sizeof(strArray) / sizeof(strArray[0]));
return 0;
}
// 打印信息
//hello
//world
//kevin
即上述可以直接使用指针数组指向多个字符串。
下面是静态数组传参方式
二、静态二维数组传参
三种方式
首先说明有三种方式:
1、数组原型传参
2、省略数组行
3、传数组指针
第一种方式:数组原型传参
int diliver(int points[5][2], int pointsSize, int pointsColSize) {
for (int i = 0; i < pointsSize; i++) {
for (int j = 0; j < pointsColSize; j++) {
printf("%d ", *(*(points + i) + j)); // printf("%d ", points[i][j]); 上述两种方式都可以
}
printf("\n");
}
return 0;
}
int main() {
int num[5][2] = {{1, 1},
{1, 3},
{3, 1},
{3, 3},
{2, 2}};
diliver(num, 5, 2);
return 0;
}
// 打印结果
// 1 1
// 1 3
// 3 1
// 3 3
// 2 2
第二种方式:数组省略一维的长度
int diliver(int points[5][2], int pointsSize, int pointsColSize) {
for (int i = 0; i < pointsSize; i++) {
for (int j = 0; j < pointsColSize; j++) {
printf("%d ", *(*(points + i) + j)); // printf("%d ", points[i][j]); 上述两种方式都可以
}
printf("\n");
}
return 0;
}
int main() {
int num[5][2] = {{1, 1},
{1, 3},
{3, 1},
{3, 3},
{2, 2}};
diliver(num, 5, 2);
return 0;
}
// 打印结果
// 1 1
// 1 3
// 3 1
// 3 3
// 2 2
第三种方式:传数组指针
int diliver(int (*points)[2], int pointsSize, int pointsColSize) {
for (int i = 0; i < pointsSize; i++) {
for (int j = 0; j < pointsColSize; j++) {
printf("%d ", *(*(points + i) + j)); // printf("%d ", points[i][j]); 上述两种方式都可以
}
printf("\n");
}
return 0;
}
int main() {
int num[5][2] = {{1, 1},
{1, 3},
{3, 1},
{3, 3},
{2, 2}};
diliver(num, 5, 2);
return 0;
}
// 打印结果
// 1 1
// 1 3
// 3 1
// 3 3
// 2 2
以上就是二维数组传参的所有方式。
三、问题探究
1、sizeof
关于sizeof对数组名和指针使用的区别
int main() {
int num[5][2] = {{1, 1},
{1, 3},
{3, 1},
{3, 3},
{2, 2}};
printf("sizeof(num):%d\n", sizeof(num));
printf("sizeof(num) / sizeof(num[0]):%d\n", sizeof(num) / sizeof(num[0]));
}
// 打印信息
// sizeof(num):40
// sizeof(num) / sizeof(num[0]):5
2、一维数组传参
当然一维数组传参原理一样,下次可以一起整理