C语言之三维数组

前言:

之前学习C语言的时候仅仅是掌握了二维数组,但是并没有对三维数组进行研究,此情此景. . .那就让我对去年研究的三维数组的相关知识发布一下,也许能够帮到你!实际上,当你阅读此篇文章时,我假设你已经对C语言的二维数组非常熟悉了,并且非常熟悉数组与指针之间的关系,如果没有达到此要求,那直接翻篇,不要看,我估摸着你看不大懂。当然了,也可以尝试看看!

一、先看看三维数组长啥样吧

《C语言之三维数组》
这个图是我网上拷贝的,搞这张图片的大哥,,希望你手下留情,不要打我哦,我胆子小。

二、首先看下三维数组的遍历

#include "stdio.h"
void main(){ 
	//三维数组
	int a[2][3][4] =
	{ 
		{ 
			{ 6,2,3,4},
			{ 5,11,15,8},
			{ 8,20,10,11}
		},
		{ 
			{ 0,0,3,4},
			{ 5,0,7,8},
			{ 8,1,18,31}
		}
	};
	int i, j, k;
	int(*p)[3][4];					//p是指向二维数组的指针 
	p = a;							//p指向三维数组的0行 (也即p指向一个二维数组) 
	//p=&a[0]; //与上等价
	printf(" 【三维数组的遍历】:\n\n");
	for (i = 0; i < 2; i++) { 
		for (j = 0; j < 3; j++) { 
			for (k = 0; k < 4; k++) { 
//元素值遍历 : 
				printf("a[%d][%d][%d]=%-9d ", i, j, k, *(*(*(p + i) + j) + k));//元素值 
				printf("a[%d][%d][%d]=%-9d ", i, j, k, *(*(a[i] + j) + k));	//元素值 
				printf("a[%d][%d][%d]=%-9d ", i, j, k, *(a[i][j] + k));		//元素值 
				printf("a[%d][%d][%d]=%-9d ", i, j, k, *(&a[i][j][k]));		//元素值 
				printf("a[%d][%d][%d]=%-9d ", i, j, k, a[i][j][k]);			//元素值 
				printf("a[%d][%d][%d]=%-9d\n", i, j, k, p[i][j][k]);			//元素值 
				
//元素地址遍历: 
// printf("&a[%d][%d][%d]=%-9d ", i, j, k, *(*(p + i) + j) + k); //元素地址 
// printf("&a[%d][%d][%d]=%-9d ", i, j, k, *(a[i] + j) + k); //元素地址
// printf("&a[%d][%d][%d]=%-9d ", i, j, k, a[i][j] + k); //元素地址
// printf("&a[%d][%d][%d]=%-9d\n", i, j, k, &a[i][j][k]); //元素地址

//由于少了整体括号,所以出现错误的遍历,只有a[0][0][0],a[0][1][0],a[0][2][0],a[1][0][0],a[1][1][0],a[1][2][0]正确
//
// printf("a[%d][%d][%d]=%-9d ", i, j, k, **(*(p + i) + j) + k); //错误,由于最外层少括号 
// printf("a[%d][%d][%d]=%-9d ", i, j, k, **(a[i] + j) + k); //错误,由于最外层少括号 
// printf("a[%d][%d][%d]=%-9d ", i, j, k, *a[i][j] + k); //错误,由于最外层少括号 
// printf("a[%d][%d][%d]=%-9d\n", i, j, k, *&a[i][j][k]); //正确 
			}
			printf("\n");
		}
	}
}

【【【注意】】】:在对地址取*运算时, 一定要加“()”,也即对地址整体取“括号”,然后*,否则将得不到期望值!
比如:*(a[i] + j) + k表示 & a[i][j][k]  ====> 也即元素a[i][j][k]的地址。

对其取*运算应该是*(*(a[i] + j) + k) ====> 表示是元素a[i][j][k]的值。

而不能写成这样:**(a[i] + j) + k ====> 并不是我们期望的各元素值!

当然了:对于&a[i][j][k]求其元素值时,可以对其直接取*,不必在意()整体的问题!



【分析如下】:
for (i = 0; i < 2; i++) { 
	for (j = 0; j < 3; j++) { 
		for (k = 0; k < 4; k++) { 
			printf("a[%d][%d][%d]=%-9d ", i, j, k, **(a[i] + j) + k);		//**(*(p + i) + j) + k, *a[i][j] + k同理
		}
	}
}


