二维数组的传递和返回

指针和二维数组 

指针存储的是内存单元的地址,当使用引用运算符  *,或者变址运算符 [ ] 时才能将指针所指向的内存单元中的值取出。

指针有两个关键属性:

1.它存储的是内存地址

2.它存储的是什么类型变量的内存地址,这一点非常重要,这将决定对指针解引用时如何对它所指向的内存单元进行解读。

如果有这样定义的数组和指针变量

int *p;

int a[3]={1,2,3};

p=a;

那么它在内存中的图例是这样的:

                                             图一

变量名称实际就是内存地址的一个代号。

这里需要说明一下,数组名a其实不是一个变量,它是一个常量,即不可以进行加减操作,例如a++也就是a=a+1,这样的赋值操作是不允许的,这里只是为了说明方便称其为变量名。

数组地址的表达方式有以下几种:

a 表示数组a的首地址,也就是0x0000;

&a也可以表示数组的首地址,也是0x0000,

&a[0]也是数组元素的首地址,也是0x0000

例如:这些输出都将是数组a的首地址

 printf("%p\n",a);

printf("%p\n", &a);

printf("%p\n",&a[0]);

二维数组和指针

如果a是一个二维数组

int a[2][3]={{1,2,3},{4,5,6}};

并使用二级指针int **p指向它

int **p;

p=a;

二维数组a[2][3]是一个2行3列的矩阵,但是那只是方便人们理解,在计算机内存中没有二维,都是一维,它仍然是线性存储的。此时,内存中的分布是这样的。

                                           图二

       这样对指针p赋值的话,编译器会给出警告,因为p和a的类型不同,也就是p+1和a[1]指针向后移动的内存单元数不同。例如这里,p存储的是指针变量的地址也就是指向整形指针的指针变量,而整形指针占4个字节的位置,所以p+1将指向0x0004。而a是二维数组,它的元素是一个一维数组,长度为12个字节,a[1]将指向0x000C。

二维数组的首地址表示方法:

以下几种表示方法都可以表示首地址

a

&a

a[0]

&a[0]

但是要注意,二维数组的a[0]和一维数组中的a[0]不一样。

如图一所示,一维数组的元素是整形变量,它的a[0]是整形值1。

如图二所示,二维数组的元素是一个一维数组,也就是说,每个元素的长度是3*4=12个字节。a[0]表示的是一维数组的地址,也就是指向一维数组的指针,例如这里是0x0000,那么a[1]将是0x000C。

p是一个二级指针,将二维数组a的首地址赋值给它,那么它存储的地址将是0x0000。对p解引用一次*p,当然就取出了0x0000中的值,也就是1,如果执行语句printf(“%d”,(int)*p);  那么得到的结果是1,但这并不是二维数组的正确打开方式。

当对p再次解引用的时候,就出错了(*(*p)),它表示取出内存地址0x0001中的值,那将什么也不是,当然会出错。而且p每增加1,内存地址+4,a每增加1,内存地址+12,所以,无法直接使用二级指针p来正确操作二维数组a。

如何使用指针操作二维数组呢?

可以定义特殊的二级指针,int (*p)[3]来指向二维数组。它是一个二级指针,并且说明了一维数组中元素的个数是3个,这样p指针每+1,内存地址加3*4=12。()不能去掉,因为*比[]运算符优先级低。

p=a;   //p=0x0000

p++;   //p=0x000C

显示数组元素可以使用这几种写法:

p[行][列]

(* (p+行))[列]

*(* (p+行)+列)

以下程序段将可以正确打印二维数组

#include <stdio.h>


main()
{

	int i, j;
	int a[2][3] = { 
		{1,2,3},
	    {4,5,6} 
	};
	//定义一个特殊的二级指针
	int(*p)[3];

	p = a;

	printf("在主函数中打印数组a[2][3]\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			printf("% d ", p[i][j]);
		}
		printf("\n");
	}

}

如何将一个二维数组作为参数传递给函数:

形式参数要写明数组的数据类型,例如这里是int ,并且是指针变量,而且每行有3个数据,即:

int(*p)[3] ,这样内存每+1,内存单元增长3*4=12

然后,可以在函数中像使用普通数组那样使用指针变量p调用数组中的元素,例如p[i][j]

#include <stdio.h>


func(int(*p)[3])
{
	int i, j;

	printf("\n在函数func中打印数组a[2][3]\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			printf("% d ", p[i][j]);
		}
		printf("\n");
	}

}


main()
{
	int a[2][3] = { 
		{1,2,3},
	    {4,5,6} 
	};

	func(a);
}

如何返回一个二维数组

首先,函数的返回值类型要是一个二级指针的形式:

int **func2()

然后,函数的返回值用一个特殊的二级指针接收,改指针指出了每行元素的个数,例如:

int (*p)[3];

表示是一个整型的二级指针,它每行的数据是3个,也就是p每加1,内存单元增长12个。

#include <stdio.h>

int **func2()
{
	static int a[2][3] = {
	{1,2,3},
	{4,5,6},
	};

	return a;
}


main()
{

	int i, j;
	int a[2][3] = { 
		{1,2,3},
	    {4,5,6} 
	};
	//定义一个特殊的二级指针
	int(*p)[3];


	p = func2();
	printf("\n在主函数中打印函数传递过来的数组\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			printf("% d ", p[i][j]);
		}
		printf("\n");
	}

}

其实这里用一级指针也可以正确返回二维数组的首地址,但是要在主函数中用带有维度的特殊二级指针正确转化一下。

但是这种返回方式编译器会给出警告,如果不想看到警告信息,可以这样返回二维数组:

#include <stdio.h>

int  (*func3())[3]
{
	static int a[2][3] = {
	   {1,2,3},
	   {4,5,6},
	};

	return a;
}

main()
{

	int i, j;
	int a[2][3] = { 
		{1,2,3},
	    {4,5,6} 
	};
	//定义一个特殊的二级指针
	int(*p)[3];

	p = func3();

	printf("\n在主函数中打印函数传递过来的数组\n");
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			printf("% d ", p[i][j]);
		}
		printf("\n");
	}

}

这样,在返回值中指出了数组的维度,在接收值中也有相同的类型和维度,也就是指针类型完全相同,编译器就不会给出警告了。

传递二维数组,关键是要传递正确的数组首地址,并正确解读其中包含的维度。

参考链接:

https://blog.csdn.net/qq_33573235/article/details/79530792

https://www.cnblogs.com/zhixin/articles/3396789.html

https://blog.csdn.net/qq_39090164/article/details/79425247

https://www.cnblogs.com/qingergege/p/6917913.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值