精华内容
下载资源
问答
  • 矩形包装:种通用的确定装箱机,旨在符合任何二维三维用例
  • 三维模拟固井界面分离时工艺参数对稳定的影响,袁永文,程严军,目前地层-水泥环-套管组合体稳定的研究主要基于平面,建立的三维模型也只是个算例,没有系统的研究在三维模型下受到三轴地应�
  • 种新型的准静态三维超声弹性成像方法,谢波,黄庆华,超声弹性成像能提供与组织异常的病理状态密切相关的组织弹性信息。三维弹性图能提供丰富的三维应变分布信息,克服了二维弹性技术
  • 我们在一维数组中已经用了很多的内容进行讲解,那么对于二维数组来说二维数组的本质,也是一维数组,只不过,一维数组中的每个元素,又是一个一维数组而己。 定义 我们首先定义一个二维数组然后进行解释: int array...

    二维数组本质说明

    我们在一维数组中已经说明了很多的内容,那么对于二维数组来说,二维数组的本质,也是一个一维数组,只不过,一维数组中的每个元素,又是一个一维数组而己,也就是存在一维数组的嵌套关系。

    定义、大小及本质剖析

    我们首先定义一个二维数组然后进行解释:

    int  array[3][4];
    

    上面代码表示定义一个数组名为array,3行4列的一个二维数组。
    我们通常理解为3×4的一个矩阵。

    我们可以这样来理解二维数组本质:
    二维数组的本质理解
    int [4] arr[3] ;
    前面int [ 4 ] 表示类型,后面arr[ 3 ]表示一维数组,里面有三个成员 arr[ 0 ],arr[ 1 ],arr[ 2 ] ,每一个成员都是int [ 4 ] 类型。

    我们在一维数组中:
    int arr[10]; 等价于 int [ 10 ] arr;

    那么在二维数组中:
    int arr[ 3 ] [ 4 ] ; 等价于 int [ 4 ] arr[ 3 ];

    我们通过上面图解对于二维数组的本质理解,把 int [ 4 ] 看着 T 得到:
    T arr[ 3 ] ; 等价于 T [ 3 ] arr ;
    T代表一维数组arr [ 3 ] 元素的类型。

    把T还原 T [ 3 ] arr ; 也就等价于 int [ 4 ] [ 3 ] arr;

    那么也就是说
    int arr[ 3 ] [ 4 ] ; 等价于 int [ 4 ] [ 3 ] arr ;

    所以:
    int[4][3] 表示三行四列 表示 int [ 4 ] 类型的元素有3个。
    在定义二维数组的时候 是 arr [ 3 ] [ 4 ] ;

    int[3][4] 表示四行三列 表示 int [ 3 ] 类型的元素有4个。
    在定义二维数组的时候 是 arr [ 4 ] [ 3 ] ;

    代码演示:

    #include <stdio.h>
    int main()
    {
    	int arr[3][4];
    	printf("sizoef(arr) = %d\n", sizeof(arr));
    	printf("sizoef(int[4][3]) = %d\n", sizeof(int[4][3]));
    	printf("sizoef(arr[0]) = %d\n", sizeof(arr[0]));
    	printf("sizoef(int[4]) = %d\n", sizeof(int[4]));
    	printf("sizoef(arr[0][0]) = %d\n", sizeof(arr[0][0]));
    	return 0;
    }
    

    运行结果为:

    二维数组的本质
    上面代码可以帮助我们理解二维数组的本质。

    再次强调:我们上面定义的二维数组是3行4列,int [ 4 ] [ 3 ]也代表3行4列。

    初始化

    二维数组初始化和一维数组一样,我们这里分为三类。

    满初始化

    满初始化的意思就是,我们在定义二维数组的时候,二维数组每一个元素都进行了初始化,并且在初始化的 { } 里面每一行的内容用 { } 单独括起来初始化。我们也可以将二维数组的所有元素都放在同一个 { } 里面,二维数组也会自动识别行列,二维数组保持行优先规则。也即是说,只有一个 { } 里面包括二维数组所有元素的时候,数据存放先存放二维数组第一行,第一行存满之后开始存放第二行,依次存放数据。

    #include <stdio.h>
    int main()
    {
    	//满初始化
    	int arr[3][4] = {  
    	{1,2,3,4},           
    	{5,6,7,8},
    	{9,10,11,12} 
    	};
    
    	//满初始化
    	int arr1[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
    	//以上两种都是满初始化
    	for (int i = 0; i < 3; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%d\t", arr[i][j]);
    		}
    		printf("\n");
    	}
    	printf("\n\n");
    
    	for (int i = 0; i < 3; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%d\t", arr1[i][j]);
    		}
    	printf("\n");
    	}
    	return 0;
    }
    

    打印结果为:
    二维数组满初始化

    部分初始化

    部分初始化的意思就是说,我们二维数组的内容只初始化了一部分,那么其他元素自动初始化为0。
    那么部分初始化这里,我们又要区分:

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

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

    我们先给出打印结果:

    #include <stdio.h>
    int main()
    {
    	//部分初始化
    	int arr[3][4] = { 
    	{1},
    	{2,3},
    	{4,5,6} };
    	
    	//部分初始化
    	int arr1[3][4] = { 1,2,3,4,5,6};
    	//以上两种都是部分初始化
    	
    	for (int i = 0; i < 3; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%d\t", arr[i][j]);
    		}
    		printf("\n");
    	}
    	printf("\n\n");
    	for (int i = 0; i < 3; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%d\t", arr1[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
    

    打印结果为:
    二维数组部分初始化
    我们先解释:

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

    我们首先知道,二维数组和一维数组一样,部分初始化中没有初始化的部分为0,但是如果初始化的每一行都用{}括起来的话,就像每一行单独的一样。初始化的时候,只把这一行里的元素从前向后初始化,没有初始化的元素为0,而不影响其他行里的元素。

    也就是说一旦每一行都用 { } 初始化,每一行的元素之间是互不影响的。从而就出现了我们第一组的打印结果,第一行 { } 里面只有1而后面三个元素没有初始化的部分就为0,第二行{}里面有2,3 后面两个元素没有初始化的部分就为0,第三行类似,每一行之间互不影响。

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

    上面的初始化很容易理解,按照二维数组行优先,开始初始化,没有初始化的部分为0。

    部分初始化的特殊情况

    那么我们也会遇到只初始化一个元素的情况:
    例如:

    #include <stdio.h>
    int main()
    {
    	int arr[3][4] = {0};
    	for (int i = 0; i < 3; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%d\t", arr[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
    

    打印结果为:
    部分初始化的特殊情况打印结果
    我们在这里需要注意的一点就是,这样并不是说把所有的元素都初始化为0,而是把第一个元素初始化为0,后面的值是因为按照部分初始化处理,所以后面的元素值都初始化为0。

    未初始化

    如果我们只有定义部分,没有初始化部分:

    #include <stdio.h>
    int main()
    {
    	int arr[3][4];
    	for (int i = 0; i < 3; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%d\t", arr[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
    

    打印结果为:
    二维数组的未初始化
    那么二维数组元素的初始化就是随机值。

    不定义行的初始化

    int arr2[][4] = { {1,2,3,4},   //初始化的时候可以省略行  但是不能省略列
    				  {5,6,7,8},
    				  {9,10,11,12} };
    

    我们可以直接这样定义:
    或者

    int arr2[][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
    

    这两个功能完全相同。
    但是我们能不能只写行不写列呢?
    结果是不行的,我们在这里分析:

    int arr2[4][] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
    

    如果要求是4行,那么如果划分呢?
    1
    2
    3
    4,5,6,7,8,9,10,11,12
    还是
    1,2,3
    4,5
    6
    7,8,9,10,11,12,
    还有很多更多的情况,所以是不能的。

    我们可以不给出二维数组的行,但是必须给出二维数组的列,二位数组按照列优先初始化元素,给出列,就知道了数组在第几个元素的时候跳转到下一行。

    当然上面的分析只是我们便于理解
    如果你对于我上面的二维数组的本质已经理解的话,下面我们进行本质分析:
    二维数组:
    int arr[ 2 ] [ 4 ] ; 本质就是 int[4] arr[2] ;
    int[4]是类型,2是元素个数,arr是二维数组变量名。
    我们已经知道一维数组里可以不设置数组元素个数及就是arr[2],但是我们不能破坏数据类型。
    例如我们的int类型,你能写成in吗?就会造成类型不完整。

    也就是说一维数组arr[ 2 ] 的数据类型是int[ 4 ],里面的4及就是二维数组的列。
    所以对于arr[2][4]二维数组,里面的4是不能省略,省略了就会造成一维数组arr[ 2 ] 数据类型不完整。
    也就是说行可以省略,但是列是不能省略的。

    总结:
    arr [ 3 ] [ 4 ] ; 省略3等价于省略了一维数组的大小,如果省略4等价于省略了类型的大小。数组中类型的大小是绝对不可以省略的。

    按照二维数组本质,我们可以通过下面方式求出来不定义行初始化的二维数组有多少行:
    代码演示:

    #include <stdio.h>
    int main()
    {
    	int arr[][4] = { 1,2,3,4,5,6,7,8,9 };
    	printf("二维数组有%d行\n", sizeof(arr) / sizeof(int[4]));
    	printf("二维数组有%d行\n", sizeof(arr) / sizeof(arr[0]));
    	for (int i = 0; i < sizeof(arr) / sizeof(int[4]); i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%3d", arr[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
    

    运行结果为:
    不定义行的初始化

    越界初始化

    我们这里只给简单说明

    int arr2[3][4] = { {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
    

    上面是越界初始化 很容易理解,只有12个格子要存放15个元素就会出现越界初始化。

    #include <stdio.h>
    in main()
    {
    	int arr[3][4] = {0};
    	for (int i = 0; i < 3; i++)
    	{
    		for (int j = 0; j < 5; j++)
    		{
    			printf("%d\t", arr[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
    

    上面是越界访问,访问到3行4列以外的元素。

    访问

    二维数组通过二重循环嵌套进行访问:
    代码演示:

    #include <stdio.h>
    int main()
    {
    	int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    	for (int i = 0; i < 3; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%d\t", arr[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
    

    运行结果:

    访问二维数组

    二维数组三要素

    起始地址

    #include <stdio.h>
    int main()
    {
    	int array[3] = { 1,2,3 };
    	int arr[3][4] = { 1,2,3,4,5,6,7,8,9 };
    	printf("一维数组数组名代表数组首元素的地址:\n");
    	printf("array = %p\t&array[0]=%p\n", array, &array[0]);
    	printf("二维数组数组名代表数组首元素的地址:\n");
    	printf("arr = %p\t\t&arr[0] = %p\n", arr, &arr[0]);
    	return 0;
    }
    

    运行结果为:
    数组名代表数组首元素的地址

    我们可以看到数组名就代表数组首元素的地址。

    步长

    #include <stdio.h>
    int main()
    {
    	int arr[3][4] = {1,2,3,4,5,6,7,8,9};
    	printf("arr = %d,arr+1 = %d\n", arr, arr + 1);
    
    	return 0;
    }
    

    运行结果为:
    二维数组步长
    我们可以看到步长为16,我们根据前面讲到的本质,arr[3][4] 本质元素类型是一个int [4] 所以步长为int[4],大小为16字节。

    范围

    二维数组内存分布图

    逻辑形式

    二维数组的逻辑形式

    物理存储形式

    二维数组的物理内存存储
    我们先给出二维数组的数组名所表示的范围,然后通过地址进行说明。
    二维数组范围简略图

    二维数组的图解分析解析:
    二维数组的本质理解

    使用下面方式访问二维数组每一行的第一个元素及地址:

    #include <stdio.h>
    int main()
    {
    
    	int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    	for (int i = 0; i <3; i++)
    	{
    		printf("%d\t", arr[i]);
    		printf("%d\n", arr[i][0]); 
    			
    	}
    	return 0;
    }
    

    运行结果为:
    访问二维数组每一行的第一个元素及地址

    代码演示:

    #include <stdio.h>
    int main()
    {
    
    	int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12};
    	printf("arr = %p\n", arr);    //外层一维数组起始地址
    	printf("&arr[0] = %p\n", &arr[0]);     //外层一维数组第一个元素的地址
    	printf("arr = %p ,arr+1 = %p\n", arr, arr + 1);//外层一维数组步长
    
    	printf("arr[0] = %p\n", arr[0]);  //内嵌一维数组起始地址
    	printf("&arr[0][0] = %p\n", &arr[0][0]);  //内嵌一维数组第一个元素的地址
    
    	printf("arr[0] = %p arr[0]+1 = %p", arr[0], arr[0] + 1);//内嵌一维数组步长
    	return 0;
    }
    

    运行结果为:
    运行结果

    上面代码中:
    arr 步长为 int [4] ; 每次跳动16个字节。
    地址从 A0 到 B0 相差16个字节。

    arr[ 0 ] ; 步长为 int 每次跳动4个字节。
    地址从 A0 到 A4 相差4个字节。

    那么每次访问一个int[4]大小,再访问一次内嵌数组的下标,可以得到每一行的其他元素。

    #include <stdio.h>
    int main()
    {
    	int arr[3][4] = { 1,2,3,4,5,6,7,8,9 };
    	for (int i = 0; i < 3; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%d\t", *(arr[i] + j));
    			printf("%p\n", arr[i] + j);
    		}
    
    	}
    	return 0;
    }
    

    运行结果为:
    打印二维数的所有元素及地址

    我们再转变换一种方式:

    #include <stdio.h>
    int main()
    {
    
    	int arr[3][4] = {1,2,3,4,5,6,7,8,9};
    	for (int i = 0; i <3; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%d\t", arr[i][j]);
    			printf("%d\n", &arr[i][j]);
    		}
    	}
    	return 0;
    }
    

    运行结果为:
    打印二维数的所有元素及地址

    上面就变成了我们常规的访问方式。

    四个相同地址

    在分析完成之后我们对于解析图中的四个相同地址进行验证:

    #include <stdio.h>
    int main()
    {
    	int arr[3][4] = { 1,2,3,4,5,6,7,8,9 };
    
    	printf("&arr = %d\n", &arr); 					//二维数组数组名取地址
    	printf("&arr + 1 = %d\n", &arr + 1); 			//二维数组数组名取地址 + 1 跨度为整个二维数组的大小
    	printf("\n======================\n");
    
    	printf("arr = %d\n", arr); 						//数组名代表外部一维数组首元素的地址
    	printf("arr + 1 = %d\n", arr + 1); 				//外部一维数组的步长
    	printf("\n======================\n");
    
    	printf("&arr[0] = %d\n", &arr[0]);				//外部一维数组首元素的地址
    	printf("&arr[0] + 1 = %d\n", &arr[0] + 1);		//外部一维数组的步长
    	printf("\n======================\n");
    
    
    	printf("arr[0] = %d\n", arr[0]);				//内嵌一维数组的数组名表示一维数组首元素的地址
    	printf("arr[0] + 1 = %d\n", arr[0] + 1);		//内嵌一维数组的步长
    	printf("\n======================\n");
    
    	printf("&arr[0][0] = %d\n", &arr[0][0]);		 //二维数组的第一行第一列元素的地址
    	printf("&arr[0][0] + 1 = %d\n", &arr[0][0] + 1); //二维数组的第一行第一列元素的地址 + 1
    	printf("\n======================\n");
    
    	printf("arr[0][0] = %d\n", arr[0][0]);			 //二维数组的第一行第一列元素数据
    	printf("arr[0][0] + 1 = %d\n", arr[0][0] + 1);   //二维数组的第一行第一列元素数据 + 1
    	printf("\n======================\n");
    
    	return 0;
    }
    

    运行结果为:
    二维数组详细说明

    我们从引用和解引用的角度进行分析。

    #include <stdio.h>
    int main()
    {
    	int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
    	printf("%d\n", *((*(arr)+0) + 0));
    	printf("%d\n", *((*(arr)+1) + 1));
    	printf("%d\n", *((*(arr)+2) + 2));
    	printf("%d\n", *((*(arr)+3) + 3));
    	return 0;
    }
    

    运行结果为:
    运行结果

    实战

    在二维数组的实战中,对于数组下标的研究非常重要。

    打印主对角线数据

    #include <stdio.h>
    int main()
    {
    
    	int arr[4][4] = {1,2,3,4
    					,1,2,3,4
    					,1,2,3,4
    					,1,2,3,4
    	};
    	for (int i = 0; i < 4; i++)  //两层循环实现
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			if (i == j)
    			{
    				int t = i;
    				while (t--)
    					printf("  ");
    				printf("%d\n",arr[i][j]);
    			}
    		}
    	}
    
    	for (int i = 0; i < 4; i++)  //一层循环实现
    	{
    		int t = i;
    		while (t--)
    			printf("  ");
    		printf("%d\n",*(arr[i]+i));
    	}
    
    	for (int i = 0; i < 4; i++)  //两层循环实现
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			if ((i + j) == 3)
    			{
    				int t = 4-i;
    				while (t--)
    					printf("  ");
    				printf("%d\n", arr[i][j]);
    			}
    		}
    	}
    
    	for (int i = 0; i < 4; i++)  //一层循环实现
    	{
    		int t = 4-i;
    		while (t--)
    			printf("  ");
    		printf("%d\n", *(arr[i] + (3-i)));
    	}
    	return 0;
    }
    

    执行结果为:
    打印二维数组的对角线

    逆置二维数组

    #include <stdio.h>
    
    int main()
    {
    	int tmp;
    	int arr[4][4] = {1,2,3,4
    					,1,2,3,4
    					,1,2,3,4
    					,1,2,3,4
    	};
    
    	for (int i = 0; i < 4; i++)  //打印二维数组
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%3d", arr[i][j]);
    		}
    		printf("\n");
    	}
    	for (int i = 0; i < 4; i++)  //逆置二维数组
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			if (i > j)
    			{
    				tmp = arr[i][j];
    				arr[i][j] = arr[j][i];
    				arr[j][i] = tmp;
    			}
    		}
    	}
    	printf("\n**************\n\n");
    	for (int i = 0; i < 4; i++)  //打印二维数组
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			printf("%3d", arr[i][j]);
    		}
    		printf("\n");
    	}
    
    	return 0;
    }
    

    运行结果为:
    二维数组转置

    天生棋局

    生成一个 10*10 的棋局,要求初始化为零。
    随机置入 10 颗棋子,棋子位置处的值为1,并打印。
    若在棋中出现连续三个棋子在一起,包含横行和竖行。
    则输出好棋,否则输入臭棋。

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    int main()
    {
    
    	srand(time(NULL));
    	int chess[10][10] = { 0 };
    
    
    	for (int i = 0; i < 10; i++)  //打印二维数组
    	{
    		for (int j = 0; j < 10; j++)
    		{
    			printf("%3d", chess[i][j]);
    		}
    		printf("\n");
    	}
    
    	int number = 0;
    	int l;
    	int r;
    	while (1)
    	{
    		r = rand() % 10;
    		l = rand() % 10;
    		if (chess[l][r] == 0)
    		{
    			chess[l][r] = 1;
    			number++;
    		}
    		if (number == 10)
    			break;
    	}
    	printf("\n\n===============================\n\n");
    	for (int i = 0; i < 10; i++)  //打印二维数组
    	{
    		for (int j = 0; j < 10; j++)
    		{
    			printf("%3d", chess[i][j]);
    		}
    		printf("\n");
    	}
    
    	int count = 0;
    	for (int i = 0; i < 10; i++)  //统计二维数组中1的个数
    	{
    		for (int j = 0; j < 10; j++)
    		{
    			if (chess[i][j] == 1)
    				count++;
    		}
    	}
    	printf("==%d==\n", count);
    
    	int sum;
    	int FlagGoodChess = 0;
    	for (int i = 0; i < 10; i++)   //横行扫描
    	{
    		sum = 0;
    		for (int j = 0; j < 10; j++)
    		{
    			if (chess[i][j] == 1)
    			{
    				sum++;
    				if (sum == 3)
    				{
    					FlagGoodChess = 1;
    					break;
    				}
    			}
    			else
    			{
    				sum = 0;
    			}
    		}
    		if (FlagGoodChess == 1)
    			break;
    	count = 0;                       //列扫描
    		sum = 0;
    		for (int j = 0; j < 10; j++)
    		{
    			if (chess[j][i] == 1)
    			{
    				sum++;
    				if (sum == 3)
    				{
    					FlagGoodChess = 1;
    					break;
    				}
    			}
    			else
    			{
    				sum = 0;
    			}
    		}
    		if (FlagGoodChess == 1)
    			break;
    	}
    	if (FlagGoodChess == 1)
    		printf("好棋\n");
    	else
    		printf("臭棋\n");
    	return 0;
    }
    

    运行结果为:

    天生棋局

    有序数组归并

    合并两个己经有序的数组 A[M], B[N],到另外一个数组 C[M+N]中去,使用另外一个数组依然有序。其中 M 和 N 均是宏常量。

    #include <stdio.h>
    #include <stdlib.h>
    
    #define M 5
    #define N 3
    int main()
    {
    
    	int a[M] = { 11,13,15,17,19 };
    	int b[N] = { 2,4,6};
    	int c[N + M] = { 0 };
    	int i = 0;
    	int j = 0;
    	int k = 0;
    	while (i < M && j < N)
    	{
    		if (a[i] <= b[j])
    		{
    			c[k++] = a[i++];
    		}
    		else
    		{
    			c[k++] = b[j++];
    		}
    	}
    
    		while (i<M)
    		{
    			c[k++] = a[i++];
    		}
    		while (j < N)
    		{
    			c[k++] = a[j++];
    		}
    
    	for (int i = 0; i < N + M; i++)
    	{
    		printf("%d\t", c[i]);
    	}
    	printf("\n");
    
    	return 0;
    }
    

    运行结果为:
    有序数组归并

    数组名的二义性

    数组名,是数组的唯一标识符,既表示一种构造数据类型的大小,也表示访问数组中成员的首地址通过地址偏移来访问数据成员使用。

    由于结构体成员所占内存大小不同,所以结构体的成员定义与成员访问是分开的,为此增加了成员运算符。而数组名,却是一身而兼二任的,这也是简洁的需要。

    一维数组名

    一维数组名,从总体来看,代表一种构造类型,同时又承担了访问每个数组元素的责任。
    所以数组名, 就有两重性。
    数组名是数组的惟一标识符

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    	int arr[10] = {5,6,7,8};
    	//一维数组数组名充当构造类型
    	printf("sizeof(arr) = %d\n", sizeof(arr));
    	printf("sizeof(arr) = %d\n", sizeof(int[10]));
    	
    	//一维数组数组名作为成员访问
    	printf("arr = %p\n", arr);
    	printf("&arr[0] = %p\n", &arr[0]);       //数组名访问地址
    	printf("*(arr + 0) = %d\n", *(arr + 0));  //数组名访问数据
    	return 0;
    }
    

    运行结果为:
    一维数组名的二义性

    二维数组名

    数组名,是数组的唯一标识符。二维数组也是如此,二维数组本质是一种嵌套关系,其本质是一维数组,一维数组的每个成员又是一个一维数组。

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    
    	int arr[3][4] = {1,2,3,4,5,6};
    	//二维数组数组名充当一种构造类型
    	printf("sizeof(arr) = %d\n", sizeof(arr));
    	printf("sizeof(int[3][4])= %d\n", sizeof(int[3][4]));
    
    	//二维数组数组名作为成员访问
    	printf("arr = %p\n", arr);
    	printf("&arr[0] = %p\n", &arr[0]);       	//数组名访问地址
    	printf("*(arr[0] + 0)= %d\n", *(arr[0] + 0));  //数组名访问数据
    	return 0;
    }
    

    运行结果为:
    二维数组名的二义性

    小结

    到这里我们一维数组和二维数组的基础知识就写,当然,这里可能会比较简单一点,之后当我们把指针和数字结合到一起的时候,就会有一些难度,但是在我们使用指针之后,程序的效率就会更高,而且有时候在操作的时候必须使用指针才能完成。我们这里先给出一个概念,之后详细理解:
    一维数组的数组名是一级指针
    二维数组的数组名是数组指针

    最后我们再来说明一下[ ] 基址变址运算符
    A[x] 等价于 * (A + x)
    代码演示:

    #include <stdio.h>
    int main()
    {
    	int arr[3][4] = { 1,2,3,4,5,6,7,8,9,0 };
    	printf("%d\n", arr[1][1]);
    	printf("%d\n", *((arr+1)[1]));
    	printf("%d\n", *(*(arr + 1)+1)); //数组指针变成了一维数组
    	return 0;
    }
    

    运行结果为:
    运行结果

    二维数组的三要素可以总结为大数组的三要素和小数组的三要素。

    数组的三要素不仅能够帮助我们更好的理解,并且在后面函数传参传递数组的时候,要传递数组的三要素。

    二维数组的本质就是一维数组对于一维数组的嵌套。

    数组名当作整体使用的情况并不多见,使用sizeof(array);的时候表示整个数组。使用 &array+1 的时候跳跃整个数组的大小。更多的情况使用的时候代表的是数组首元素的地址。

    展开全文
  • 来自马克斯·普朗克物质结构与动力学研究所(MPSD)、RWTH亚琛大学和熨斗...通过结合大规模从头计算和密度矩阵重整化群计算,研究表明莫尔干涉图样将产生相关一维系统的平行线。其研究成果现已发表在《自然通讯》期刊...

    来自马克斯·普朗克物质结构与动力学研究所(MPSD)、RWTH亚琛大学和熨斗研究所的研究人员发现:将两张原子薄的材料扭转堆叠在一起所产生的可能性,甚至比预期要大。科学家研究了硒化锗(GeSE),这是一种具有矩形晶胞的材料,而不是专注于具有三重或六重对称的晶格,如石墨烯。通过结合大规模从头计算和密度矩阵重整化群计算,研究表明莫尔干涉图样将产生相关一维系统的平行线。

    9b71903496eb5b9b01072098cc6256c9.png

    其研究成果现已发表在《自然通讯》期刊上,这极大地拓宽了使用莫尔扭曲物理实现结构的范围,并为相关系统如何从二维跨越到一维这一具有挑战性的问题提供了一条道路。由于粒子不能像在多维环境中那样彼此通过,一维系统很耐人寻味,因为相关性必然会导致集体激发。对这两种数值方法联合分析产生了很好的结果:能够对两张扭曲的硒化锗相图进行分类,发现了许多可实现的物质相。

    7cd9701be1bb98e1bab779f7cd1d0972.png

    (上图所示)扭曲双层硒化锗中出现一维相关态,图中显示了由密度泛函理论计算得到的这些态的电荷密度分布。图片:Lede Xian, Jörg Harms, MPSD

    展开全文
  • 认识一维二维数组

    2020-08-05 21:21:44
    认识数组 一、Java 中的数据类型有2类 1.基本数据类型 ...、如何定义一个一维数组? 格式: 数据类型 数组名称[]; 数据类型 []数组名称; 例如: int shuzu1[]; char []shuzu2; 数组定义与变量定义的区

    认识数组

    一、Java 中的数据类型有2类
    1.基本数据类型
    2.复合数据类型
    为了能够一次性保存一组数据,所以才有了数组。
    二、什么是数组?
    相同数据类型的数据按照顺序组成的复合数据类型就是数组。
    1.相同数据类型的数据----将来被保存到数组中的数据都是同一类型。
    例如:【男澡堂子里都是男的,不能出现女的】
    2.按照顺序
    3.复合数据类型
    三、如何定义一个一维数组?
    格式:
    数据类型 数组名称[];
    数据类型 []数组名称;
    例如:
    int shuzu1[];
    char []shuzu2;

    数组定义与变量定义的区别:数组的定义与变量的定义相似,只是需要”[]”与变量区分,因此上”[]”就是数组的标志。

    名称的前面/后面出现一个“[]”就是一维数组,有两个”[][]”就是二维数组,两个以上就是多维数组。
    四、如何创建一个一维数组?
    创建数组实际上就是为数组开辟指定的存储空间,用来保存一组数组。
    1.先定义,后创建
    数据类型 数组名称[];
    数据类型 []数组名称;
    数组名称 = new 数据类型[指定的存储空间];
    指定的存储空间是一个整数int
    例如:
    int shuzu3[];
    shuzu3=new int[4];
    char []shuzu4;
    shuzu4 = new char[5];
    错误示范:
    shuzu4 = [5]new char;
    shuzu4 = new char[];
    shuzu4 = new char[3.2];

    2.定义+创建
    数据类型 数组名称[ ] = new 数据类型[指定的存储空间];
    数据类型 [ ]数组名称 = new 数据类型[指定的存储空间];
    例如:
    int shuzu5[]=new int[4];
    char []shuzu6=new char[5];

    五、如何为一维数组赋值?

    1.逐个赋值—就是挨个为数组的每一个存储空间存放数据值。
    因为是按照顺序存放数据的,顺序是从0开始的,每一顺序编号就是一个数组的存储空间,这个顺序编号就叫下标。
    格式: 数组名称[下标] = 数据值;

    注意:当保存在数组中的数据超过数组指定的存储空间就是会出错。
    报错例如:java.lang.ArrayIndexOutOfBoundsException: 5
    例如:

    public  class  ShuZuDemo2{
       public static  void main(String args[]){
    	 char shuzu1[]=new char[5];
    	 shuzu1[0]='A';
    	 shuzu1[1]='B';
    	 shuzu1[2]='C';
    	 shuzu1[3]='D';
    	 shuzu1[4]='E';
         //shuzu1[5]='F'; //错误示范java.lang.ArrayIndexOutOfBoundsException: 5
    	  }
    }
    

    2.直接赋值—就是在创建数组的时候将数据值保存到数组中。
    格式:数据类型 数组名称[]={数据值1,数据值2,…,数据值n};
    注意:创建数组的时候不能指定存储空间。
    例如:

    public  class  ShuZuDemo2{
       public static  void main(String args[]){
    	 char  shuzu4[]={'a','b','c','d','e'};	
         //创建数组的时候不能指定存储空间
    	 //double shuzu3[]=new double[4]{12.5,23.8,456.7,23.9};//错误
      }
    }
    

    六、如何从一维数组中取值?
    只要我们能够得到数组的存储位置,就可以得到数组中的数据值。
    格式:数组名称[下标]
    shuzu1[2]—从shuzu1这个数组中得到第3个位置中保存的数据值。
    例如:

    public  class  ShuZuDemo2{
        public static  void main(String args[]){
          char shuzu1[]={'h','e','l','l','o'};
          System.out.println("取出数组中的最后一个值---"+shuzu1[4]);
       }
    }
    

    输出结果:
    在这里插入图片描述

    七、一维数组的length属性

    1.length表示指定空间大小
    例如:

    public class ShuZuLian{
        public static void main(String args[]){
            int sz1[] = new int[10];
            sz1[2] = 110;
            sz1[5] = 520;
            System.out.println("sz1的length属性---"+sz1.length);
          }
    }
    

    输出结果:
    在这里插入图片描述

    2.length表示数组元素个数【指定空间大小】
    例如:

    public class ShuZuLian2{
        public static void main(String args[]){
            char sz2[] = {'a','b','c','d','e','f'};
            System.out.println("sz2的length属性---"+sz2.length);
          }
    }
    

    输出结果:
    在这里插入图片描述

    八、数组的内存结构

    在这里插入图片描述

    九、循环遍历一维数组
    例如:

    public  class  ShuZuLian3{
    	public static  void main(String args[]){
    		char shuzu1[]={'a','b','c','d','e'};
    		//for循环遍历数组
    		for(int i=0;i<shuzu1.length;i++){
    			System.out.println("char数组shuzu1--"+shuzu1[i]);
    		}
    		System.out.println("_______________");
    		//while循环遍历数组
            int j=0;
            while(j<shuzu1.length){
    			System.out.println("char数组shuzu1--"+shuzu1[j]);
    			j++;
    		}
    		System.out.println("_______________");
    		//do{}while()循环遍历数组
    		int k=0;
    		do{
               System.out.println("char数组shuzu1--"+shuzu1[k]);
    		   k++;
    		}while(k<shuzu1.length);
    	}
    }
    

    十、增强的for循环遍历一维数组
    增强的for循环格式:
    for(数组的数据类型 变量名称 : 被遍历的数组名称){
    循环体;
    }
    例如:

    public class ShuZuLian5{
         public static void main(String args[]){
             char sz5[] = {'a','b','c','d','e'};
             for(char value:sz5){
                System.out.println("char数组sz5--"+value);
              }
          }
    }
    

    十一、如何定义一个二维数组?
    格式:
    数据类型 数组名称[][];
    数据类型 [][]数组名称;
    例如:
    int shuzu1[][];
    char [][]shuzu;

    十二、如何创建一个二维数组?
    二维数组可以保存一个类似表格一样的数据,所以我们可以认为二维数组就是一个表格。
    1.先定义,后创建
    数据类型 数组名称[][];
    数据类型 [][]数组名称;
    数组名称=new 数据类型[表格行][行中的列];
    例如:
    int shuzu1[][];
    shuzu1 = new int[2][3];
    2.定义+创建
    数据类型 数组名称[ ] = new 数据类型[表格行][行中的列];
    数据类型 [ ]数组名称 = new 数据类型[表格行][行中的列];
    例如:
    int shuzu1[][]=new int[2][3];
    十三、如何为二维数组赋值?

    1.逐个赋值—就是挨个为数组的每一个存储空间存放数据值。
    格式: 数组名称[下标][下标] = 数据值;
    例如:

    public class EShuZu1{
         public static void main(String args[]){
             int sz[][] = new int[2][4];
             sz[0][0] = 1;
             sz[0][1] = 2;    
             sz[0][2] = 3;
             sz[0][3] = 4;
             sz[1][0] = 5;
             sz[1][1] = 6;
             sz[1][2] = 7;
             sz[1][3] = 8;
           }
       }
    

    2.直接赋值—就是在创建数组的时候将数据值保存到数组中。

    格式:
    数据类型 数组名称[]={{数据值1,数据值2,…数据n},{数据值1,数据值2,…数据n}};
    例如:

    public class EShuZu2{
         public static void main(String args[]){
            char sz[][] = {{'A','B','C'},{'D','E','F'}};
           }
      }
    

    十四、如何从二维数组中取值?
    只要我们能够得到数组的存储位置,就可以得到数组中的数据值。
    格式:数组名称[行][列];
    shuzu1[2][3]—从shuzu1这个数组中得到第3行,第4列中保存的数据值。
    例如:

    public class EShuZu3{
           public static void main(String args[]){
              char sz[][] = {{'A','B','C'},{'D','E','F'}};
              System.out.println("取出sz数组中sz[0][2]的值---"+sz[0][2]);
            }
      }
    

    输出结果:
    在这里插入图片描述

    十五、二维数组的length属性 – 行数

    1.length表示指定空间大小
    例如:

    public class EShuZu4{
        public static void main(String args[]){
            int sz[][] = new int[2][4];
            sz[0][0] = 1;
            sz[0][1] = 2;    
            sz[0][3] = 4;
            sz[1][1] = 6;
            sz[1][3] = 8;
            System.out.println("sz的length属性---"+sz.length);
        }
    }
    

    输出结果:
    在这里插入图片描述

    注意:二维数组的length属性为该数组的行数

    2.length表示数组行元素个数【指定空间大小】
    例如:

    public class EShuZu5{
           public static void main(String args[]){
                char sz[][] = {{'A','B','C'},{'D','E','F'},{'G','H','J'}};
            System.out.println("sz的length属性---"+sz.length);
               }
      }
    

    输出结果:
    在这里插入图片描述

    十六、循环遍历二维数组
    使用双层循环结构,外层控制行,内层控制列
    例如:

    public class EShuZu6{
         public static void main(String args[]){
            int sz[][] = {{100,200,300},{400,500,600},{700,800,900}};
            for(int i = 0;i < sz.length;i++){
                  for(int j = 0;j<3;j++){
                  System.out.println("sz的值==="+sz[i][j]);              
              }         
          }
       }
    }
    

    十七、基本数据类型与复合数据类型的区别?
    1.基本数据类只在内栈区去保存数据,而复合数据类型在内存的栈区和堆区都有保存数据,栈区保存的数据是堆区的存储位置,堆区则保存真实的数据值。
    2.由于计算机在执行的时候,总是先从内存区获取数据,因此基本数据类型的执行速度要比复合数据类型的执行速度快。

    展开全文
  • 提出了种记录透射标识二维三维彩虹全息图的新方法, 它直接用散射狭缝光照明二维透射标识, 将透射光记录为主全息图; 主全息图可按普通二步彩虹一样进行二维三维的分色、分层次记录, 既保持了普通二步彩虹全息的...
  • 、计算机图形学中...2. 仿射变换:是二维坐标到二维坐标的线性变换。满足:平直(直线经过变换之后依然是直线)、平行(平行线依然是平行线);3. 齐次坐标表示法:用个n+1维的向量表示个n维向量的方法...

    一、计算机图形学中坐标系分类

    世界坐标系、建模坐标系、观察坐标系、设备坐标系、规范化坐标系

    其中:规范化坐标系是一个中间坐标系,坐标值取值范围0-1;

    二、二维图形变换

    1. 变换种类:比例、旋转、镜像、错切、平移等;

    2. 仿射变换:是一种二维坐标到二维坐标的线性变换。满足:平直性(直线经过变换之后依然是直线)、平行性(平行线依然是平行线);

    3. 齐次坐标表示法:用一个n+1维的向量表示一个n维向量的方法;

    n维向量的变换是在n+1维的空间进行的,变换后的n维结果是被反投回到感兴趣的特定的维空间内而得到的。

    为什么要采用齐次坐标?对于图形来说,没有实质性的差别,但是却给后面矩阵运算提供了可行性和方便性。

    4. 二维变换矩阵

    二维空间中某点的变化可以表示成点的齐次坐标与3阶的二维变换矩阵T2d相乘,即:

    其中可对变换矩阵进行分割:

    三、三维图形变换

    三维图形的几何变换是在二维方法基础上增加了对z坐标的考虑而得到的;

    1. 三维图形变换矩阵

    同样,根据T3D在变换中所起的具体作用,进一步可将T3D分成四个矩阵。即:

    左上部分:对点进行比例、对称、旋转、错切变换;

    左下部分:对点进行平移变换;

    右上部分:进行透视投影变换;

    右下部分:产生整体比例变换;

    2. 投影变换

    1)透视投影:投影线均通过投影中心,在投影中心相对投影面确定的情况下,空间的一个点在投影面上值存在唯一一个投影。生成真实感视图但不保持相关比例;

    2)平行投影:分正投影和斜投影。保持物体的有关比例不变,没有给出三维物体外表的真实性表示。

    展开全文
  • 编译:T.R点云是三维目标最为重要的表示形式之,但高效地处理需要面临点云非规则、无序和稀疏的特点。为了克服三维卷积带来的计算资源消耗和分辨率限制,来自香港中文大学深圳分校等机构的研究人员们提出了种...
  • 图片来源于网络,如有侵权请联系删除 超声是产前... 简单来讲,二维超声是种平面超声,可以理解成是平面的照片,三维超声是在二维超声的基础上加上空间轴,也就是能够立体的观察结构,等于立体照片。四维超...
  • 我们在一维数组开始之前会介绍到一些在学习表达式的时候要注意的点,由于基础的表达式只是比较简单,在这里基本的表达式和用法我们在这里不举例,后期在使用过程中很重要的点就是要注意其表达式的优先级和结合。...
  • 前面输电线路的生成方式...应用高分辨率卫星影像和数字高程模型建立三维选线平台以辅助选线并进行杆塔辅助规划,可有效提高线路路径规划的可行和准确,节省投资。 基础地理数据主要包括DEM、DOM、DLG,杆塔模型以及
  • 将激光的平面信息和电机云台的高度信息结合构建三维模型。通过RANSAC算法从三维点云阵中提取平面。并在图像配准部分对四点算法与RANSAC算法法进行比较,实验结果分析出四点算法能大大的减少配准消耗时间和调高...
  • 前言:因公司业务需求,需要实现dwg、dwf、stl、stp、x_t等二三维图纸在web端在线预览的功能。图纸兼容与浏览器兼容都很重要,经过这段时间的技术调研,基本确认了几种...该产品只针对二维图纸,具有很好的兼容...
  • 二维图像三维

    万次阅读 2018-09-29 11:40:49
    1: 物体表达的必要和重要 机器人能像人一样识别物体,是机器人视觉(robot vision)专家的梦想和追求。要想识别物体,不论是人还是机器人,仅仅看到是不够的,还需要知道物体的表达方式。表达是个与认知科学...
  • 利用低成本的二维激光扫描仪实现针对目标物体的三维重建,为此对基于二维激光扫描技术的三维重建过程中所涉及的相关技术进行了研究分析,为后续开展三维重建的实验研究奠定理论基础。同时在构建基于二维激光扫描仪...
  • 设计了种将轮廓线三维建模与多尺度二维图像处理技术相结合的新方法。该方法的核心是边缘距离图算法。该方法对于复杂环境下的重建结果优于传统方法,对于传统方法较难解决的复杂环境下轮廓线对应和分支问题,能较好...
  • 提出了种基于二维正交投影图像的三维模型相似比较算法。首先计算三维模型的二维正交投影图像,然后提取二维正交投影图像的边缘轮廓夹角特征,并比较这些二维正交投影图像的相似,最后通过二维正交投影图像的...
  • m:表示这个二维数组有多少个一维数组 n :表示每一个一维数组的元素有多少个 b. 注意: i. 其他格式: 1) 数据类型 数组名 [] []=new 数据类型[m][n] 2) 数据类型[] 数组名[] =new 数据类型[m][n] ii
  • 一维指针其实就相当于一维数组,不用去看书上所说的数组在内存中的首地址这些晦涩的话,以此类推 二维指针就相当于二维数组,新手对一维数组的开辟与释放比较容易熟悉,例如上面的a 释放就是 delete []a;...
  • 目前WebGIS的方向逐渐在从二维地球像三维地球转变,作为个GISer,三维开发技术也是必须要掌握的一门技术了,Cesium是个开源的三维地图开发包,是目前市面上用的非常多的个包,接下来我们就一起学习如何使用...
  • 、计算机图形学中坐标系分类 ...2. 仿射变换:是二维坐标到二维坐标的线性变换。满足:平直(直线经过变换之后依然是直线)、平行(平行线依然是平行线); 3. 齐次坐标表示法:用个n+1维的向...
  • c语言创建动态二维数组,大致有种方法。 其一:先申请一个二级指针,再给每个一级指针申请空间。...其:就是用一维数组模拟二维数组。这个无局限,且申请的空间时连续的,符合局部原理,不...
  • 二维空间句法研究的基础上,将城市建筑物的高度作为第三维,进行了基于三维空间句法的城市空间通视研究。在传统二维轴线地图上,创建了三维轴线地图,将轴线交点平均斜率作为评价该点通视指标,通过克吕格插值...
  • 提出种基于二维经验模态分解(2D EMD)的像素匹配方法,并结合五步非等步算法应用于在线三维面形测量中。将正弦条纹投影到在线匀速运动的待测物体上,物体运动产生等效相移,在个条纹周期范围内任意采集五帧变形...
  • 这个过程也让我再次认识到利用编程解决问题的便利,可能过程很难,但是这种可以高度自定义真是太多软件无法替代的 ......1. 问题由来最近阅读论文中,遇到了类图,非常好看,并且在其他论文中也多次遇到...
  • 二维地图引擎市面上比较多,比较有代表的像openlayers、leaflet等。三维地图目前比较流行的开源方案有cesium,它本身是基于webGL实现的地图引擎。cesium在vue上实现需要很多步骤,我之前写过篇总结,是基于vue...
  • 基于二维div塑造的三维动画效果

    千次阅读 2020-01-18 00:14:57
    与纯三维模型相比量更小,对电脑和浏览器要求较低 易加载 易开发 坏处 1.动画效果有局限 只能完成某角度或者某形状的动画 效果 由于CSDN不能放视频演示动画效果(可放大缩小旋转跳跃我闭着眼),无奈只能挂张...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,445
精华内容 978
关键字:

一维性二维性三维性