【输出结果】:[6],7,8,9  [5],6,7,8  [8],9,10,11  [0],1,2,3  [5],6,7,8  [8],9,10,11
【很明显】:只有a[0][0][0], a[0][1][0], a[0][2][0], a[1][0][0], a[1][1][0], a[1][2][0]正确,其他值并不是个元素的值!
【假如】:
	  i=0, j=0, k=0; ==> **(a[i]+j)+k ===> **(a[0]+0)+0 ===> *(*(a[0]+0))+0 ===> *(a[0][0])+0 ===>*(a[0][0])+0 ===> *(&a[0][0][0])+0= 6
	  i=0, j=0, k=1; ==> **(a[i]+j)+k ===> **(a[0]+0)+1 ===> *(*(a[0]+0))+1 ===> *(a[0][0])+1 ===>*(a[0][0])+1 ===> *(&a[0][0][0])+1= 7
      i=0, j=0, k=2; ==> **(a[i]+j)+k ===> **(a[0]+0)+2 ===> *(*(a[0]+0))+2 ===> *(a[0][0])+2 ===>*(a[0][0])+2 ===> *(&a[0][0][0])+2= 8
	  i=0, j=0, k=3; ==> **(a[i]+j)+k ===> **(a[0]+0)+3 ===> *(*(a[0]+0))+3 ===> *(a[0][0])+3 ===>*(a[0][0])+3 ===> *(&a[0][0][0])+3= 9
其他情况亦是如此!

三、看下三维数组中的地址系列

