1.数组
数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个标识符命名,并通过编号(索引,亦称为下标或角标)的方式对这些数据进行统一管理。
1.1数组相关概念
(1)数组名:本质上是一个标识符常量,命名需要符合标识符规范。
(2)元素:同一个数组中的元素必须是相同的数据类型。
(3)下标(索引、角标):从0开始的连续数字。
(4)数组的长度:表示元素的个数。
1.2数组的特点
(1)创建数组时会在内存中开辟一整块连续的空间,占据的空间的大小,取决于数组的长度和数组中元素的类型。
(2)数组中的元素在内存中是依次紧密排列的且有序的。
(3)数组一旦初始化完成,其长度就是确定的,数组的长度一旦确定,就不能修改。
(4)我们可以直接通过索引(下标)获取指定位置的元素,速度很快。
1.3数组的定义
//方式一:先指定元素的个数和类型,再进行初始化
// 定义数组,数组名字是 arr1,元素类型是 int,元素个数是 3 个
int arr1[3];
// 定义完成后再给元素赋值
arr1[0] = 100;
arr1[1] = 200;
//方式二:指定元素的类型和个数并同时进行初始化
// 定义完数组直接进行初始化
int arr2[3] = {4,5,6};
//方式三:指定元素的类型,不指定元素个数,同时进行初始化
// 没有指定元素个数,系统会自动计算
int arr3[ ] = {7,8,9,10};
1.4访问数组元素
通过“数组名[下标]”可以访问数组中的元素,案例如下
#include <stdio.h>
int main()
{
// 定义 4 个元素的数组
int nums[4] = {1, 2, 3, 4};
// 修改第二个元素的值
nums[1] += 10;
// 读取元素的值
printf("第一个元素的值:%d\n", nums[0]); // 第一个元素的值:1
printf("第二个元素的值:%d\n", nums[1]); // 第一个元素的值:12
printf("第三个元素的值:%d\n", nums[2]); // 第一个元素的值:3
printf("第四个元素的值:%d\n", nums[3]); // 第一个元素的值:4
return 0;
}
1.5数组越界
数组下标必须在指定范围内使用,超出范围视为越界。
#include <stdio.h>
int main()
{
// 定义数组 没有指定长度
int nums[5] = {1,2,3,4,5};
printf("下标是0的元素:%d\n", nums[0]); // 1
printf("下标是4的元素:%d\n", nums[4]); // 5
printf("下标是-1的元素:%d\n", nums[-1]);// 得到的是不确定结果
printf("下标是5的元素:%d\n", nums[5]); // 得到的是不确定结果
return 0;
}
1.6计算数组长度
数组长度(元素个数)是在数组定义时明确指定且固定的,我们不能在运行时直接获取数组长度,但是,我们可以通过sizeof 运算符间接计算出数组长度,计算步骤如下:使用sizeof运算符计算出整个数组的字节长度。由于数组成员是同一类型,每个元素字节长度相等,用整个数组的字节长度除以单个元素的字节长度就可以得到数组的长度。
// 定义数组 没有指定长度
int nums[] = {10, 20, 30, 40, 50, 60, 70};
// 计算数组总的字节长度
int arrByteLen = sizeof nums;
// 用总字节长度除以单个元素的字节长度
int arrLen = arrByteLen / sizeof nums[0];
1.7遍历数组(重点)
遍历数组是指按顺序访问数组中的每个元素,以便读取或修改它们,编程中一般使用循环结构对数组进行遍历。
#include <stdio.h>
int main()
{
// 定义数组
int arr[10] = {12, 2, 31, 24, 15, 36, 67, 108, 29, 51};
// 计算数组长度
int len = sizeof arr / sizeof arr[0];
// 遍历数组中的元素
printf("遍历数组中的元素:\n");
for (int i = 0; i < len; i++)
{
printf("%d: %d \n", i, arr[i]);
}
return 0;
}
(1)案例
取出数组中之值最大的元素。
#include <stdio.h>
int main()
{
// 定义数组
int arr[10] = {12, 2, 31, 24, 15, 36, 67, 108, 29, 51};
// 计算数组长度
int len = sizeof arr / sizeof arr[0];
// 定义变量用于存储最大元素值,初始值为第一个元素的值
int max = arr[0];
// 遍历数组比较最大值
for (int i = 0; i < len; i++)
{
// 如果当前遍历到的元素比max大,就将当前元素的值赋值给max
if (arr[i] > max) {
max = arr[i];
}
}
// 输出结果
printf("最大的元素值:%d", max);
return 0;
}
分析:既然求数组中的最大值(不仅限于最大也可以最小),那么肯定要遍历数组中的每一个值进行比较,所以这个最值我们应该把他直接初始化为数组中的第一个值利用循环进行遍历比较然后赋值。
1.8字符数组
用来存放字符的数组称为字符数组,也可以称为字符串。字符串的输入输出格式占位符是 %s。
字符串结尾,会自动添加一个 \0 作为字符串结束的标志,所以字符数组最后一个元素必须是 \0。
\0 是ASCII码表中的第0个字符,用NUL表示,称为空字符,该字符既不能显示,也不是控制字符,输出该字符不会有任何效果,它在C语言中仅作为字符串的结束标志。
1.9字符数组的定义
char str1[12] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0'}; // 显式地设值 \0
char str2[4] = {'t', 'o', 'm'}; // 后面自动添加 \0
char str3[ ] = {'j', 'a', 'c', 'k'}; // 不会自动添加 \0
printf("str1=%s \n", str1);
printf("str2=%s \n", str2);
printf("str3=%s \n", str3); // 由于没有结束标识,会包括相邻内存的数据,直到遇到结束标记\0
输出结果:
str1=Hello World
str2=tom
str3=jacktom
简化写法
char str1[ ] = {"I am happy"}; // 后面自动添加 \0
char str2[ ] = "I am happy"; // 省略{}号,后面自动添加 \0
1.9字符数组的访问和遍历
// 定义字符串
char greeting[] = "Hello";
// 计算字符串长度
int len = sizeof greeting / sizeof greeting[0];
printf("%s \n", greeting);
printf("数组长度:%d \n", len);
printf("第3个字符: %c \n", greeting[2]);
printf("\n");
// 遍历字符串
for (int i = 0; i < len; i++)
{
printf("%c \n", greeting[i]);
}
2.多维数组
2.1多维数组介绍
如果数组的元素还是数组,这样的数组就称为多维数组。这种多层次的结构允许我们以表格或矩阵的方式组织数据,其中每个维度都对应于不同的行、列或更多的维度,使数据更加结构化和有组织。多维数组可以分为二维数组、三维数组、四维数组 …… 等,这里我们以二维数组为例进行演示。
2.2二维数组的定义
方式1: 先定义再初始化
// 定义一个4行6列的二维数组
int a[4][6];
// 进行初始化赋值
a[0][0] = 10
a[0][1] = 20;
········
方式2: 直接定义并初始化
/ 定义一个4行6列的二维数组,以为矩阵的形式初始化
int a[4][6] = {
{10, 20, 30, 30, 40, 60},
{100, 200, 300, 400, 500, 600},
{1000, 2000, 3000, 4000, 5000, 6000},
{10000, 20000, 30000, 40000, 50000, 60000}
};
// 定义一个4行6列的二维数组, 会自动匹配到各行各列
int b[4][6] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
// 如果所赋值的数量可以与元素数量对应,第一维的数组长度可以不给出
int b[][6] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
2.3二维数组的访问和遍历
访问二维数组的元素,需要使用两个下标(索引),一个用于访问行(第一维),另一个用于访问列(第二维),我们通常称为行下标(行索引)或列下标(列索引)。遍历二维数组,需要使用双层循环结构。
#include <stdio.h>
int main()
{
// 定义一个 3 行 4 列的数组
int map[3][4] = {
{1, 2, 3, 4},
{11, 12, 13, 14},
{21, 22, 23, 24}};
// 计算第一维度的长度
int rows = sizeof(map) / sizeof(map[0]);
// 计算第二维度的长度
int cols = sizeof(map[0]) / sizeof(int);
// 遍历输出每个元素
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
printf("%d\t", map[i][j]); // \t 可以输出得更加整齐
}
printf("\n");
}
// 计算所有元素的和
int sum = 0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
sum += map[i][j];
}
}
printf("所有元素的和:%d", sum); // 所有元素的和:150
return 0;
}
输出结果:
1 2 3 4
11 12 13 14
21 22 23 24
所有元素的和:150
2.4二维数组应用案例
//现在有三个班,每个班五名同学,用二维数组保存他们的成绩,并求出每个班级平均分、以及所有班级平均分,数据要求从控制台输入。
include <stdio.h>
int main()
{
// 定义 一个 3 行 5 列的数组
double scores[3][5];
// 定义变量存储第一个维度长度和第二个维度长度
int rows = 3, cols = 5;
// 遍历二维数组进行赋值
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
printf("请输入第%d个班的第%d个学生的成绩:", i + 1, j + 1);
scanf("%lf", &scores[i][j]);
}
}
// 遍历数组,计算每个班级的平均分和总的平均分
// 定义变量记录所有班级总分数
double total_sum = 0;
// 定义变量记录每个班级总分数
double class_sum = 0;
// 遍历班级(行)
for (int i = 0; i < rows; i++)
{
// 将当前班级总分数重置为0
class_sum = 0;
// 遍历当前班级的每个成绩(该行的每一列)
for (int j = 0; j < cols; j++)
{
class_sum += scores[i][j];
}
// 输出当前班级的平均分
printf("第%d个班级的平均分为:%.2f \n", i + 1, class_sum / cols);
// 将该班级总分加入到所有总分中
total_sum += class_sum;
}
// 输出所有班级平均分
printf("所有班级的平均分为:%.2f", total_sum / (rows * cols));
return 0;
}
2.6练习
请求出一个数组的最小值,并得到对应的索引。