二维数组arr[][]与二级指针**arr 个人误区

        最近,前同事发问:“一个函数怎么返回二维数组指针,外层应用怎么接收这个指针才能以arr[][]这种形式去访问数组元素。”之前也没处理过类似的案例,误以为二维数组名与二级指针可以等价转换,实操后发现自己大错特错。

        先下结论:二维数组名不等价于二级指针!!!

 1. 动态分配的二维数组

        该数组的数组名是二级指针,以整型为例,其类型是int**,指向于一级指针int*。arr[]的地址步进大小是int*的大小。(该二维数组内存不一定连续)以32位系统为例,如下图。

       

        当int**定义的变量arr获取到动态分配的二维数组的数组名后,可以用arr[][]形式访问二维数组元素。

2. 静态定义的二维数组

        该数组的数组名是数组指针,以整型为例,其类型是int(*)[],指向一个整型的一维数组首地址,arr[]的一个地址步进是该一维整型数组的长度。(该二维数组内存连续)

        

        当int**定义的变量arr获取到静态定义的二维数组的数组名后,此时不能以arr[][]的形式访问。在32位系统中,假设地址0x8872de70和0x8872de74中存储的值都是2,a[0]此时是一级指针,就会指向0x00020002这个未知地址。然后访问a[0][0]时可能就会出现隐藏的未知错误或者死机,类似于下图64位系统的状态(二级指针已经获取到二维数组首地址,但是最终一级指针指向的地址错误)。

        当然,二级指针也可以用来访问静态定义的二维数组元素,找到了数组首地址后,需要通过地址偏移去寻址的方法,而不是用arr[][]去索引数组。

3. 如何访问静态定义的二维数组呢?

        可以通过定义数组指针int(*arr)[]的方式去获取二维数组名,访问静态定义的二维数组。

        此时个人采用两种方法(具体实现见测试例程):

  • 通过函数返回二维数组名获取数组指针。
  • 通过函数入参获取数组指针。
typedef uint16_t	U16;
typedef uint16_t*	PU16;
typedef uint16_t**	PPU16;

U16	g_array1_ui16[FIRSTNUM][SECONDNUM] = { {3,3},{3,3} };
U16	g_array2_ui16[FIRSTNUM][SECONDNUM] = { {4,4},{4,4} };

//返回数组指针
U16 (*g_Get2DArrayType2_vd(void))[SECONDNUM]
{
	return g_array2_ui16;
}

//数组指针入参赋值
static void g_Get2DArrayType1_vd(U16 (**parray)[SECONDNUM])
{
	*parray = g_array1_ui16;
}

        也可以通过typedef使得定义更加简单易懂。

typedef U16 (*P_ARRAY)[SECONDNUM];

//返回数组指针
//U16 (*g_Get2DArrayType2_vd(void))[SECONDNUM]
//{
//	return g_array2_ui16;
//}

P_ARRAY g_Get2DArrayType2_vd(void)
{
	return g_array2_ui16;
}

//数组指针入参赋值
//static void g_Get2DArrayType1_vd(U16(**parray)[SECONDNUM])
//{
//	*parray = g_array1_ui16;
//}

static void g_Get2DArrayType1_vd(P_ARRAY *parray)
{
	*parray = g_array1_ui16;
}

4. 测试例程

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

/* -------------------- 宏定义 ------------------------*/
#define FIRSTNUM	(2u)
#define SECONDNUM	(2u)

/* -------------------- 类型定义 ------------------------*/
typedef uint16_t	U16;
typedef uint16_t*	PU16;
typedef uint16_t**	PPU16;
typedef U16			(*P_ARRAY)[SECONDNUM];

typedef enum
{
	TEST_DEFAULT_ENUM = 0,
	TEST_INIT_U16_ARRAYBUF_ENUM,		//二维数组初始化赋值
	TEST_DYNALLOCATE_U16_PPBUF_ENUM,	//为二级指针指向的空间分配内存
	TEST_ARRAY_POINTER_TYPE1_ENUM,		//数组指针入参赋值
	TEST_ARRAY_POINTER_TYPE2_ENUM,		//数组指针返回赋值
	TEST_MAX_ENUM
}TEST_TYPE;



/* -------------------- 变量定义 ------------------------*/
U16		g_array1_ui16[FIRSTNUM][SECONDNUM] = { {3,3},{3,3} };
U16		g_array2_ui16[FIRSTNUM][SECONDNUM] = { {4,4},{4,4} };
PPU16	g_ppoint_ppui16 = NULL;


