数组
通过前面所学到的知识,我们了解到,当我们需要使用一些变量的时候,我们可以通过创建变量来使用它,但是,有的时候我们需要使用很多个同类型的变量,那样一个个创建是否显得太过繁琐?
其实 数组就是一组相同类型元素的集合。 我们只要创建一个类型的数组,就可以同时创建很多相同类型的变量。
一、一维数组
1.1 一维数组的创建
格式:
数据类型 数组名 [常量表达式] int arr [5];
常量表达式:决定创建的数组的大小(即可以存储多少个相同类型的数据)
注意:数组创建,在C99标准之前, []里面 必须是常量才行,不能使用变量。在C99标准支持了变长数组的概念之后,数组的大小可以使用变量指定,但是数组不能初始化。(vs2019并不支持C99标准)
举例:
可能出错代码:
int a = 10; int arr[a];
由于在vs2019环境下并不支持C99标准,所以这里使用变量,编译器是会报错的。
正确代码:
int arr[10];//创建一个可以存储10个整形变量的数组。 char arr[10];//创建一个可以存储10个字符类型的数组
1.2 一维数组的初始化
数组已经创建好了,怎样将我们需要创建的变量放进去呢?
我们在创建数组的同时,可以给数组赋予一些合理初始值(初始化)。
//创建一个可以存储10个整形数组的整形数组,并将它的前5个元素分别赋值为1,2,3,4,5,剩余元素则默认为0; int arr1[10] = { 1,2,3,4,5 }; //这里[]为空的时候表示:根据后面初始化的元素个数,来自动设置大小 int arr2[] = { 1,2,3,4 };//自动设置为4个大小,等价于arr2[4]={1,2,3,4} int arr3[5] = { 1,2,3,4,5 };//表示完全初始化,即每个元素都被赋予了初始值。 //定义字符型数组,可以存储3个字符,98如果按字符打印会自动转化为对应的ASCII码表对应的字符 char arr4[3] = { 'a',98, 'c' };
1.3 一维数组的应用
我们首先介绍介绍一个操作符: [] (下标引用操作符), 数组元素的下标是从0开始的,即arr[5]数组的首元素是arr[0];
题目:从键盘输入10个数,并将他们打印在屏幕上。
#include <stdio.h> int main() { int arr[10] = { 0 };//数组的不完全初始化 //计算数组的元素个数 int sz = sizeof(arr) / sizeof(arr[0]); //对数组内容赋值,数组是使用下标来访问的,下标从0开始。 int i = 0; printf("请输入:10个数。"); for (i = 0; i < 10; i++)//从键盘输入10个数字赋值给数组arr[0]到arr[9] { scanf("%d",&arr[i]);//这里记得&,新手总是忘记 } //输出数组的内容 for (i = 0; i < 10; ++i) { printf("%d ", arr[i]); } return 0; }
代码中 sizeof(arr)表示计算整个数组arr的大小,而sizeof(arr[0])表示计算数组中首元素的大小(随便计算一个元素就行,因为每个元素的大小都是相等的,这里是选取了首元素)。
补充小知识:
1.sizeof:c语言中的一个关键字,也是一种操作符。是用于计算数据在内存中所占的字节数。
1.4 一维数组的存储
数组在内存中是怎样存储的呢?
#include <stdio.h> int main() { int arr[5] = {0};//定义一个可以存储5个元素的整形数组 int i = 0; int sz = sizeof(arr)/sizeof(arr[0]);//计算数组元素的个数 for(i=0; i<sz; ++i) { printf("arr[%d]的地址 = %p\n", i, &arr[i]);//打印每个数组的地址 } return 0; }
补充小知识:%p是打印地址的格式输出符号。
运行结果:
注意:每次运行的时候打印的结果会不一样,因为变量的创建会 重新分配地址。
从图中结果我们知道,随着数组下标的增长,元素的地址是在有规律的递增(每个元素之间差四个字节)。
所以我们知道,数组在内存中是连续存放的。
每个元素之间差4个字节是因为整形int(vs2019环境下)占四个字节,所以一个元素存储要分配四个字节
重点介绍以下两个数组
char arr5[] = "abcdef";//数组1 char arr6[] = { 'a','b','c','d','e','f'}; //数组2
这两个数组等价吗?长度一样吗?试着猜一下下面代码运行的结果:
补充小知识:
strlen:C 语言中的库函数中的一种,用于计算字符串的长度,直到遇到结束字符(‘\0’),但不包括空格字符。
需要引用的头文件是:#include <string.h>
#include <stdio.h> int main() { char arr5[] = "abcdef";//数组1 char arr6[] = { 'a','b','c','d','e','f'}; //数组2 printf("数组arr5的大小为是 %d\n", sizeof(arr5));//语句1 printf("数组arr6的大小为是 %d\n", sizeof(arr6));//语句2 printf("数组arr5的长度是 %d\n", strlen(arr5));//语句3 printf("数组arr6的长度是 %d\n", strlen(arr6));//语句4 return 0; }
运行结果:
原因分析:
语句1:值为7是因为字符串“abcdef”在 存储的时候会自动在末尾加上’\0‘,所以sizeof也计算了字符’\0‘。
语句2:值为6是因为数组2只有6个元素,后面并没有’\0‘;
语句3:值为6是因为“abcdef\0”,strlen函数遇到’\0’就结束了,只计算’\0’前面的字符串长度。
语句4:由于一维数组在内存中是连续存放的,char arr6[] = { ‘a’,‘b’,‘c’,‘d’,‘e’,‘f’};后面并不会默认加上’\0‘所以strlen会继续往后找,直到遇到’\0‘,所以会打印 随机值。
二、二维数组
2.1 二维数组创建
//数组创建 int arr[3][4];//创建一个3行4列的整形二维数组 char arr[3][5];//创建一个3行5列的整形二维数组 double arr[2][4];//创建一个2行4列的浮点型形二维数组
2.2 二维数组的初始化
//数组初始化 int arr[3][4] = {1,2,3,4};//将第一行赋值1,2,3,4,其余行的数默认为0; //表示第1行{1,2},第2行{4,5} //最终效果: //1 2 0 0 //4 5 0 0 //0 0 0 0 int arr[3][4] = {{1,2},{4,5}}; int arr[][4] = {{2,3},{4,5}};//二维数组如果有初始化,行可以省略,列不能省略
注意:二维数组如果有初始化,行可以省略,列不能省略。
因为你不告诉列数,计算机不知道什么时候换行,但是行数不知道的情况下,只要达到列数的最大值就会自动换行,一直往下走就行。
2.3 二维数组的应用
二维数组的访问时用arr[行号] [列标]的形式,与一维数组一样都是从0开始。
计算3阶行列式的值:
代码:
#include <stdio.h> int main() { int arr1[3][3];//创建一个三行三列的二维数组 int i = 0; printf("请输入行列式:\n"); for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 3; j++) { scanf("%d", &arr1[i][j]);//从键盘的到行列式的值 } } int sum1 = 0;//主对角线的三个数的积与和主对角线平行的对角线上的三个数的积的和 int sum2 = 0;//次对角线的三个数的积与和次对角线平行的对角线上三个数的积的和 int sum = 0;//行列式的值 sum1 = arr1[0][0] * arr1[1][1] * arr1[2][2] + arr1[1][0] * arr1[2][1] * arr1[0][2] + arr1[2][0] * arr1[0][1] * arr1[1][2]; sum2 = arr1[0][2] * arr1[1][1] * arr1[2][0] + arr1[0][1] * arr1[1][0] * arr1[2][2] + arr1[0][0] * arr1[1][2] * arr1[2][1]; sum = sum1 - sum2; printf("该三阶方阵的值是%d", sum); return 0; }
2.4 二维数组的存储
我们试着和一维数组一样,通过打印个元素的地址观察一下:
#include <stdio.h> int main() { int arr[3][4]; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 4; j++) { printf("arr[%d][%d]的地址是:%p\n", i, j, &arr[i][j]); } } return 0; }
运行结果:
由此可见,二维数组和一维数组一样,在内存中也是连续存储的。
三、数组越界
我们知道数组的下标是有范围限制的。
比如:如果数组有n个元素,那么元素的下标范围是0到n-1;
所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。
注意:C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的。
建议我们在使用数组的时候要注意检查,数组是否越界。
数组越界的例子:
#include <stdio.h> int main() { int arr[10]; int i = 0; for (i = 0; i <= 10; i++)//当i=10的时候,arr[10]则数组越界了。 { arr[i] = i; printf("%d ", arr[i]); } return 0; }