提示:文章
文章目录
前言
前期疑问:
本文目标:
一、背景
问题来源于上次考试做的一道题,题目中是在函数中将字符串分割存在二维数组中。二维数组是从函数外传进来的。但是我还想传出去。传出去的时候就出问题了。基于此,做了一下验证,其中已经写了一篇文章,在文章中验证了多次写法。最后经过多次拉扯,确定了二维数组传参和返回的一些问题。
在这篇文章中做了总结。总结为二维数组传参的三种方法。其中第三种方法还是有问题。
2024年8月21日13:59:47
今天又看了下书《C和指针》,对多维数组相关的知识看了一遍,加深了二维数组的了解,也完善了这篇文章。
二、对二维数组传参的总结
2.1
下面的代码主要是验证数组传参的方式,C和指针书籍Page159也介绍了这两种方式
第一种是DeliverArrayWithSecondPointer(int array[][6], int len)
第二种是int** DeliverArrayWithSecondPointer3(int (*array)[6], int len)
值得一提的是,这边还是验证了返回静态二维数组的方式
下面是具体的代码验证
#include "secondArrayDeliverReturn.h"
#include <stdio.h>
int** DeliverArrayWithSecondPointer3(int (*array)[6], int len);
int DeliverArrayWithSecondPointer(int array[][6], int len)
{
printf("DeliverArrayWithSecondPointer\n");
for(int i = 0; i < len; i++)
{
for(int j = 0; j < 6; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
printf("\n");
for(int i = 0; i < len; i++)
{
for(int j = 0; j < 6; j++)
{
printf("addr:%p ", &array[i][j]);
}
printf("\n");
}
printf("\n");
for(int i = 0; i < len; i++)
{
printf("addr:%p ", array[i]);
}
printf("\n");
return 0;
}
int** DeliverArrayWithSecondPointer2(int array[][6], int len)
{
printf("DeliverArrayWithSecondPointer2\n");
for(int i = 0; i < len; i++)
{
for(int j = 0; j < 6; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
printf("\n");
printf("打印全部地址\n");
for(int i = 0; i < len; i++)
{
for(int j = 0; j < 6; j++)
{
printf("addr:%p ", &array[i][j]);
}
printf("\n");
}
printf("\n");
printf("打印首地址\n");
for(int i = 0; i < len; i++)
{
printf("addr:%p ", array[i]);
}
printf("\n");
return (int **)array; //这边直接返回,用二级指针接收,会报错
}
int secondArrayDeliverReturn()
{
int array[5][6] = {0};
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 6; j++)
{
array[i][j] = i * j;
}
}
DeliverArrayWithSecondPointer(array, 5);
int **ptr = DeliverArrayWithSecondPointer2(array, 5);
for(int i = 0; i < 5; i++)
{
printf("**ptr addr:%p ", ptr + i);
}
printf("\n");
printf("静态二维数组,形参二维数组指针,返回二级指针,在函数外注意地址访问\n");
int **ptr3 = DeliverArrayWithSecondPointer3(array, 5);
printf("函数外访问\n");
for(int i = 0; i < 6; i++)
{
for(int j = 0; j < 6; j++)
{
printf("addr:%p ", ptr3 + i * 6 + j);
}
printf("\n");
}
printf("\n");
for(int i = 0; i < 6; i++)
{
for(int j = 0; j < 6; j++)
{
printf("addr:%p ", ptr3[i * j + j]);
}
printf("\n");
}
}
//DeliverArrayWithSecondPointer
//0 0 0 0 0 0
//0 1 2 3 4 5
//0 2 4 6 8 10
//0 3 6 9 12 15
//0 4 8 12 16 20
//
//addr:000000c0807ff5a0 addr:000000c0807ff5a4 addr:000000c0807ff5a8 addr:000000c0807ff5ac addr:000000c0807ff5b0 addr:00000
//0c0807ff5b4
//addr:000000c0807ff5b8 addr:000000c0807ff5bc addr:000000c0807ff5c0 addr:000000c0807ff5c4 addr:000000c0807ff5c8 addr:00000
//0c0807ff5cc
//addr:000000c0807ff5d0 addr:000000c0807ff5d4 addr:000000c0807ff5d8 addr:000000c0807ff5dc addr:000000c0807ff5e0 addr:00000
//0c0807ff5e4
//addr:000000c0807ff5e8 addr:000000c0807ff5ec addr:000000c0807ff5f0 addr:000000c0807ff5f4 addr:000000c0807ff5f8 addr:00000
//0c0807ff5fc
//addr:000000c0807ff600 addr:000000c0807ff604 addr:000000c0807ff608 addr:000000c0807ff60c addr:000000c0807ff610 addr:00000
//0c0807ff614
//
//addr:000000c0807ff5a0 addr:000000c0807ff5b8 addr:000000c0807ff5d0 addr:000000c0807ff5e8 addr:000000c0807ff600
// 从打印结果来看,DeliverArrayWithSecondPointer函数内部array变成了指向指针函数的指针一样。或者是按照数组名下标访问
//DeliverArrayWithSecondPointer2
//0 0 0 0 0 0
//0 1 2 3 4 5
//0 2 4 6 8 10
//0 3 6 9 12 15
//0 4 8 12 16 20
//
//addr:000000c0807ff5a0 addr:000000c0807ff5a4 addr:000000c0807ff5a8 addr:000000c0807ff5ac addr:000000c0807ff5b0 addr:00000
//0c0807ff5b4
//addr:000000c0807ff5b8 addr:000000c0807ff5bc addr:000000c0807ff5c0 addr:000000c0807ff5c4 addr:000000c0807ff5c8 addr:00000
//0c0807ff5cc
//addr:000000c0807ff5d0 addr:000000c0807ff5d4 addr:000000c0807ff5d8 addr:000000c0807ff5dc addr:000000c0807ff5e0 addr:00000
//0c0807ff5e4
//addr:000000c0807ff5e8 addr:000000c0807ff5ec addr:000000c0807ff5f0 addr:000000c0807ff5f4 addr:000000c0807ff5f8 addr:00000
//0c0807ff5fc
//addr:000000c0807ff600 addr:000000c0807ff604 addr:000000c0807ff608 addr:000000c0807ff60c addr:000000c0807ff610 addr:00000
//0c0807ff614
//
//addr:000000c0807ff5a0 addr:000000c0807ff5b8 addr:000000c0807ff5d0 addr:000000c0807ff5e8 addr:000000c0807ff600
//000000c0807ff5a0 000000c0807ff5a8 000000c0807ff5b0 000000c0807ff5b8 000000c0807ff5c0
// 从打印结果来看,DeliverArrayWithSecondPointer2函数内部将array返回用二级指针接收,会报错。强转之后在函数外部不能正常访问。会丢失二维数组信息。
// 目前静态数组经过传参再返回,只有在函数内部创建一个指针数组,再返回指针数组的地址,用二级指针接收可以实现。
// 还有一个问题就是二维数组传参,二维数组指针作为形参之前写的不对
// 下面验证一下
int** DeliverArrayWithSecondPointer3(int (*array)[6], int len)
{
printf("DeliverArrayWithSecondPointer3\n");
for(int i = 0; i < len; i++)
{
for(int j = 0; j < 6; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
printf("\n");
for(int i = 0; i < len; i++)
{
for(int j = 0; j < 6; j++)
{
printf("addr:%p ", &array[i][j]);
}
printf("\n");
}
printf("\n");
for(int i = 0; i < len; i++)
{
printf("addr:%p ", array[i]);
}
printf("\n");
return (int **)array;
}
// DeliverArrayWithSecondPointer3打印信息
//尝试直接返回静态二维数组强制转换的二级指针,在函数外注意地址访问,是会出错的。出错的点在于即便我使用形如ptr3 + i * 6 + j方式,偏移的长度是64位指针长度8,而二维数组的偏移是4
//静态二维数组,形参二维数组指针,返回二级指针,在函数外注意地址访问
//DeliverArrayWithSecondPointer3
//0 0 0 0 0 0
//0 1 2 3 4 5
//0 2 4 6 8 10
//0 3 6 9 12 15
//0 4 8 12 16 20
//
//addr:0000009b6d5ff880 addr:0000009b6d5ff884 addr:0000009b6d5ff888 addr:0000009b6d5ff88c addr:0000009b6d5ff890 addr:00000
//09b6d5ff894
//addr:0000009b6d5ff898 addr:0000009b6d5ff89c addr:0000009b6d5ff8a0 addr:0000009b6d5ff8a4 addr:0000009b6d5ff8a8 addr:00000
//09b6d5ff8ac
//addr:0000009b6d5ff8b0 addr:0000009b6d5ff8b4 addr:0000009b6d5ff8b8 addr:0000009b6d5ff8bc addr:0000009b6d5ff8c0 addr:00000
//09b6d5ff8c4
//addr:0000009b6d5ff8c8 addr:0000009b6d5ff8cc addr:0000009b6d5ff8d0 addr:0000009b6d5ff8d4 addr:0000009b6d5ff8d8 addr:00000
//09b6d5ff8dc
//addr:0000009b6d5ff8e0 addr:0000009b6d5ff8e4 addr:0000009b6d5ff8e8 addr:0000009b6d5ff8ec addr:0000009b6d5ff8f0 addr:00000
//09b6d5ff8f4
//
//addr:0000009b6d5ff880 addr:0000009b6d5ff898 addr:0000009b6d5ff8b0 addr:0000009b6d5ff8c8 addr:0000009b6d5ff8e0
//函数外访问
//addr:0000009b6d5ff880 addr:0000009b6d5ff888 addr:0000009b6d5ff890 addr:0000009b6d5ff898 addr:0000009b6d5ff8a0 addr:00000
//09b6d5ff8a8
//addr:0000009b6d5ff8b0 addr:0000009b6d5ff8b8 addr:0000009b6d5ff8c0 addr:0000009b6d5ff8c8 addr:0000009b6d5ff8d0 addr:00000
//09b6d5ff8d8
//addr:0000009b6d5ff8e0 addr:0000009b6d5ff8e8 addr:0000009b6d5ff8f0 addr:0000009b6d5ff8f8 addr:0000009b6d5ff900 addr:00000
//09b6d5ff908
//addr:0000009b6d5ff910 addr:0000009b6d5ff918 addr:0000009b6d5ff920 addr:0000009b6d5ff928 addr:0000009b6d5ff930 addr:00000
//09b6d5ff938
//addr:0000009b6d5ff940 addr:0000009b6d5ff948 addr:0000009b6d5ff950 addr:0000009b6d5ff958 addr:0000009b6d5ff960 addr:00000
//09b6d5ff968
//addr:0000009b6d5ff970 addr:0000009b6d5ff978 addr:0000009b6d5ff980 addr:0000009b6d5ff988 addr:0000009b6d5ff990 addr:00000
//09b6d5ff998
//
//addr:0000000000000000 addr:0000000000000000 addr:0000000000000000 addr:0000000100000000 addr:0000000300000002 addr:00000
//00500000004
//addr:0000000000000000 addr:0000000000000000 addr:0000000300000002 addr:0000000200000000 addr:0000000a00000008 addr:00000
//00900000006
//addr:0000000000000000 addr:0000000100000000 addr:0000000200000000 addr:0000000300000000 addr:0000000400000000 addr:00007
//ff6198ceff7
//addr:0000000000000000 addr:0000000300000002 addr:0000000a00000008 addr:0000000400000000 addr:0000009b6d5ff880 addr:00000
//00500000006
//addr:0000000000000000 addr:0000000500000004 addr:0000000900000006 addr:00007ff6198ceff7 addr:0000000500000006 addr:00007
//ff6198cf4f7
//addr:0000000000000000 addr:0000000200000000 addr:0000000400000000 addr:000000036d5ff958 addr:0000009b6d5ff9d0 addr:00000
//00000000001
2.2
三、静态二维数组返回方式
静态二维数组返回方式目前看只有一种,就是在函数内存创建静态指针数组,将二维数组的首地址赋值给指针数组,然后使用二级指针返回,在函数外部解析地址。
四、指针+1的概念
还是疑惑为什么函数DeliverArrayWithSecondPointer3返回二级指针ptr3,对ptr3进行+1操作偏移地址为8,为什么不是偏移4,偏移4的话就能正确访问二维数组了,下面代码是验证这一问题
printf("打印二级指针+1的地址\n");
printf("%p\n",ptr3);
printf("%p\n",ptr3 + 1);
printf("sizeof(ptr3):%d\n",sizeof(ptr3));
//打印结果
//打印二级指针+1的地址
//000000f3b33ff980
//000000f3b33ff988
//sizeof(ptr3):8
查找资料,指针+1偏移的长度取决于指针指向的数据类型是什么。
总结
未完待续