文章目录
📺.前言
欢迎来到C语言数组内容章节,通过前面三层的了解,我们知道了C语言中各种数据类型、关键字、以及结构化语句的了解,通过了解各种数据类型创建不同类型的变量来表示生活中的数据,但是现在我们想一下表示1000个生活中的数据(比如1000种物品的价格),我们还是用1000个不同的变量名来存储它吗?
int a=10,b=20,c=3…………num=1000;写1000次吗?😵😵😵😵显然不可能吧,这样的效率惨不忍睹啊。要把这一组数据存起来,就得用到这一章节的数组了。
🎈🎈.数组基本概念
数组是一个啥子东西呢?其实啊,数组是一组具有相同类型元素的集合.
• 数组中存放的是1个或者多个数据,但是数组元素个数不能为0。
• 数组中存放的多个数据,类型是相同的。
【数组】可以分为一维数组和多维数组,多维数组常见的就是二维数组 |
👇👇👇👇👇
🎈🎈.一维数组的创建和初始化
- 我们来看看这一维数组吧!👀👀👀
🍭🍭.基本语法格式
- 一维数组创建的格式如下:👀👀👀
type array_name[常量值];
- type 表示数组中存放数据的类型,可以是int、short、char、double、float 等,也可以是自定义数据类型。
- array_name 表示数组的名字,取名字作到见名知意就欧克。
- [ ] 中的常量值是⽤来指定数组的⼤⼩的,这个数组的⼤⼩是根据实际的需求指定就⾏。
- 存放在数组里面的值称之为数组的元素。同时数组在创建的时候可以指定数组的大小和数组元素的数据类型。
- 比如存储一个班级上20个人的英语成绩(取整),我们可以写出以下的数组形式:
int English[20];
【在定义数组的时候,需要特别注意中括号里面必须是常量,不能是变量。】
🍭🍭.一维数组的初始化
我们有些时候在创建数组的时候,需要给它赋予初始值,就叫作初始化。
那数组如何初始化呢?数组的初始化⼀般使⽤⼤括号,将数据放在⼤括号中。
`//完全初始化数组
int array[10]={1,2,3,4,5,6,7,8,9,10};
//不完全初始化数组
int array[10]={1,2 3};第一个、第二个、第三个元素对应的值为1,2,3;后面的系统默认初始化为0。
//错误初始化数组
int array[5]={1,2,3,4,5,6,7};初始化的个数大于数组中括号的数字.
🍭🍭.一维数组的类型
数组是有类型的,数组算是⼀种自定义类型,去掉数组名留下的就是数组的类型。 |
int arr1[10];
//它的类型是 int [10]
char arr2[20];
//它的类型是 int [20]
char ch[5];
//它的类型是 char [5]
🍭🍭.一维数组元素的类型
上面是数组的类型,也就是把数组名字去掉,剩下的就是数组的类型。再进一步说,数组元素的类型,就是前面的类型。比如:
int arr[10]; //数组元素有10个数,每个数组元素的类型就是int类型。
🎈🎈.一维数组的使用
学习了⼀维数组的基本语法,⼀维数组可以存放数据,存放数据的⽬的是对数据的操作,那我们如何使⽤⼀维数组呢?接下来我们先去看看数组下标👀👇👇👇
🍭🍭.一维数组下标
- C语⾔规定数组是有下标的,下标是从0开始的,假设数组有n个元素,最后⼀个元素的下标是n-1,下标就相当于数组元素的编号,示例如下:
int array[10]={1,2,3,4,5,6,7,8,9,10};
//下面用图展示:
在C语言中,访问数组下标,提供了一个操作符 [ ],叫作下标引用操作符。
有了下标访问操作符,我们就可以轻松的访问到数组的元素了,⽐如我们访问下标为2的元素,我们使⽤ arr[2] ,想要访问下标是5的元素,就可以使⽤ arr[5] ,如下代码:
#include<stdio.h>
int main()
{
int array[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", array[2]);//3
printf("%d\n", array[5]);//6
return 0;
}
- 结果输出:
🍭🍭.一维数组打印
学了数组的下标,紧接着就是访问数组下标,把存入在数组里面的数据打印出来。看一看数组里面到底是什么?
#include<stdio.h>
int main()
{
int array[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (int i = 0; i < 10; i++)//通过for循环来输出所有元素。
{
printf("%d ",array[i]);
}
printf("\n");
return 0;
}
- 输出结果:
🍭🍭.一维数组的输入
上面是通过直接初始化的,从而数组存储数据元素。那么我们需要自己随意输入数据给数组该咋整呢?如下操作:👇👇👇👇
#include<stdio.h>
int main()
{
int array[10] = { 0 };//直接初始化为0
printf("请输入10个整数:\n");
for (int i = 0; i < 10; i++)
{
scanf_s("%d", &array[i]);//取地址符号 & 别忘了
}
for (int i = 0; i < 10; i++)
{
printf("%d ",array[i]);
}
printf("\n");
return 0;
}
🍭🍭.一维数组的存储地址
我们了解了一维数组的基本操作以后,现在来看看这一维数组在系统里到底是怎样存储的呢?是如何把数据放进去的呢?不妨我们把一个一维数组的数组元素的地址打印出来看一看:👀👀👀👀
#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("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
我们可以看到,随着数组下标不断地增加,数组中元素的地址是不断增加的,相邻的两个元素的地址相差4个,因为一个整型的大小是4个字节。因此,得出结论就是:数组在内存中是连续存储的。
- 从VS调试中,观察数组元素内存也可以看出地址的变化,以及数组的元素存储的下标。
🍭🍭.sizeof计算一维数组大小
数组大小就是数组名中括号里面的数字,但是有些创数组可以省略不写,所以在使用的时候就需要数初始化的个数,比较麻烦。我们可以通过sizeof 来求解数组大小。
#include<stdio.h>
int main()
{
int arr[] = { 1,5,9,4,3,6,45,6,8,2,855,89,5,8,9,56,2,6,9,552,6,4,565,4,55 };
printf("%zd\n", sizeof(arr));//整个数组所占内存的空间的总大小,单位为字节。
printf("%zd\n", sizeof(arr[0]));//一个元素所占内存空间大小,单位也是字节。
int ret = sizeof(arr) / sizeof(arr[0]);//总的除以单个的就是数组大小。
printf("%d\n", ret);//可以理解为单价(单个元素所占内存空间)乘以数量(数组元素个数)等于总价(总的内存空间)。
return 0;
}
🎈🎈.二维数组的创建和初始化
通过介绍一维数组的内容后,再来看二维数组其实很好理解。二维:表示有行有列,也就是在数学中说到的直接坐标,就属于二维。其实,二维是由一维数组变化而来的,一维数组是由相同类型的多个元素组成的,而二维数组的元素就是由多个一维数组的组成的。我们先看二维数组的形式:
🍭🍭.基本语法格式
- 下面是二维数组的基本语法格式:👇👇👇👇
type array_nme[常量值1][常量值2];
//比如下面的二维数组创建:
int arr1[4][5];//表示该二维数组是4行5列的。【一行有5个元素,总共4行,int 表示每个元素是整型,arr1为数组的名字】
🍭🍭.二维数组的初始化
二维数组的初始化和一维数组差不多,可以分为完全初始化和不完全初始化,只是多了注意项!来看一看吧👀👀👀👀
完全初始化: |
//完全初始化
int arr1[3][4]={1,2,3,4, 2,3,4,5, 3,4,5,6};//图解arr1二维数组如下:
通过vs2022调试可以看到各个元素:
不完全初始化: |
//不完全初始化
int arr1[3][4]={1,2,3};//图解如下:
int arr2[3][4]={0};
可以看到不完全初始化的默认为0:
【在定义二维数组的时候,初始化时省略行,但是不能省略列】
int arr[][4]={1,2,3,4};
int arr1[][5]={2,3,4,5,6};
🍭🍭.二维数组的类型和元素类型
二维数组的类型和元素类型的判断,与前面一维数组一样的,去掉数组名字就是二维数组的类型,而前面的定义类型就是数组元素的类型。
🎈🎈.二维数组的使用
我们了解了二维数组的创建和初始化,接下来该如何使用它呢?🏃♀️🏃♀️🏃♀️🏃♀️
二维数组和一维数组是差不多的,也是使用下标访问,只是一维数组下标只有一个数,而二维数组在用下标访问的时候是需要包括行和列的,所以有2个数字。只要锁定了行和列就能唯⼀锁定二维数组中的⼀个元素。我们就来看看二维数组的访问吧!👇👇👇👇
🍭🍭.二维数组的下标
C语言规定,二维数组的行是从0开始的,列也是从0开始的,我们用上面的例子,如下所⽰👀👀👀👀:
int arr1[3][4]={1,2,3,4, 2,3,4,5, 3,4,5,6};
竖起的代表行号,横起的代表列号;都是从0开始访问的。例如:我们访问2行3列的数组元素,代码如下:
#include<stdio.h>
int main()
{
int arr1[3][4] = { 1,2,3,4, 2,3,4,5, 3,4,5,6 };
printf("arr1[%d][%d]=%d\n", 2,3,arr1[2][3]);
return 0;
}
🍭🍭.二维数组的输入和输出
既然了解了二维数组的下标访问,接下来用代码演示数组的输入和输出:👇👇👇👇
#include<stdio.h>
int main()
{
int arr1[3][4] = {0};
printf("请输入二维数组数据:\n");
//循环输入
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
scanf_s("%d", &arr1[i][j]);
}
}
//循环打印
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("arr1[%d][%d]=%d ", i, j, arr1[i][j]);
}
//打印完一行后,换行处理
printf("\n");
}
return 0;
}
🍭🍭.二维数组的存储地址
和查看一维数组的地址一样,我们也把二维数组的地址打印出来瞧一瞧:
#include<stdio.h>
int main()
{
int arr1[3][4] = { 0 };//直接全部初始化为0.
//打印出地址看一看
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("arr1[%d][%d] = %p\n", i, j, &arr1[i][j]);
}
}
return 0;
}
通过vs2022调试来看和打印出来的来看,每⼀行内部的每个元素都是相邻的,地址之间相差4个字节,跨行位置处的两个元素之间也是差4个字节,所以二维数组中的每个元素都是连续存放的。
把上面的地址拆开看就是像下面对应的那样,每4个地址就是每一行的。
🧨🧨.C99标准之后的变长数组
在C99标准之前,C语言在创建数组的时候,数组⼤⼩的指定只能使用常量、常量表达式,或者如果我们初始化数据的话,可以省略数组⼤⼩。
int arr1[5];
int arr2[5+6];
int arr3[]={10,20,30};
- 如上所示的数组大小创建就不灵活。有时候会出现不够或者浪费空间等问题。因此,在C99标准中给⼀个变⻓数组(variable-length array,简称 VLA)的新特性,允许我们可以使用变量指定数组⼤⼩。但是,在我们常用的 vs 平台上是不支持变长数组的,在gcc编译器、刷题网站上一般是支持的,以变长数组不能初始化。比如:小熊猫C++ 是支持的这样写的
int x=0;
scanf(”%d“,&n);
int arr[n];//变长数组
✨✨✨即学即用【数组练习代码】
练习1:多个字符从两端移动,向中间汇聚
#include<stdio.h>
#include<string.h>//strlen()库函数的头文件
#include<windows.h>//sleep()库函数的头文件
int main()
{
char str1[] = { "Welcome to the programming world!" };
char str2[] = { "#################################" };
int left = 0;
int right = strlen(str1) - 1;//因为下标是从0开始的
while (left <= right)
{
str2[left] = str1[left];//把str1中的第一个放入str2中的第一个
str2[right] = str1[right];//把str1中的最后一个放到str2中的最后一个
printf("%s\n", str2);
Sleep(1000);//单位为毫秒
system("cls");
left++;//改变大小,往后移动一位
right--;//往前移动一位
}
printf("%s\n",str2);
return 0;
}
- 结果如下:从两边间隔1秒,向中间汇聚。
练习2:二分查找
在⼀个升序的数组中查找指定的数字n,很容易想到的方法就是遍历数组,但是这种方法效率比较低。
比如我买了⼀双鞋,你好奇问我多少钱,我说不超过300元。你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜?你会1,2,3,4…这样猜吗?显然很慢;⼀般你都会猜中间数字,比如:150,然后看大了还是⼩了,这就是二分查找,也叫折半查找。
- 暴力求解:
//暴力求解:从第一个数开始遍历,每遍历一个数字就与要查找的数字相比较,看是否相等。
#include<stdio.h>
#include<string.h>
int main()
{
int arr[] = { 10,22,35,56,67,85,95,100,130,180 };
int number = 0;//存储需要查找的数字
printf("请输入要查找的数字:\n");
scanf_s("%d", &number);
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
if (number == arr[i])
{
printf("%d在arr数组中的位置在%d处\n", number, i);
}
}
printf("没找到!\n");
return 0;
}
- 结果展示:
- 二分查找
上面的解法不够快,要是需要找的数字在最后,那么需要遍历整个数组,才能找到。
然而,在一个有序数组中,我们可以用二分查找,代码如下:
//二分查找
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//计算大小
size_t len = sizeof(arr) / sizeof(arr[0]);
int number = 0;
printf("请输入要查找的数字:\n");
scanf_s("%d", &number);
int left = 0;
int right = len - 1;
int mid = 0;
int flag = 0;
while (left <= right)
{
mid = (left + right) / 2;
if (arr[mid] == number)
{
flag = 1;
break;
}
if (arr[mid] > number)//说明要找的数字在中间的数的左边
right = mid - 1;
if (arr[mid]< number)//说明在中间的数字的右边
left = mid + 1;
}
if (flag == 1)
printf("找到了,下标是%d\n",mid);
else
printf("没找到!\n");
return 0;
}
- 结果展示:
求中间元素的下标,使⽤ mid = (left+right)/2 ,如果left和right⽐较⼤的时候可能存在问题,可以使⽤下⾯的⽅式:
mid = left+(right-left)/2;
- 有问题的,希望各位大佬多多评论提出。谢谢,下期再见!