/* -------------------- api定义 ------------------------*/
//返回(二级指针强转)二维数组名
PPU16 g_GetStaU16BufPoint_ppui16(void)
{
	return (PPU16)g_array1_ui16;
}

//返回二级指针
PPU16 g_GetDynU16BufPoint_ppui16(void)
{
	return g_ppoint_ppui16;
}

//返回数组指针
//U16 (*g_Get2DArrayType2_vd(void))[SECONDNUM]
//{
//	return g_array2_ui16;
//}

P_ARRAY g_Get2DArrayType2_vd(void)
{
	return g_array2_ui16;
}

//数组指针入参赋值
//static void g_Get2DArrayType1_vd(U16 (**parray)[SECONDNUM])
//{
//	*parray = g_array1_ui16;
//}

static void g_Get2DArrayType1_vd(P_ARRAY *parray)
{
	*parray = g_array1_ui16;
}

//为二级指针和一级指针指向的空间动态分配内存
static void g_DynAllocatePPBuf_vd(void)
{
	g_ppoint_ppui16 = (PPU16)malloc(FIRSTNUM * sizeof(PU16));

	for (uint8_t i = 0; i < FIRSTNUM; i++)
	{
		g_ppoint_ppui16[i] = (PU16)malloc(SECONDNUM * sizeof(U16));

		for (uint8_t j = 0; j < SECONDNUM; j++)
		{
			g_ppoint_ppui16[i][j] = i * FIRSTNUM + j;
		}
	}
}


//测试接口
static void g_2LPointTest_vd(TEST_TYPE f_testtype_enum)
{
	PPU16 l_ppoint_ppui16 = NULL;
	U16 (*l_arrpoint)[SECONDNUM] = { NULL };

	switch (f_testtype_enum)
	{
	case TEST_INIT_U16_ARRAYBUF_ENUM:
	{
		printf("TEST_INIT_U16_ARRAYBUF\r\n");
		l_ppoint_ppui16 = g_GetStaU16BufPoint_ppui16();
	}
	break;

	case TEST_DYNALLOCATE_U16_PPBUF_ENUM:
	{
		printf("TEST_DYNALLOCATE_U16_PPBUF\r\n");
		g_DynAllocatePPBuf_vd();
		l_ppoint_ppui16 = g_GetDynU16BufPoint_ppui16();
	}
	break;

	case TEST_ARRAY_POINTER_TYPE1_ENUM:
	{
		printf("TEST_ARRAY_POINTER_TYPE1\r\n");
		g_Get2DArrayType1_vd(&l_arrpoint);
	}
	break;

	case TEST_ARRAY_POINTER_TYPE2_ENUM:
	{
		printf("TEST_ARRAY_POINTER_TYPE2\r\n");
		l_arrpoint = g_Get2DArrayType2_vd();
	}
	break;

	default:break;
	}

	for (uint8_t i = 0; i < FIRSTNUM; i++)
	{
		for (uint8_t j = 0; j < SECONDNUM; j++)
		{
			if (l_ppoint_ppui16 != NULL)
			{
				printf("l_ppoint_ppui16[%d][%d] = %d\r\n", i, j, l_ppoint_ppui16[i][j]);
			}

			if (l_arrpoint != NULL)
			{
				printf("l_arrpoint[%d][%d] = %d\r\n", i, j, l_arrpoint[i][j]);
			}
		}
	}
}


//主函数
int main()
{
	g_2LPointTest_vd(TEST_DYNALLOCATE_U16_PPBUF_ENUM);		//[OK]动态分配二维数组返回(强转二级指针)数组名----二级指针uint16**a 调用a[][]
	//g_2LPointTest_vd(TEST_INIT_U16_ARRAYBUF_ENUM);		//[ERR]静态定义二维数组返回数组名----二级指针uint16**a 调用a[][]
	g_2LPointTest_vd(TEST_ARRAY_POINTER_TYPE1_ENUM);		//[OK]静态定义二维数组返回数组名----数组指针uint16 (*a)[] 调用a[][]
	g_2LPointTest_vd(TEST_ARRAY_POINTER_TYPE2_ENUM);		//[OK]静态定义二维数组返回数组名----数组指针uint16 (*a)[] 调用a[][]

	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

98MHz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值