一、数组的概念:
数组是一组类型相同元素的集合
数组的定义:
1、数组中存放的是一个或多个数据,但是数组元素不能为0
2、数组中存放的多个数据类型是相同的
3、数组分为一维数组和多维数组,多维数组一般比较常见的是二维数组
二、一维数组的创建和初始化
数组的创建
一维数组的基本语法如下:
type arr_name[常量值]
type:数组中存放数据的类型,如int char float等,也可以是自定义类型
arr_name:一维数组的名字,有意义就行
存放在数组的值被称为数组元素,数组在创建的时候可以指定数组的大小值和数组元素的类型
数组的初始化:
int data1[10] = {0};
int data2[10] = {1,2,3};
一维数组的类型:
数组也是有类型的,数组算是一种自定义类型,去掉数组名留下的就是数组类型
比如:
int arr1[10]; int [10]
char ch[5]; char [5]
就是数组的类型
三、一维数组的使用:
数组的下标:
数组的下标指的是数组元素的编号,下表是从0开始的且最后一个元素的下表是n-1
int arr[] = {1,2,3,4,5,6,7,8,9,10}
这个代码等价于:int arr[10] ={1,2,3,4,5,6,7,8,9,10}
数组的使用:
在c语言中数组访问提供了一个操作符[]。这个操作符叫做下标引用操作符
如果我们想要访问数组arr[7]和arr[9]里面的元素的话:
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10}
printf("%d",arr[7]);
printf("%d",arr[9]);
return 0;
}
这样我们就会在屏幕上打印出数组arr中下标为7和9的元素了
数组元素的打印:
如果我们想要访问整个数组的内容,那我们只需要把数组的所有下标全部访问一遍
比如:
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for(int i = 0;i<10;i++)
{
printf("%d",arr[i]);
}
return 0;
}
只需要用一个for循环来把数组的所有下标全部访问一遍,这种方法我们称为数组的遍历。
数组的输入:
其实数组的输入跟数组元素的打印差不多
int main()
{
int arr[10] = {0};//创建数组
for(int i = 0;i<10;i++)//对数组进行遍历
{
scanf("%d",&arr[i]);//对数组进行输入
}
return 0;
}
四、一维数组在程序中的储存:
数组在内存中是连续存放的
随着下标的增长,地址是由小(低)到大(高)的变化
五、sizeof计算元素的个数:
int main()
{
int arr[10] = {0};
printf("%zd\n",sizeof(arr));//计算的是数组总大小,比如说int是4字节的,
//一共有10个元素输出就是40字节
printf("%zd\n",sizeof(arr[0]));//单个数组元素的大小
printf("%zd\n",sizeof(arr)/sizeof(arr[0]));//计算的是数组中元素的个数
return 0;
}
这里提示一下sizeof和strlen的区别:
strlen 用于计算字符串的实际长度,sizeof 用于计算数据类型或者变量占用的字节数。
sizeof
:这是一个操作符,并非函数。在编译阶段,它就能计算出数据类型或者变量所占用的内存字节数。
strlen
:这是一个标准库函数,在运行时,它会计算以空字符 '\0'
结尾的字符串的实际长度。
六、二维数组的创建:
二维数组的概念:
前面学习的数组被称为一维数组,数组的元素都是内置类型的,如果我们把一维数组作为数组的元素,这时候就是二维数组,二维数组作为数组元素被称为三维数组,二维数组及以上的数组统称为多维数组
说白了就是由多个一维数组组合在一起。
二维数组的创建:
二维数组的语法如下:
type arr_name [常数值1][常数值2];
比如下列这两个二维数组:
int arr1[2][4];
char arr2[3][5];
就拿数组arr1[2][4]来说
type:数组的类型的定义是int类型
arr是数组名,可以根据自己的需要来指定名字
date数组意思基本一样
2表示数组有2行
4表示每一行有4个元素
七、二维数组的初始化:
在创建变量或者数组的时候,给定义些初始值,被称为初始化。
二维数组不完全初始化:
例如:int arr1[3][5] = {1,2};
int arr2[3][5] = {0};
这两个数组的初始化如下:
因为没有完全初始化的话,除了已经初始化的值意外,系统默认没有初始化的值为0
二维数组完全初始化:
当然有不完全初始化肯定也有完全初始化
例如:int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6 ,3,4,5,6,7};
按照行初始化:
例如:
int arr4[3][5] = {{1,2},{3,4},{5,6}};
初始化时省略行,但是不能省略列:
例如:
int arr5[][5] = {1,2,3};
int arr6[][5] = {1,2,3,4,5,6,7};
int arr7[][5] = {{1,2},{3,4},{5,6}};
八、二维数组的使用:
二维数组的下标:
其实二维数组的下标跟一维数组的下标一样都是从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数组为例,⾏的选择范围是0~2,列的取值范围是0~4,所以我们可以借助循环实现⽣成所有的下标。
如下:
int main()
{
int arr[3][5] = {1,2,3,4,5 ,2,3,4,5,6 ,3,4,5,6,7};
for (int i = 0;i<3;i++)//产生行号
{
for (int j = 0;j < 5;j++)//产生列号
{
scanf("%d",&arr[i][j]);//输入数据
}
}//输出
for (int i = 0;i < 3;i++)
{
for (int j = 0;j < 5;j++)
{
printf("%d ",arr[i][j]);//输出数据
}
printf("\n");
}
return 0;
}
代码结果如下:
输出的值取决于用户输入的值
二维数组在内存中的存储:
,每⼀⾏内部的每个元素都是相邻的,地址之间相差4个字节,跨⾏位置处的两个元素(如:arr[0][4]和arr[1][0])之间也是差4个字节,所以⼆维数组中的每个元素都是连续存放的。
十、C99中的变长数组:
在C99标准值前,c语言在创建数组的时候,数组大小的指定只能使用常量、常量表达式,或者如果我们初始化数据的话,可以省略数组的大小。
例如:
int arr1[10];
int arr2[3+5];
int arr3[]={1,2,3};
这样的语法限制,让我们创建数组就不够灵活,有时候数组大了浪费空间,有时候数组又小了不够用。
因此C99中给了一个变长数组的新特性,允许我们可以使用变量指定数组大小:
变长数组的大小在运行的时候确定,不能改变
一旦确定了大小后,它的大小是固定的,无法改变。
注意:vs编译器上不支持C99,可以使用gcc编译器
接下来让我们做一下数组的练习吧:
练习
练习一:多个字符从两端移动,向中间汇聚
编写代码,演示多个字符从两端移动,向中间汇聚
#include<windows.h>
#include<string.h>
#include<stdlib.h>
int main()
{
do
{
char arr1[] = "meizhu I love you!!!";
char arr2[] = "********************";
int left = 0;
int right = strlen(arr1) - 1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
Sleep(500);//sleep是windows.h中的函数,单位是毫秒,可以让程序暂停一段时间
system("cls");//清理屏幕上的信息,他是stdlib.h中的函数
printf("%s\n", arr2);
left++;
right--;
}
} while (1);//死循环,也就是外面广告牌的工作原理。
return 0;
}
结果如下:
实际上这个程序是不会停止的,是因为我按下了CTRL+C
这段程序中有两个陌生知识一个是Sleep函数,一个是system函数的清屏的用法
Sleep函数的用法是:
Sleep(常量);
调用Sleep函数需要#include这个头文件
system函数的用法是:
system("cls");
调用system函数需要#include这个头文件
练习二:二分查找
在一个升序的数组中查找指定的数字n,很容易想到的方法就是遍历数组,但是这种方法效率比较低。
什么是二分查找:就比如说猜一个数字100-200之间,很多人都会直接猜150,直接就是对半,大了就会猜100-150之间的数,这样会快捷很多。
当然,使用二分查找是有条件的:必须是有序的
int main()
{
int arr[20] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 };
int left = 0;//数组左边的下标
int k = 0;
scanf("%d", &k);//输入需要查找到数
int right = sizeof(arr) / sizeof(arr[0])-1;//先算数组元素的个数,再减一就是最后元素的下标了
int flag = 0;
while (left<=right)//当left>right的时候就已经超出数组的范围了,所以就需要退出循环
{
int mid = left + (right - left) / 2;//right - left:计算当前查找区间的长度
//(right - left) / 2:算出当前查找区间长度的一半。
//left + (right - left) / 2:在左边界 left 的基础上,加上区间长度的一半,从而得到中间位置的索引
if (arr[mid] < k)//如果比需要查找到数小,下标向右移一位
{
left = mid + 1;
}
else if (arr[mid] > k)//如果比需要查找到数大,下标向左移一位
{
right = mid - 1;
}
else
{
printf("找到了,下标是:%d\n", mid);
flag = 1;
break;
}
}
if (flag == 0)
{
printf("找不到\n");
}
return 0;
}
代码结果如下:
二分查找可以大大缩减查询的时间。