C 语言学习笔记(8)
内容提要
- 数组
- 数组的概念
- 一维数组
数组
数组的概念
什么是数组
数组是相同类型,有序数据的集和
数组的特征
- 数组中的数据被称之为数组的元素(所谓的元素,其实就是数组的每一个匿名的变量空间),是同构。
- 数组中的元素存放在内存空间(char play_name[6]:申请在内存中开辟六块连续的基于char型的变量空间)
衍生概念:下标(索引)
-
下标或者索引代表了数组中元素距离第1个元素(首地址所在的元素)的偏移量。举例:第1个元素距离第1个元素的偏移量是0,所以数组中下标是从0开始的。
-
数组的下标是从0开始(数组的最大下标 = 数组的元素个数 - 1)
int a:在内存中开辟一块空间,该空间的大小是4个字节。
int a1,a2,a3,a4,a5:在内存中开辟连续的5块空间,每一块空间的大小是4个字节。但是不如数组方便。
int arr[5]:在内存中开辟连续的5块空间,每一块空间的大小是4个字节。
一维数组
数组的定义
语法:
数据类型 数组名[数组容量];
注意:数据类型又被称作类型说明符,数组容量又被称作数组元素个数或者数组的大小|长度。
说明:
-
数组的数据类型又数组中的元素来决定。也就是说数据类型,有元素的类型来决定,元素是什么类型,数组就是什么类型。同一个数组中,所有的类型都是一致的。
-
**数组名也是标识符,我们所说的数组(名),大家可以理解为数据类型是数组的变量(名)。**命名规则与变量的规则一样,唯一的区别是变量使用单数,数组使用复数。也就是说以字母或者下划线开头,后面只能跟字母、数字、下划线。
-
数组容量还可以叫做常量表达式,**其值必须是整数。**关于数组容量的类型:
-
C89标准:只支持常量和符号常量,不支持变量。
#define SIZE 5int length = 5;int arr1[5]; //常量(字面量) 正确 int arr2[SIZE]; //符号常量 正确 int arr3[length]; //变量 错误
-
C99标准:引入==变长数组(VLA)==的概念,就是可以使用变量,数组在运行的时候决定大小。举例:
int length = 5; //创建变量length,赋值5 int arr[length]; //创建一个容量为5的数组,这里是正确的 length = 10; //此时虽然变量length的值改变了,但是数组容量并不会改变,依然是5
-
类型:
代表了数组中元素的类型。数组的空间=数组中所有元素空间之和
容量:
数组中能存储多少个元素,数组容量一定是一个整型。
深入理解:
①定义一个数组,相当于申请了一个可以容纳所指定元素个数的内存单元。所申请的内存单元室连续的。
②定义一个数组,相当于定义了多个匿名的变量,这些变量可以通过数组名[下标]
来访问。、
范例:
//定义一个数组
int arr[10]; //定义一个存放10个int类型的元素的数组
关于数组中元素默认值的问题:
全局变量和static修饰的变量:元素的默认值是0
局部变量:元素的默认值是随机值,此时建议用户初始化。
举例:
int g_age; //这是全局变量,全局变量定义在函数的外部,默认值是0 int g_age[5]; //这是全局数组,元素的默认值是0int main() {int p_age; //局部变量,局部变量定义在函数的内部,默认值是随机值,视同前需要初始化int p_ages[5]; //局部数组,局部数组定义在函数内部,元素默认值是随机值,使用前需要初始化 }
注意:关于默认值,整型和浮点型的默认值是
0
,字符型的默认值是\0
数组元素的访问
原则:
数组中的元素不能一次性访问所有,只能一个一个访问。
语法:
-
取值:
数组名[下标];
-
赋值:
数组名[下标] = 值;
举例:
//定义一个存储10个元素的int数组
int arr[10];//给数组的第一个元素进行赋值
arr[0] = 88;//访问数组中的第一个元素的值
int a = arr[0];//修改数组中的第一个元素的值
arr[0] = 66;int c = arr[9]; //如果是一个定义在函数中的数组,此时访问的元素的值是 随机值
int b = arr[10]; //error,报一个下标越界异常,因为访问了一个位置的内存空间
案例
-
需求:利用循环给数组元素a[0]~a[9]赋值
0~9
,并且要求逆序输出。 -
代码:
#include<stdio.h>int main() {//创建一个数组,用来存放0~9int a[10];//计算数组的大小(元素的个数) sizeof运算符可以计算出数据类型,数组、变量等的空间字节数int len = sizeof(a) / sizeof(a[0]); // 数组的大小 = 数组总字节数 / 一个元素的字节数//通过for循环给数组赋值0~9for (int i =0; i <= 9; i++) a[i] = i;//逆序输出 数组最大下标 = 数组大小 - 1for (int j = len - i; j >= 0; j--) printf("%4d", a[j]);printf("\n");return 0;
数组初始化
所谓的初始化,就是定义数组的同时,用指定数据给对应的元素赋值。
语法:
数据类型 数组名[数组容量] = {.....};
注意事项:
-
数组可以部分初始化:也就是可以给数组中的前几个元素初始化,未被初始化的元素系统将自动初始化,初始值是
0
(整型和浮点型)或者\0
(字符型)或者NULL
(指针类型)//数组的部分初始化 int arr[10] = {11,12,13,14,15}; //推荐写法,只初始化前5个元素,剩余由系统默认为0,等价于下面写法 int arr[10] = {11,12,13,14,15,0,0,0,0,0}char arr1[5] = {`a`,`b`,`c`}; //推荐写法,等价下面写法 char arr1[5] = {`a`,`b`,`c`,`\0`,`\0`};
-
数组更具初始化的元素自动分配大小:如果定义数组为指定数组容量,则系统会根据初始化的元素的个数来决定容量。
//由初始化的元素来决定数组的容量 int arr[] = {11,12,13,14,15}; //推荐写法,等价于下面写法 int arr[5] = {11,12,13,14,15};
一维数组案例
案例
-
需求:斐波拉契数列
-
分析:1,1,2,3,5,…就是斐波拉契数列
-
代码:
#include<stdio.h>int main() {//定义循环变量int i;//定义一个数组,来存储20个数int f[20] = {1,1};//计算数组的大小int len = sizeof(f) /sizeof(f[0]);//通过一个循环,将数据存入数组for (i = 2; i < len; i++) f[i] = f[i-1] + f[i-2];//便利数组:通过for循环,依次输出数组中的每一元素for (i = 0; i < len; i++){//1行显示五个数if(i > 0 && i % 5 == 0) printf("\n");printf("%8d", f[i]);}printf("\n");return 0; }
案例
- 需求:按键盘输入年、月、日,计算并输出该日是该年的第几天。
- 分析:
- 首先创建一个数组,用来存放每一个月的天数,因为二月特殊,初始化的时候,默认为平年天数
- 从控制台输入年,月,日
- 闰年判断,修改数组中的二月对应的天数(闰年:29,平年:28)
- 定义一个变量,用来记录天数,默认就是我们输入的天数
- 将输入月份之前的所有月的天数从数组中取出来相加,再加上控制台输入的天数
- 将统计后的天数打印输出。
#include<stdio.h>int main()
{//创建一个数组,用来存放没一个月的天数int t[]={31,28,31,30,31,30,31,31,30,31,30,31};//定义三个变量,用来接收控制台输入的年月日int year,month,day;printf("请输入年份、月份、天(yyyy-MM-dd):");scanf("%d-%d-%d", &year, &month, &day);//闰年判断if(year % 100 != 0 && year % 4 == 0 || year % 400 == 0) t[1] =29;//创建一个变量,用来记录天数int sum = day;//将当月之前所有天数相加for (int i = 0; i < month - 1; i++){sum += t[i];}printf("%d月%d日是%d年的第%d天!\n", month, day, year, sum);return 0;
}