#include "stdio.h"
void main()
{ 
	int a[2][3][4] =	
		{ 
			{ 
				{ 6,2,3,4},
				{ 5,11,15,8},
				{ 8,20,10,11}
			},
			{ 
				{ 0,0,3,4},
				{ 5,0,7,8},
				{ 8,1,18,31}
			}
		};
//相当于有2个二维数组a[0] [3][4]和a[1] [3][4]------其中a[0]和a[1]为二维数组名! 

//【【【第1个二维数组】】】: 【a[0]相当于二维数组的名字】
	printf("【第1个二维数组】:\n");
	printf("0行首地址: %d\n", &a[0][0]);	//0行首地址 (a[0][0]相当于一维数组的名字) 【int (*)[4]型】
	printf("1行首地址: %d\n", &a[0][1]);	//1行首地址 (a[0][0]相当于一维数组的名字) 【int (*)[4]型】
	printf("2行首地址: %d\n\n", &a[0][2]);	//2行首地址 (a[0][0]相当于一维数组的名字) 【int (*)[4]型】

	printf("0行首地址: %d\n", a[0]);		//0行首地址 (a[0][0]相当于一维数组的名字) 【int (*)[4]型】
	printf("1行首地址: %d\n", a[0] + 1);	//1行首地址 (a[0][0]相当于一维数组的名字) 【int (*)[4]型】
	printf("2行首地址: %d\n\n", a[0] + 2);	//2行首地址 (a[0][0]相当于一维数组的名字) 【int (*)[4]型】
	
	
	printf("0行0列首地址: %d\n", a[0][0]);		//0行0列元素地址 (a[0][0]相当于一维数组的名字) 
	printf("1行0列首地址: %d\n", a[0][1]);		//1行0列元素地址 (a[0][0]相当于一维数组的名字)
	printf("2行0列首地址: %d\n\n", a[0][2]);	//2行0列元素地址 (a[0][0]相当于一维数组的名字) 
	

	printf("0行0列元素地址: %d\n", &a[0][0][0]);//0行0列元素地 (a[0][0]相当于一维数组的名字) 
	printf("1行0列元素地址: %d\n", &a[0][1][0]);//1行0列元素地 (a[0][0]相当于一维数组的名字) 
	printf("2行0列元素地址: %d\n\n", &a[0][2][0]);//2行0列元素地址(a[0][0]相当于一维数组的名字) 

	printf("0行0列元素值: %d\n", a[0][0][0]);//0行0列元素值 (a[0][0]相当于一维数组的名字) 
	printf("1行0列元素值: %d\n", a[0][1][0]);//1行0列元素值 (a[0][0]相当于一维数组的名字) 
	printf("2行0列元素值: %d\n\n", a[0][2][0]);//2行0列元素 (a[0][0]相当于一维数组的名字) 

	printf("0行0列元素值: %d\n", *(*(a[0] + 0) + 0));//a[0][0][0] (a[0]相当于二维数组的名字) 
	printf("1行0列元素值: %d\n", *(*(a[0] + 1) + 0));//a[0][1][0] (a[0]相当于二维数组的名字) 
	printf("2行0列元素值: %d\n\n", *(*(a[0] + 2) + 0));//a[0][2][0] (a[0]相当于二维数组的名字) 


//【【【第2个二维数组】】】: 【a[1]相当于二维数组的名字】
	printf("\n【第2个二维数组】:\n");
	printf("0行首地址: %d\n", &a[1][0]);	//0行首地址 【int (*)[4]型】
	printf("1行首地址: %d\n", &a[1][1]);	//1行首地址 【int (*)[4]型】
	printf("2行首地址: %d\n\n", &a[1][2]);	//2行首地址 【int (*)[4]型】

	printf("0行首地址: %d\n", a[1]);		//0行首地址 【int (*)[4]型】
	printf("1行首地址: %d\n", a[1] + 1);	//1行首地址 【int (*)[4]型】
	printf("2行首地址: %d\n\n", a[1] + 2);	//2行首地址 【int (*)[4]型】

	printf("0行0列元素地址: %d\n", &a[1][0][0]);//0行0列元素地址
	printf("1行0列元素地址: %d\n", &a[1][1][0]);//1行0列元素地址
	printf("2行0列元素地址: %d\n\n", &a[1][2][0]);//2行0列元素地址

	printf("0行0列元素值: %d\n", a[1][0][0]);//0行0列元素值 
	printf("1行0列元素值: %d\n", a[1][1][0]);//1行0列元素值 
	printf("2行0列元素值: %d\n\n", a[1][2][0]);//2行0列元素值 


	printf("0行0列元素值: %d\n", *(*(a[1] + 0) + 0));//0行0列元素值 
	printf("1行0列元素值: %d\n", *(*(a[1] + 1) + 0));//1行0列元素值 
	printf("2行0列元素值: %d\n", *(*(a[1] + 2) + 0));//2行0列元素值 
	printf("2行2列元素值: %d\n", *(*(a[1] + 2) + 2));//2行2列元素值 

//【【【其他问题】】】:
	printf("\n\n【其他问题】:");
	printf("\na[0]= %d\n", a[0]);		//指向一维数组的指针 int (*)[4]型(a[0]是二维数组名)
	printf("a[1]= %d\n\n", a[1]);		//指向一维数组的指针 int (*)[4]型(a[1]是二维数组名)

	printf("&a[0]= %d\n", &a[0]);		//指向二维数组的指针 int (*)[3][4]型(a[0]是二维数组名)
	printf("&a[1]= %d\n", &a[1]);		//指向二维数组的指针 int (*)[3][4]型(a[1]是二维数组名)
	printf("&a[0]+1= %d\n\n", &a[0] + 1);//指向二维数组的指针 int (*)[3][4]型

	printf("a= %d\n", a);				//指向二维数组的指针 int (*)[3][4]型(a是三维数组名)
	printf("a+1= %d\n", a + 1);			//指向二维数组的指针 int (*)[3][4]型
	printf("\n");
}

四、详解三维数组

//首先我们回顾一下二维数组:
二维数组是“数组的数组”,也即二维数组是由一维数组构成的!

【例如】:int a[3][4];
二维数组是数组的数组,也即二维数组a是3个一维数组组成的!
相当于定义了3个一维数组:int a[0][4], a[1][4], a[2][4];
此处是把a[0], a[1], a[2]看作是一维数组的名字。
则二维数组就转换成一维数组了,就可以在一维数组的领域内解决问题了!

且在二维数组中存在以下等式关系:
a[i]+j === *(a+i)+j === &a[i][j]				//这是各元素地址
* (a[i]+j) === *(*(a +i)+j) === *(&a[i][j])	//这是各元素值

且在指向一维数组的指针中存在以下关系:(int(*p)[4])
int(*p)[4];//指向一维数组的指针
若p = a;	//使得p指向二维数组0行首地址
则有以下等式必然成立:
*(p+i)+j === *(a+i)+j === a[i]+j === &a[i][j]	//这是各元素地址
**(p+i)+j) === **(a+i)+j) === *(a[i]+j) === * &a[i][j] ===p[i][j]	//这是各元素值


