数组
一、数组的概念
数组是一组相同类型元素的集合 分为一维数组和多为数组,多维数组常见的是二维数组。
1、数组中存放的是一个或多个数据,但是数组元素个数不能为0.
2、数组中存放的多个数据,类型是相同的。
二、数组的创建和初始化
1、一维数组:type arr_name[常量值];
①不初始化
int arr1[10]; char arr2[8]
②完全初始化
int arr[5]={1,2,3,4,5} //{}内元素个数等于数组长度
③不完全初始化
int arr[5]={1,2,3} //{}内元素个数小于数组长度,未初始化部分默认值是0
④不指定长度,通过大括号内元素个数确定数组长度
int arr[]={1,2,3,4} //数组如果初始化了, []内可以省略长度,编译器根据{}的内容长度确定数组的长度
⑤错误的初始化
int arr[5]={1,2,3,4,5,6} //{}内的元素个数大于[]定义的数组长度
2、数组的类型
数组也是有类型的,算是一种自定义类型,去掉数组名留下的就是数组的类型
如:
int arr1[4];
int arr2[5];
cahr ch[6];
arr 1的数组类型是 int [4]
arr 2的数组类型是 int [5]
ch的数组类型是 char [6]
四、一维数组的使用
1数组下标
C语言规定数组是有下标的,下标从 0 开始,假设数组有n个元素,最后一个元素的下标是 n-1 ,下标就相当于数组元素的编号
如下:
int arr[10]={1,2,3,4,5,6,7,8,9,10};
在c语言中数组的访问提供了一个操作符 [ ] ,这个操作符叫下标引用操作符
比如要访问下标为7的元素,就可以使用 arr[7],想要访问下标为3的元素,就可以使用 arr[3]
2、数组元素的打印(遍历)
使用for循环产生0~9的下标,用下标访问打印
#include <stdio.h>
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]);
}
}
3、使用for循环依次向数组中输入数据
#include <stdio.h>
int main()
{
int arr[10];
for (int i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
}
4、一维数组在内存中的存储
打印数组元素的地址 %p用于打印地址
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
for (int i = 0; i < 10; i++)
{
printf("%p\n", &arr[i]);
}
}
从输出结果分析,数组随着下标的增长,地址越来越大,且每两个相邻地址差为4(因为一个整型占用4个字节)
所以:数组在内存中是连续存放的
5、sizeof计算数组元素个数
在遍历数组的时候,往往需要知道数组元素的个数,这时可以使用sizeof(计算类型或变量大小,返回其占用的字节数)
int main()
{
int arr[10] = { 0 };
int len = sizeof(arr) / sizeof(arr[0]); //用整个数组的大小(字节)/单个数组元素的大小(字节)
printf("%d", len);
}
五、二维数组
1、二维数组的概念
如果把以为数组作为数组的元素,就是二维数组,二维数组作为数组的元素,就是三位数组,二维及以上的数组成为多维数组
2、二维数组的创建 type arr_name[常量1] [常量2]
int arr[3][5]
double [2][8]
[3]可以看作行,[5]可以看作列 3行5列
[2]可以看作行,[8]可以看作列 2行8列
六、二维数组的使用
1、二维数组初始化
①不完全初始化
int arr1[3][5]={1,2}; int arr2[3][5]={0}
int arr[3][5]={1,2,3,4,5,6,7}; //依次初始化每一行,剩余不够的默认为0
②完全初始化
int arr[3][5]={1,2,3,4,5 2,3,4,5,6, 3,4,5,6,7};
③按照行初始化
int arr[3][5]={{1,2},{3,4},{5}};
{}内就是一行,该行剩余元素默认为0
④行可以省略
int arr[][5]={1,2,3,4,5,6,7};
可以不指定多少行,但一定要指定多少列,否则不知道多少列后到下一行
看一下这几种的结果
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}};
2、二维数组的下标
二维数组的访问也使用下标形式,二维数组具有行和列,只要锁定了行和列就能唯一确定数组中的一个元素,也是从0开始。
int arr[3][5]={1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
绿色为行号,蓝色为列号,比如第2行,第4列,arr[2] [4] 就能快速定位到 7
#include <stdio.h>
int main()
{
int arr[][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
printf("%d", arr[2][4]);
return 0;
}
3、使用for循环嵌套一次往数组中赋值和遍历
int main()
{
int arr[3][5] = {0};
for (int i = 0; i < 3; i++) //i控制行号
{
for (int j = 0; j < 5; j++) //j控制列号
{
scanf("%d", &arr[i][j]); //向第i行j列赋值
}
}
for (int i = 0; i < 3; i++) //i控制行号
{
for (int j = 0; j < 5; j++) //j控制列号
{
printf("%d ", arr[i][j]); //打印第i行j列的元素
}
printf("\n"); //打印完一列后换行
}
}
也可以将输入和打印写到同一个循环中
#include <stdio.h>
int main()
{
int arr[3][5] = { 0 };
int i = 0;
for (i = 0; i < 3; i++) //i控制行号
{
int j = 0;
for (j = 0; j < 5; j++) //j控制列号
{
scanf("%d", &arr[i][j]); //向第i行j列赋值
printf("%d ", arr[i][j]); //打印
}
}
return 0;
}
上一种方法,必须将全部元素初始化后一块打印,而输入和打印写进同一个循环,可以边打印遍输出,每次输入几个就打印几个。
4、二维数组在内存中的存储
#include <stdio.h>
int main()
{
int arr[3][5] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
for (int i = 0; i < 3; i++) //i控制行号
{
for (int j = 0; j < 5; j++) //j控制列号
{
printf("&arr[i][j]=%p\n",&arr[i][j]);
}
}
return 0;
}
二维数组在内存中也是连续存放的!!!,存完一行,到下一行的差也是4个字节(int)
七、C99标准
C99标准之前,数组的大小是由常量指定的。
C99标准之后,引入了变长数组的概念,可以用变量来指定数组的大小。
VS默认不支持C99中的变长数组,可以使用小熊猫DevC++来测试,它自带gcc编译器,支持C99之后的变长数组。
变长数组
变长数组的根本特性,就是数组长度只有在运行时才能确定,所以,变长数组不能初始化。他的好处是程序员不必在开发时,随意为数组指定一个估计的长度,程序可以在运行时为数组分配精确的长度。
迷惑点:变长数组的意思是数组的大小可以用变量来指定,在程序运行的时候,根据变量的大小来指定数组元素的个数,而不是说数组的大小是可变的。
因为,数组的大小一旦确定就不能再变化了
练习
1、字符从两端向中间逐个显示
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <stdlib.h>
int main(){
char arr1[]="welcome to bit"; //[welcome to bit\0]
char arr2[]="##############";
int left = 0; //第一个元素下标
int right = strlen(arr1)-1; //找到末尾元素下标,数组是char,可以直接用strlen计算长度,一个字符就是一个元素
while(left<=right){
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n",arr2);
Sleep(1000); //等待1000毫秒 Sleep的头文件 windows.h
system("cls"); //清除屏幕,使打印结果始终在第一行 sys的头文件 stdib.h
left++;
right--;
}
printf("%s",arr1); //循环的最后cls清屏了,这里再打印一次
// return 0;
}
2、二分查找
int main(){
int arr[]={1,2,3,4,5,6,7,8,9,10,11};
int k= 11;
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) //如果在数组左半边
right= mid-1; //将中间下标左移并赋值给右边下标,这里一定要减1,否则会进入死循环
else if(arr[mid]< k) //如果在数组右半边
left= mid+1; //将中间小标右移并赋值给嘴边下标,这里一定要加1,否则会进入死循环
else{
printf("找到了,下标是%d",mid);
break;
}
}
if(left>right)
printf("找不到");
}