C语言入门(九):二维数组的介绍
一:二维数组的结构
1.二维数组的概念
前⾯学习的数组被称为⼀维数组,数组的元素都是内置类型的,如果我们把⼀维数组做为数组的元 素,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称 为多维数组。
具体结构如下
2.二维数组的原型
原型:type arr_name[常量值1][常量值2]
type是元素类型 arr后面的是数组名字 常量1指行 常量2指列
代码如下
int表⽰数组的每个元素是整型类型
arr是数组名,可以根据⾃⼰的需要指定名字 data数组意思基本⼀致。
三行七列,总共是3行,每一行有7个元素
char ch[3][7];
三行五列
int arr[3][5]; //三行五列
二行八列
double date[2][8]; //二行八列
二:二维数组的初始化
在创建变量或者数组的时候,给定⼀些初始值,被称为初始化。 那⼆维数组如何初始化呢?像⼀维数组⼀样,也是使⽤⼤括号初始化的。
代码如下
1.不完全初始化(和一维初始化一样)
用监视我们可以看到前三个元素是1,2,3后面没有初始化的元素全部会是0来代替
int main()
{int arr1[3][5] = {1,2,3};//用监视我们可以看到前三个元素是1,2,3后面没有初始化的元素全部会是0来代替int arr2[3][5] = {0};//全部是0return 0;
}
结果可以看这个来进行分析、
下面这个图就是我们具体的结构图,上面代码结果的下面详细结构图
2.完全初始化
部分代码如下
int main()
{int arr3[3][5] = { 1,2,3,4,5 , 2,3,4,5,6 , 3,4,5,6,7 };return 0;
}
结果下图
3.按照⾏初始化
指定某个位置进行初始化,这里我们是第一行放1,2由于我们每一行有5个元素,后面我们没有给定的初始化全部用0代替
int date[3][5] = { {1,2},{3,4},{5,6} };//指定某个位置进行初始化,这里我们是第一行放1,2由于我们每一行有5个元素,后面我们没有给定的初始化全部用0代替
注意:数组在初始化的时候, 行可以省略,列不可以省略
int main()
{int arr5[][5] = { 1,2,3 };//只有1行,监视结果:1,2,3,0,0int arr6[][5] = { 1,2,3,4,5,6,7 };//2行 第一行是1,2,3,4,5第二行是6,7,0,0,0int arr7[][5] = { {1,2},{3,4},{5,6} };//3行 第一行1,2,0,0,0第二行 3,4,0,0,0第三行 5,6,0,0,0 return 0;
}
只有1行,监视结果:1,2,3,0,0
int arr5[][5] = { 1,2,3 };//只有1行,监视结果:1,2,3,0,0
2行 第一行是1,2,3,4,5
第二行是6,7,0,0,0
int arr6[][5] = { 1,2,3,4,5,6,7 };//2行 第一行是1,2,3,4,5第二行是6,7,0,0,0
3行 第一行1,2,0,0,0
第二行 3,4,0,0,0
第三行 5,6,0,0,0
int arr7[][5] = { {1,2},{3,4},{5,6} };//3行 第一行1,2,0,0,0第二行 3,4,0,0,0第三行 5,6,0,0,0
结构图如下
三:⼆维数组的使用
1.⼆维数组的下标
当我们掌握了⼆维数组的创建和初始化,那我们怎么使⽤⼆维数组呢? 其实⼆维数组访问也是使⽤下标的形式的,⼆维数组是有⾏和列的,只要锁定了⾏和列就能唯⼀锁定 数组中的⼀个元素。 C语⾔规定,⼆维数组的⾏是从0开始的,列也是从0开始的,如下所⽰:
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
结构图如下
图中最右侧绿⾊的数字表⽰⾏号,第⼀⾏蓝⾊的数字表⽰列号,都是从0开始的,⽐如,我们说:第2 ⾏,第4列,快速就能定位出7
#include <stdio.h>int main(){int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};printf("%d\n", arr[2][4])return 0;]
输出的结果如下
2.用下标来打印二维数组的元素(和一维数组一样,下标的 行 列 都是从0开始的)
int main()
{int arr[3][5] = { 1,2,3,4,5 , 2,3,4,5,6 , 3,4,5,6,7 };printf("%d\n", arr[1][3]);//结果是5return 0;
}
输出结果如下
3.打印我们的所有元素的方法,利用循环来打印
完整代码如下
int main()
{int arr[3][5] = { 1,2,3,4,5 , 2,3,4,5,6 , 3,4,5,6,7 };int i = 0;//将 行 存放起来for (i = 0; i < 3; i++){int j = 0;//将 列 存放起来for (j = 0; j < 5; j++){printf("%d ", arr[i][j]);//将行 列 打印出来}printf("\n");//这里的printf可以省略,但是为了好看,所有我就加上了}return 0;
}
解析
将 ‘行’ 存放起来
int i = 0;//将 行 存放起来
将 列 存放起来
int j = 0;//将 列 存放起来
这里的printf可以省略,但是为了输出的结果好看,所有我就加上了
}printf("\n");//这里的printf可以省略,但是为了好看,所有我就加上了
将行 列 打印出来
printf("%d ", arr[i][j]);//将行 列 打印出来
输出结果如下
四:二维数组的输入和输出
访问⼆维数组的单个元素我们知道了,那如何访问整个⼆维数组呢? 其实我们只要能够按照⼀定的规律产⽣所有的⾏和列的数字就⾏;以上⼀段代码中的arr数组为例,⾏ 的选择范围是0~2,列的取值范围是0~4,所以我们可以借助循环实现⽣成所有的下标。
1.输入
int main()
{int arr[3][5] = {0};int i = 0;for (i = 0; i < 3; i++)//产生行号{int j = 0;for (j=0; j<5; j++)//产生列号{scanf("%d ", &arr[i][j]);//输入数据,这里的行和列可以反过来,就是竖着打印也是可以的}}
给数组进行初始化
int arr[3][5] = {0};
输入数据,这里的行和列可以反过来,就是竖着打印也是可以的
scanf("%d ", &arr[i][j]);//输入数据,这里的行和列可以反过来,就是竖着打印也是可以的
2. 输出
for (i = 0; i < 3; i++)//产生行号{int j = 0;for (j = 0; j < 5; j++)//产生列号{printf("%d ", arr[i][j]);//输出数据}printf("\n");}return 0;
完整的二维数组的输入与输出的代码
int main()
{int arr[3][5] = {0};int i = 0;for (i = 0; i < 3; i++)//产生行号{int j = 0;for (j=0; j<5; j++)//产生列号{scanf("%d ", &arr[i][j]);//输入数据,这里的行和列可以反过来,就是竖着打印也是可以的}}// 输出for (i = 0; i < 3; i++)//产生行号{int j = 0;for (j = 0; j < 5; j++)//产生列号{printf("%d ", arr[i][j]);//输出数据}printf("\n");}return 0;
}
输出的结果如下
五:二维数组在内存中的存储
像⼀维数组⼀样,我们如果想研究⼆维数组在内存中的存储⽅式,我们也是可以打印出数组所有元素 的地址
代码如下
int main()
{int arr[3][5] = { 0 };int i = 0;//把数组每个元素的地址打印出来for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("&arr[%d}[%d] = %p\n", i,j, &arr[i][j]);}}return 0;
}
把数组每个元素的地址打印出来
printf("&arr[%d}[%d] = %p\n", i,j, &arr[i][j]);
输出的结果
从输出的结果来看,每⼀⾏内部的每个元素都是相邻的,地址之间相差4个字节,跨⾏位置处的两个元 素(如:arr[0][4]和arr[1][0])之间也是差4个字节,所以⼆维数组中的每个元素都是连续存放的。 如下图所⽰:
了解清楚⼆维数组在内存中的布局,有利于我们后期使⽤指针来访问数组的学习。
六:. C99中的变⻓数组
在C99标准之前,C语⾔在创建数组的时候,数组⼤⼩的指定只能使⽤常量、常量表达式,或者如果我 们初始化数据的话,可以省略数组⼤⼩
这样的语法限制,让我们创建数组就不够灵活,有时候数组⼤了浪费空间,有时候数组⼜⼩了不够⽤ 的。 C99中给⼀个变⻓数组(variable-lengtharray,简称VLA)的新特性,允许我们可以使⽤变量指定 数组⼤⼩。 请看下⾯的代码
上⾯⽰例中,数组 arr 就是变⻓数组,因为它的⻓度取决于变量 n 的值,编译器没法事先确定,只 有运⾏时才能知道 n 是多少。 变⻓数组的根本特征,就是数组⻓度只有运⾏时才能确定,所以变⻓数组不能初始化。它的好处是程 序员不必在开发时,随意为数组指定⼀个估计的⻓度,程序可以在运⾏时为数组分配精确的⻓度。有 ⼀个⽐较迷惑的点,变⻓数组的意思是数组的⼤⼩是可以使⽤变量来指定的,在程序运⾏的时候,根 据变量的⼤⼩来指定数组的元素个数,⽽不是说数组的⼤⼩是可变的。数组的⼤⼩⼀旦确定就不能再 变化了。 遗憾的是在VS2022上,虽然⽀持⼤部分C99的语法,没有⽀持C99中的变⻓数组,没法测试;下⾯是 我在gcc编译器上测试,可以看⼀下。
第⼆次测试,我给n中输⼊10,然后输⼊10个数字在数组中,并正常输出
七:数组练习
问题:多个字符从两端移动,向中间汇聚
完整代码如下
int main()
{char arr1[] = "welcome to bit !!!!!!";char arr2[] = "***************************";int left = 0;//左边的字符int right = strlen(arr1) - 1;//右边的字符while (left<=right){arr2[left] = arr1[left];//将arr1左边的字符放到arr2下面左边对应的字符arr2[right] = arr1[right];//和上面一样,这里是和右边对应的printf("%s\n", arr2);Sleep(500);//单位是毫秒,需要一个头文件 #include<windows.h>,代码程序会每隔1000毫秒进行下一个代码system("cls");//system是给电脑下指令的意思,cls是清理输出屏幕的信息left++;right--;}return 0;
}
左边的字符
int left = 0;//左边的字符
右边的字符
int right = strlen(arr1) - 1;//右边的字符
将arr1左边的字符放到arr2下面左边对应的字符
和上面一样,这里是和右边对应的
arr2[left] = arr1[left];//将arr1左边的字符放到arr2下面左边对应的字符
arr2[right] = arr1[right];//和上面一样,这里是和右边对应的
单位是毫秒,需要一个头文件 #include<windows.h>,代码程序会每隔1000毫秒进行下一个代码
Sleep(500);//单位是毫秒,需要一个头文件 #include<windows.h>,代码程序会每隔1000毫秒进行下一个代码
system是给电脑下指令的意思,cls是清理输出屏幕的信息
system("cls");//system是给电脑下指令的意思,cls是清理输出屏幕的信息
八:数组的二分查找(折半查找)
注意:使用的前提是,必须是连续有序的数组
这里我们先用普通的查找方式
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int k = 7;//在数组中找数字7int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int flag = 0;for (i = 0; i < sz; i++){if (k == arr[i]){printf("找到了,下标是:%d", i);flag = 1;//非0为真break;}}if (flag == 0)//0为假{printf("超出范围\n");}return 0;
}
范围里面的情况
超出范围的情况(将k设置为范围之外的元素17)
使用二分查找(折半查找)方式
完整代码如下
这里的输出的结果和上面的一样,超不超出范围取决于k和arr的元素是多少
这里的flag是表示真假的意思
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int k = 100;//在数组中找数字7int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int flag = 0;int left = 0;//左下标int right = sz - 1;//右下标while (left <= right){int mid = (left + right) / 2;//计算中间数的下标,mid是中间的意思int mid = left + (right - left) / 2;//这个计算中间数的下标更好一点if (arr[mid] < k)// arr[mid] 是我们中间下标的那个数,将它与我们要找的那个数 k 进行比较{left = mid + 1;//当我们的中间数的下标小于k的时候,我们就可以知道左边所有的数都不符合我们那个数,因为小了,于是我们要从右边在进行一次二分查找,依次循环}else if (arr[mid] > k)//同上,这里是大于k的情况{right = mid - 1;}else{flag = 1;printf("找到了,下标是%d\n", mid);break;}}if (flag == 0){printf("超出范围了\n");}return 0;
}
以上就是关于二维数组的全部内容了