数组的概念
数组是一组相同类型元素的集合
数组中存放的是1个或者多个数据,但是数组元素个数不能为0。
数组中存放的多个数据,类型是相同的。
数组分为⼀维数组和多维数组。
1、一维数组
1.1、一维数组的创建及初始化
⼀维数组创建的基本语法:
type arr_name[常量值];
/*类型 数组名 表示数组的元素个数
char
int
short
…… */
①数组的元素是指存放在数组的值,创建数组时可以指定数组的大小和数组的元素类型。
②type 指定的是数组中存放数据的类型,可以是: char、short、int、float 等,也可以自定义的类型。
③arr_name 指的是数组名的名字。
④[](下标引用操作符) 中的常量值是用来指定数组的大小(数组占用的内存空间大小,即数组中元素的数)。
比如
int arr1[10];
其中数组元素类型:int
arr1数组类型:int [10] ,这里注意数组大小不同,数组类型也不同,数组名代表的单元是整个数组,比如sizeof(int[10])和sizeof[arr1]一样大,是sizeof(int[5])的两倍
数组名:arr1
数组的大小:10个数组元素大小,即sizeof(int) * 10
数组的初始化
即创建数组时给定⼀些初始值,一般使用大括号,并将数据放入。
//完全初始化
int arr[5] = {1,2,3,4,5};
//不完全初始化
int arr2[6] = {1};//第⼀个元素初始化为1,剩余的元素默认初始化为0
//错误的初始化 - 初始化项太多
int arr3[3] = {1, 2, 3, 4};
1.2、一维数组的使用
数组下标
一维数组可以存放数据,存放数据的目的是对数据的操作,针对数组的使用规定了数组下标
数组下标就相当于数组元素的编号,下标是从0开始的,假设数组有n个元素,最后⼀个元素的下标是n-1。
int arr[5] = {1,2,3,4,5};
数组 1 2 3 4 5
下标 0 1 2 3 4
使用下标引用操作符[]可以访问某一个数组元素,比如访问下标为1的元素,arr[1]
访问整个数组内容即访问每一个数组元素,只要产生所有元素下标即可
也可以自己给数组输入想要的元素,&arr[i],取下标i这个元素的地址
#include <stdio.h>
int main()
{
int arr[5] = {1,2,3,4,5};
int i = 0;
for(i=0; i<5; i++)
{
scanf("%d", &arr[i]);
}
for(i=0; i<5; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
1.3、一维数组在内存中的存储
内存会被划分为一个个的内存单元,一个单元的大小是1个字节,每个内存单元都有一个编号,这个编号就是地址。
数组在内存中是连续存放的。
数组随着下标的增长,地址是由小到大变化的,每两个相邻的元素之间相差4(因为一个整型是4个字节)
#include <stdio.h>
int main()
{
int arr[5] = {1,2,3,4,5};
int i = 0;
for(i=0; i<5; i++)
{
printf("&arr[%d] = %p\n ", i, &arr[i]);
}
return 0;
}
数组元素个数计算
数组元素的个数=数组数组所占内存空间的总大小/一个元素所占字节的个数
即数组元素的个数=sizeof(arr)/sizeof(arr[0])
#include <stdio.h>
int main()
{
int arr[5] = {0};
printf("%d\n", sizeof(arr));//数组所占内存空间的总⼤⼩,单位是字节
printf("%d\n", sizeof(arr[0]));//计算⼀个元素的⼤⼩,单位是字节
int sz = sizeof(arr)/sizeof(arr[0]);//数组元素个数
printf("%d\n", sz);
return 0;
}
使用strlen() 计算字符串长度时,遇到 \0 的时候就自动停止了。
使用sizeof()计算字符串长度时,'\0'也要算在有效元素里面。
strlen(str2)=随机值.(因为str2的'e'字符后面什么时候遇见'\0'是不确定的,因此随机)
#include <stdio.h>
int main()
{
char str1[] = "abcde";
char str2[] = {'a','b','c','d','e'};
printf("sizeof=%d\nstrlen=%zd\n",sizeof(str1),strlen(str1));
printf("sizeof=%d\nstrlen=%zd\n",sizeof(str2),strlen(str2));
return 0;
}
2、二维数组
二维数组是指把⼀维数组做为数组的元素,同理三维数组是指把二维数组做为数组的元素,二维数组以上的数组统称为多维数组
1 1 2 3 4 5 1 2 3 4 5
int int int int int int int int int int int
1 2 3 4 5
int int int int int
1 2 3 4 5
int int int int int
数组元素 一维数组 二维数组
比如把一行作为一个元素,作为一个一维数组,三行作为一维数组的数组,就是二维数组,把二维数组作为一个数组看就是三维了
2.1、二维数组的创建及初始化
二维数组定义语法:
type arr_name[常量值1][常量值2];
例如:
int arr[3][5];
int arr[3][5];
① 3表示数组有3行
② 5表示每一行有5个元素
③ int表示数组的每个元素是整型类型
④ arr是数组名,可以根据自己的需要指定名字
二维数组的初始化
可以使用大括号对二维数组进行初始化。
//完全初始化,可以看成3行5列
int arr1[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
即 1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
arr1数组
//不完全初始化,可以看成3行5列只有第一行的两个元素不是0,此时除了这两个元素其他元素都是0
int arr2[3][5] = {1,2};
即 1 2 0 0 0
0 0 0 0 0
0 0 0 0 0
arr2数组
//按照⾏初始化,可以看成3行5列每行只有两个元素不是0,其他元素都是0
int arr3[3][5] = {{1,2},{3,4},{5,6}};
即 1 2 0 0 0
3 4 0 0 0
5 6 0 0 0
arr3数组
//初始化时省略⾏,但是不能省略列,可以看成告知列数,即一行放几个后,可以由列数知道有几行
int arr4[][5] = {1,2,3};//个数比列数少,1行,后面补0
即 1 2 3 0 0
arr4数组
int arr5[][5] = {1,2,3,4,5,6,7};//个数比列数多,自动换行
即 1 2 3 4 5
6 7 0 0 0
int arr7[][5] = {{1,2}, {3,4}, {5,6}};//每行个数比列数少,后面补0
即 1 2 0 0 0
3 4 0 0 0
5 6 0 0 0
2.2、二维数组的使用
二维数组的下标
二维数组访问也是使用下标的形式的。
二维数组的行是从0开始的,列也是从0开始的。
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
下标 0 1 2 3 4
0 1 2 3 4 5
1 2 3 4 5 6
2 3 4 5 6 7
根据二维数组的行列下标就能确定数组中的一个元素,如arr[2][4]可以定位7
访问整个二维数组只要能够按照⼀定的规律产生所有的行和列的数字就行
也可以自己给数组输入想要的元素,&arr[i][j],取下标i这个元素的地址
#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]);
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;
}
![](https://i-blog.csdnimg.cn/direct/514c7ee557b24334a4e5071fe18ae559.png)
2.3、二维数组在内存中的存储
二维数组中的每个元素都是连续存放的,每⼀⾏内部的每个元素都是相邻的,地址之间相差4个字节,跨行位置处的两个元素(如:arr[0][4]和arr[1][0])之间也是差4个字节
#include <stdio.h>
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++)
{
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
}
return 0;
}
实际上
int arr[3][5] = { 0 };
实际上
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
下标 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
arr[]0 arr[1] arr[2]
我们假想:下标 0 1 2 3 4
0 0 0 0 0 0
1 0 0 0 0 0
2 0 0 0 0 0
3、变长数组
在C99标准之前,创建数组时数组大小的指定只能使用常量、常量表达式,或者初始化数据可以省略数组大小。
在C99标准之后,变长数组允许我们可以使用变量指定数组大小。
但是变长数组不能初始化,因为当数组长度只有运行时才能确定,程序运行的时候,根据变量的大小来指定数组的元素个数,而不是说数组的大小是可变的,数组的大小一旦确定就不能再变化了
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);//根据输⼊数值确定数组的⼤⼩
int arr[n];
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
return 0;
练习1:多个字符从两端移动,向中间汇聚
编写代码,演示多个字符从两端移动,向中间汇聚
思路:
1、两个字符数组
2、左右两边下标表示出来
3、while循环
每过一秒, 左下标+1,右下标-1
再赋值给第一个数组输出
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "welcome to china";//这里arr1数组的长度已经一开始确定了
char arr2[] = "#################";
int left = 0;//左边下标从零开始
int right = strlen(arr1)-1;//求arr1长度字符串长度
printf("%s\n", arr2);
while(left<=right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
Sleep(1000);//休眠,单位毫米
system("cls");
left++;
right--; //此时arr2=arr1,最后留在屏上
}
retutn 0;
}
练习2:二分查找
在一个升序的数组中查找指定的数字n,除了效率低的遍历数组外,一般都会猜中间数字,然后看大了还是小了,这就是二分查找,也叫折半查找。
思路:
比如10个数,下标0~9,升序情况下找7,下标为6,中间数字下标(0+9)/2=4
只需拿中间数字下标4对应的数和要找的数进行对比,
小了,那么右边的才有可能,左边下标4+1=5接着找中间数字下标(5+9)/2=7,再接着判断
发现大了,左边的才有可能,此时把右边下标7-1=6,中间数(6+5)/2=5,再进行比较
此时下标5小了,肯定是5右边的了,左边下标加1
5+1=7-1=6 //左边下标=右边下标了
(6+6)/2=6//此时中间数字下标和要找的数一样了
|共找了4次
#include<stdio.h>
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
int k = 0;
scanf("%d",&k);
int sz = sizeof(arr)/sizeof(arr[0]);
int left = 0;
int right = sz -1;
while(left<=right)
{
int mid = 0;
mid = (left + right)/2;
if(mid<k)
{
left = mid;
left++;
}
else if(mid>k)
{
right = mid;
right--;
}
else
{
printf("找到了,下标是%d",mid);
break;
}
}
if(left>right)
{
printf("找不到");
}
}