//再来看三维数组:
通过对二维数组的理解,我们可以知道,三维数组是“数组的数组的数组”
也即三维数组是由二维数组构成的,而二维数组又是由一维数组构成的!
例如 int a[2][3][4];
可以把三维数组看成是2个二维数组构成的,而二维数组又是由一维数组构成的!
也即本题定义了2个二维数组int a[0][3][4]和a[1][3][4](此处是把a[0], a[1]看作是二维数组的名字)!
而二维数组又是由一维数组构成的,所以此处的二维数组又是由3个一维数组构成的。
也即一维数组a[0][0][4], a[0][1][4], a[0][2][4], a[1][0][4]......!(此处把a[0][0], a[0][1], a[0][2]......看作是一维数组的名字)
也即
	int a[0][0][4]		//此处是把a[0][0]看做是一维数组的名字,它包含4个元素
	int a[0][1][4]		//此处是把a[0][1]看做是一维数组的名字,它包含4个元素
	int a[0][2][4]		//此处是把a[0][2]看做是一维数组的名字,它包含4个元素
	int a[1][0][4]		//此处是把a[1][0]看做是一维数组的名字,它包含4个元素
	int a[1][1][4]		//此处是把a[1][1]看做是一维数组的名字,它包含4个元素
	int a[1][2][4]		//此处是把a[1][2]看做是一维数组的名字,它包含4个元素


有了上述的理解之后,我们就可以对三维数组进一步认识了!
在二维数组中存在以下等式关系:
a[i] + j === *(a + i) + j === &a[i][j](等式一)		//这是各元素地址
上述说了:三维数组是由二维数组构成的,也即上述三维数组是由2个二维数组a[0]和a[1]构成。
对(等式一)进行替换:
在(等式一)中:
a[i] + j === > a为二维数组的名字, i和j分别为二维数组的行和列;
所以在三维数组中:a[i][j] + k === > a[i]为二维数组的名字,j和k为相应的二维数组的行和列。
那么由此在三维数组中的等式也出现了:
   a[i] + j === *(   a + i) + j === &   a [i][j](a为二维数组的名字, i和j分别为二维数组的行和列)
a[i][j] + k === *(a[i] + j) + k === & a[i][j][k](a[i]为二维数组的名字, j和k分别为二维数组的行和列)


*********************************************************************************************
【【【指向二维数组的指针】】】:

同样,在二维数组中,存在指向一维数组的指针int(*p)[];
那么在三维数组中,同样存在指向二维数组的指针int(*p)[][];

【【【在二维数组中】】】:
int(*p)[4];//指向一维数组的指针
若p = a;	//使得p指向二维数组0行(实际上也就是p指向一维数组)
则有以下等式必然成立:
*(p + i) + j == = *(a + i) + j == = a[i] + j == = &a[i][j]	//各元素地址(a表示二维数组的名字,i,j是相应的行和列)

* (*(p + i) + j) == = *(*(a + i) + j) == = *(a[i] + j) == = *(&a[i][j])//这是各元素值


【【【同样在三维数组中】】】:
	int(*p)[3][4];	//指向二维数组的指针
如若p = a;		//p指向三维数组的0行(实际上也就是p指向二维数组)
则同样有以下等式成立:

*(*(p + i) + j) + k) == = *(a[i] + j) + k == = a[i][j] + k == = &a[i][j][k]	//这是各元素地址(a[i]表示二维数组的名字,j,k是相应的行和列)

* (*(*(p + i) + j) + k)) == = *(*(a[i] + j) + k) == = *(a[i][j] + k) == = *&a[i][j][k] == = a[i][j][k]	//这是各元素地址

同样在对地址取“*”运算符(求元素值)时,要对地址整体取“()”,然后“*”,这和二维数组中的道理是一样的!
在三维数组中,始终要知道a[i]代表二维数组名!这样就可以在二维数组的基础之上照猫画虎了!

温馨提示:由于时间关系,运行结果我就不贴图了,程序是完全正确的,大家拿去自己运行,这都是我自己去年学习C语言的时候做的笔记,均为原创,直到今天才发出来,希望能够帮助到你!

    原文作者:风赢十三水
    原文地址: https://blog.csdn.net/TianYanRen111/article/details/118940004
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