数组是一组相同类型元素的集合
1、数组中存放的是1个或者多个数据,但是数组元素个数不能为0
2、数组中存放的多个数据类型是相同的
数组的分类
一维数组、二维数组、多维数组
创建数组的基本语法格式:
type arr_name[常量值];
存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的大小和数组的元素类型。
type:可以是int,short,float,char等。
arr_name:是数组名,起有意义的。
[]中的常量值用来指定数组的大小。
一维数组的初始化
1、完全初始化
#include<stdio.h>
int main(void)
{
int data[10] = { 0,1,2,3,4,5,6,7,8,9 }; //完全初始化
return 0;
}
2、不完全初始化
剩余元素默认初始化为0
#include<stdio.h>
int main(void)
{
int data[10] = { 0,1,2,3,4,5}; //不完全初始化
return 0;
}
3、数组如果初始化了,也可以省略数组的大小指定
#include<stdio.h>
int main(void)
{
int data[] = { 0,1,2,3,4,5}; //可以不指定数组的大小
return 0;
}
数组也是有类型的,数组算是一种自定义的类型,去掉数组名留下的就是数组的类型
#include<stdio.h>
int main(void)
{
int arr[4]; //int arr
char ch[5]; //char ch
}
数组元素下标是从0开始的
#include<stdio.h>
int main(void)
{
int arr[] = { 1,2,3,4,5,6,7 };
printf("%d\n", arr[6]);
//arr[6]找到数组下标为7的数组元素
return 0;
}
运行结果:
7
#include<stdio.h>
int main(void)
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i == 0; i < 10; i++) //循环打印数组arr中的所有元素
{
printf("%d\n", arr[i]);
}
return 0;
}
运行结果:
1
2
3
4
5
6
7
8
9
10
以下也是不完全初始化,只将第一个元素初始化为0,剩余的元素均为0
#include<stdio.h>
int main(void)
{
int arr[10] = { 0 };
return 0;
}
计算机处理的数据,都要加载到内存中处理
内存会被划分成一个个的内存单元,然后给每个内存单元都编号
一个内存单元大小是一个字节
#include<stdio.h>
int main(void)
{
int arr[] = { 0 };
int i = 0;
for (i = 0; i < 10; i++) //循环打印数组arr中的所有元素
{
printf("&arr[%d]=%p\n", i,arr[i]); //%p是取地址符号
}
return 0;
}
运行结果:
&arr[0]=00000000
&arr[1]=CCCCCCCC
&arr[2]=C3AC8F8D
&arr[3]=00DCF998
&arr[4]=006320D3
&arr[5]=00000001
&arr[6]=012EAEF0
&arr[7]=012E32B0
&arr[8]=00000001
&arr[9]=012EAEF0
不难发现,一维数组的地址是连续递增的,随着数组下标的增长一直是由小到大变化的,各个相邻的元素之间相差4
sizeof计算数组元素的大小
sizeof能够计算变量所占内存空间大小,单位是字节
sizeof计算的是变量或者类型的长度,单位是字节
#include<stdio.h>
int main(void)
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr)); //计算的是数组的总大小,单位是字节
printf("%d\n", sizeof(arr[0])); //求数组第一个元素的大小
printf("%d\n", sizeof(arr)/sizeof(arr[0])); //求有几个数组元素
return 0;
}
运行结果:
40
4
10
二维数组的初始化
type arr_name[常量值][常量值];
例如:
int arr[3][5]; //[3][5]分别是行和列
double data[3][5];
1、不完全初始化
#include<stdio.h>
int main(void)
{
int arr[3][5] = { 1,2,3,4,5 }; //不完全初始化
//依次初始化每一行,当不够的时候,剩余的元素初始化为0
//只初始化了第一行
return 0;
}
2、完全初始化
#include<stdio.h>
int main(void)
{
int arr[3][5] = {
{ 1,2,3,4,5},
{ 1,2,3,4,5},
{ 1,2,3,4,5}
};
printf("%d", arr[3][5]);
return 0;
}
初始化的时候可以省略行,但不能省略列
#include<stdio.h>
int main(void)
{
int arr[][5] = {
{ 1,2,3,4,5},
{ 1,2,3,4,5},
{ 1,2,3,4,5}
};
return 0;
}
二维数组的下标行和列都是从0开始的
#include<stdio.h>
int main(void)
{
int arr[3][5] = {
{ 1,2,3,4,5,},
{ 1,2,3,4,5,},
{ 1,2,3,4,5,}
};
printf("%d", arr[1][4]); //打印5
//不完全初始化
//依次初始化每一行,当不够的时候,剩余的元素初始化为0
return 0;
}
运行结果:
5
#include<stdio.h>
int main(void)
{
int arr[3][5] = { 0 };
int i = 0;
printf(">");
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;
}
运行结果:
>1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
打印二维数组中所有元素的地址
#include<stdio.h>
int main(void)
{
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;
}
运行结果:
&arr[0][0]=003FFD74
&arr[0][1]=003FFD78
&arr[0][2]=003FFD7C
&arr[0][3]=003FFD80
&arr[0][4]=003FFD84
&arr[1][0]=003FFD88
&arr[1][1]=003FFD8C
&arr[1][2]=003FFD90
&arr[1][3]=003FFD94
&arr[1][4]=003FFD98
&arr[2][0]=003FFD9C
&arr[2][1]=003FFDA0
&arr[2][2]=003FFDA4
&arr[2][3]=003FFDA8
&arr[2][4]=003FFDAC
每行相邻元素之间相差4
二维数组在内存中也是连续存放的
二维数组是一个一维数组的数组
存放一维数组的数组
二维数组的每个元素是一维数组
变长数组
变长数组的根本特征,就是数组长度只有运行时才能确定,所以变长数组不能初始化。变长数组的好处是程序员不必在开发时,随意为数组指定一个估计的长度,程序可以在运行时为数组分配精确的长度。
1、多个字符从两端向中间移动
#include<stdio.h>
#include<windows.h> //引用Sleep()函数
#include<string.h>
#include<stdlib.h> //引用system()函数
int main(void)
{
char arr1[] = "welcome bo bit";
char arr2[] = "##############";
int left = 0;
int right = strlen(arr1) - 1;
//字符串求长度=长度-1
while (left<=right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
//实现打印一行清空一行的效果
Sleep(1000); //单位是毫秒,使用此函数可以一秒打印一行
system("cls"); //system函数是库函数,可以执行系统指令,cls可以清理控制台屏幕信息
left++;
right--;
}
printf("%s\n", arr2);
//以上函数体内的代码打印完成之后最后一次会清空屏幕
//想要看到全部则需要再次打印一次arr2数组
return 0;
}
printf("%d", strlen(arr1)); //函数求的字符串长度是带结束符'\0'的
printf("%d", sizeof(arr1)); //函数求得字符串长度是不带结束符'\0'的
2、二分查找(折半查找)
折半查找原理,(数组的左下标+数组的右下标)/2,除完之后小数部分直接舍弃
一次折半查找的过程:
1、确定被查找的范围
2、确定被查找范围的左右下标
3、根据左右下标确定中间元素的下标
4、根据中间元素和要找的元素进行比较
5、如果找到则结束,找不到根据大小关系确定新的查找范围
//常规的顺序查找
#include<stdio.h>
int main(void)
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; //升序数组
//在数组中查找key
int key = 0;
printf(">");
scanf("%d", &key);
int sz = sizeof(arr) / sizeof(arr[0]); //sz的值为数组arr的长度包含结束符
int i = 0;
for (i = 0; i < sz; i++)
{
if (arr[i] == key)
{
printf("找到了下标是%d\n",i);
break;
}
}
if (i == sz)
{
printf("找不到了\n");
}
return 0;
}
运行结果:
>8
找到了下标是7
#include<stdio.h>
int main(void)
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 0;
printf(">");
scanf("%d", &k);
int sz = sizeof(arr) / sizeof(arr[0]);
int left = 0;
int right = sz - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] == k)
{
printf("找到了,下标是:%d\n", mid);
break; //找到后跳出循环
}
else if (arr[mid] < k)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
if (left > right)
{
printf("找不到\n");
}
return 0;
}
运行结果:
>5
找到了,下标是:4
优化:
加入标签flag
#include<stdio.h>
int main(void)
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 0;
printf(">");
scanf("%d", &k);
int sz = sizeof(arr) / sizeof(arr[0]); //求元素个数,包含结束符
int left = 0;
int right = sz - 1; //将结束符占用的空间去掉
int flag = 0;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] == k)
{
printf("找到了,下标是:%d\n", mid);
flag = 1; //flag标签
break; //找到后跳出循环
}
else if (arr[mid] < k)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
if (flag==0)
{
printf("找不到\n");
}
return 0;
}
使用折半查找的数组必须是有序的