目录
1.数组的概念
数组是一组相同类型元素的集合;从这个概念中我们就可以发现2个有价值的信息:
- 数组中存放的是1个或者多个数据,但是数组元素个数不能为0。
- 数组中存放的多个数据,类型是相同的。
数组分为⼀维数组和多维数组,多维数组⼀般⽐较多⻅的是⼆维数组。
2.一维数组的创建和初始化
2.1 数组创建
⼀维数组创建的基本语法如下:
type arr_name[常量值];
type表示类型(比如:char、int...),arr_name表示数组名,[常量值]表示数组元素。
存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的⼤⼩和数组的元素类型。
比如·:
int math[10];
就可以表示存储一个班10人的数学成绩。
2.2 数组的初始化
那数组如何初始化呢?数组的初始化⼀般使⽤⼤括号,将数据放在⼤括号中。
//完全初始化
int arr[3]={1,2,3};
//不完全初始化
int arr[3]={1,2};
//错误初始化
int arr[3]={1,1,2,3};//初始化项太多
2.3 数组的类型
去掉数组名留下的就是数组的类型,比如:
int arr[1];
int arr1[2];
int arrr2[3];
arr数组的类型是int [1]
arr1数组的类型是int [2]
arr2数组的类型是int [3]
3.一维数组的使用
3.1数组下标
C语⾔规定数组是有下标的,下标是从0开始的,假设数组有n个元素,最后⼀个元素的下标是n-1,下标就相当于数组元素的编号,如下:
举个例子:
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", arr[0]);
printf("%d\n", arr[9]);
printf("%d\n", arr[3]);
return 0;
}
(后面的代码省略头文件#include<stdio.h>哈)
3.2 数组元素的打印
只要利用for循环,将数组所有元素的下标打印出来就可以了,如下:
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i < 10; i++)
printf("%d ", arr[i]);//从arr[0]-arr[9]循环打印。
return 0;
}
3.3 数组的输入
数组的输入其实也是有一样的道理,如下:
int main()
{
int arr[10] = {0};//注意写法arr[10],不要省略[10]
int i = 0;
for (i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
结果:
4.一维数组在内存中的存储
有了前⾯的知识,我们其实使⽤数组基本没有什么障碍了,如果我们要深⼊了解数组,我们最好能了 解⼀下数组在内存中的存储。
利用前面学的知识,用%p来依次打印数组元素的地址:
int main()
{
int arr[10] = {0};
int i = 0;
for(i=0;i<10;i++)
printf("&arr[%d]=%p\n",i, &arr[i]);
return 0;
}
上图我们可以看到:
随着下标的增长,地址也是由小到大变化的,并且地址从C到0到4到8(C在16进制中表示12),每两个相邻的元素都相差4(因为一个整形是4个字节)。
数组在内存中是连续存放的!
5.sizeof计算数组元素个数
在遍历数组的时候,我们经常想知道数组的元素个数,那C语⾔中有办法使⽤程序计算数组元素个数吗? 这时候我们就可以使⽤sizeof。
sizeof在C语言中是一个关键字,前面我们写过用sizeof来计算类型长度和变量大小,单位是字节。其实,sizeof也可以计算数组的大小。
比如:
int main()
{
int arr[10] = { 0 };
int sz = (sizeof(arr) / sizeof(arr[0]));
printf("%d", sz);
return 0;
}
sizeof(arr):表示计算整个数组所有元素的大小
sizeof(arr[0]):表示计算一个元素的大小,单位字节
输出结果:10,表示数组有10个元素
补充:
问打印的结果是什么?
int main()
{
char arr[] = "welcome to NC";
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d", sz);
return 0;
}
结果为14,因为这里arr是一个字符串,字符串包含了\0,sizeof会算上\0,所以结果为14
以后在代码中需要数组元素个数的地⽅就不⽤固定写死了,使⽤上⾯的计算,不管数组怎么变化,计 算出的⼤⼩也就随着变化了。
6.二维数组的创建
6.1 二维数组的概念
前⾯学习的数组被称为⼀维数组,数组的元素都是内置类型的(内置类型指的是C语言本身具有的类型),如果我们把⼀维数组做为数组的元素,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称为多维数组。
6.2 二维数组的创建
那我们如何定义⼆维数组呢?语法如下:
type arr_name[常量值1][常量值2];
比如:
int arr[3][4];
解释:上述代码中出现的信息
- 3表⽰数组有3⾏
- 4表⽰每⼀⾏有4个元素
- int表⽰数组的每个元素是整型类型
- arr是数组名,可以根据⾃⼰的需要指定名字
7.二维数组的创建
同理一维数组:
7.1 不完全初始化
//不完全初始化
int arr1[3][5]={1,2};
int arr2[2][5]={0};
7.2 完全初始化
int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
7.3 按照行初始化
int arr4[3][5] = {{1,2},{3,4},{5,6}};
注意:初始化的时候可以省略行,但不能省略列。
因为如果省略行,可以根据一行有多少个元素(列)来知道有多少行。
8.二维数组的使用
8.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。
int main()
{
int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
printf("%d", arr[2][4]);
return 0;
}
8.2 二维数组的输入和输出
其实我们只要能够按照⼀定的规律产⽣所有的⾏和列的数字就⾏;以上⼀段代码中的arr数组为例,⾏ 的选择范围是0~2,列的取值范围是0~4,所以我们可以借助循环实现⽣成所有的下标。
int main()
{
int arr[3][5] = { 0 };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
for (j = 0; j < 5; j++)
scanf("%d", &arr[i][j]);
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");//最好给for循环后面打上()
}
return 0;
}
结果如下:
9.二维数组在内存中的存储
同理一维数组
int main()
{
int arr[3][4] = { 0 };
int i = 0;
int j = 0;
for(i = 0; i < 3;i++)
for(j=0;j<4;j++)
printf("%p\n", &arr[i][j]);
return 0;
}
结果如下:
从输出的结果来看,每⼀⾏内部的每个元素都是相邻的,地址之间相差4个字节,跨⾏位置处的两个元素(如:arr[0][3]和arr[1][0])之间也是差4个字节,所以⼆维数组中的每个元素都是连续存放的!
10.数组练习
10.1 练习一:多个字符从两端移动,向中间汇聚。
分析:其实就是要两个数组,利用数组的下标进行两个数组的交换
int main()
{
int i = 0;
char arr1[] = "####################";
char arr2[] = "welcome to NC!!!!!!!";
printf("%s\n", arr1);
for (i = 0; i < 10; i++)//一次交换2个,所以只需要交换一半次就可以了
{
arr1[i] = arr2[i];
arr1[19 - i] = arr2[19 - i];
printf("%s\n", arr1);
}
return 0;
}
代码优化:上面的代码是知道了arr1和arr2的元素个数都为20,那如果不知道呢?
这里就可以用刚刚讲的sizeof来计算数组的元素个数,改进如下
//改进1
int main()
{
int i = 0;
char arr1[] = "######################";
char arr2[] = "welcome to NC!!!!!!!!!";
int sz = sizeof(arr1) / sizeof(arr1[0]);
printf("%s\n", arr1);
for (i = 0; i < sz/2; i++)
{
arr1[i] = arr2[i];
arr1[sz -2- i] = arr2[sz-2 - i];//改为sz-2,因为数组下标从0开始;并且要减去字符串的\0
printf("%s\n", arr1);
}
return 0;
}
如果想要动态的感觉还可以使用Sleep(1000)单位是毫秒,sleep(1000)表示睡眠1000毫秒,即一秒。不过要包含头文件#include <windows.h>
此外还可以使用system("cls");用来清屏。
最终改进如下:
#include <windows.h>
#include <stdio.h>
int main()
{
int i = 0;
char arr1[] = "######################";
char arr2[] = "welcome to NC!!!!!!!!!";
int sz = sizeof(arr1) / sizeof(arr1[0]);
printf("%s\n", arr1);
for (i = 0; i < sz/2; i++)
{
Sleep(1000);
system("cls");
arr1[i] = arr2[i];
arr1[sz -2- i] = arr2[sz-2 - i];
printf("%s\n", arr1);
}
return 0;
}
当然,还可以使用其他方法来写:
#include<string.h>
#include <windows.h>
#include <stdio.h>
int main()
{
char arr1[] = "######################";
char arr2[] = "welcome to NC!!!!!!!!!";
printf("%s\n", arr1);
int left = 0;
int right = strlen(arr1) - 1;
for (; left <= right; left++, right--)
{
Sleep(1000);
system("cls");
arr1[left] = arr2[left];
arr1[right] = arr2[right];
printf("%s\n", arr1);
}
return 0;
}
补充:strlen是求字符串长度的,不会将\0计算进去。使用strlen需要包含头文件#include<string.h>
10.2 练习二:二分查找
在⼀个有序的数组中查找指定的数字n,很容易想到的⽅法就是遍历数组,但是这种⽅法效率⽐较低。
⽐如我买了⼀双鞋,你好奇问我多少钱,我说不超过300元。你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜?你会1,2,3,4...这样猜吗?显然很慢;⼀般你都会猜中间数字,⽐如:150,然后看⼤了还是⼩了,这就是⼆分查找,也叫折半查找。
思路:
- 确定被查找的范围
- 确定被查找范围的左右下标
- 根据左右下标确定中间元素的下标
- 将确定的中间元素的下标和目标元素下标比较,没找到,就根据大小关系确定新的查找范围;找到了,就结束。
分析:比如1,2,3,4,5,6,7,8,9,10个数如何二分查找,找到数字7呢?我们知道这10个数的下标是0到9,那么数字7就是下标6。既然是二分查找,我们可以用下标相加再除以2,那么第一次找到的就是下标为4的数组元素(即(0+9)/2),但是下标4在目标下标6的左边,所以这时候我们让下标5(即下标4的后面一位)加下标9再除二,即得下标7,此时下标7在目标下标6的右边,所以再一次折半查找,用(5+6(下标7的上一位))/2即得下标5.下标5在下标6的左边,所以再一次折半查找,即((6+6)/2)可以得到目标下标6。
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int target = 7;
int left = 0;//left代表左下标
int sz = sizeof(arr) / sizeof(arr[0]);
int right = sz - 1;//right代表右下标数
int find = 0;
while (left != right)
{
int mid = (left + right) / 2;
if (arr[mid] > target)
{
right = mid - 1;
}
if (arr[mid] < target)
{
left = mid + 1;
}
else
{
find = 1;
break;
}
}
if (1==find)
printf("找到了\n");
else
printf("找不到\n");
return 0;
}
11.本章代码
完