【C学习】13-数组使用与运算
“知道做不到就是不知道”
一、初始数组
思考一个问题,之前我们声明的变量都是一个一个的,那思考一下,如果要存储一个班级30个人的成绩该怎么办?难道要单独设置30个变量吗?
float mark1 = 90;
float mark2 = 90;
float mark3 = 90;……float mark29 = 90;
float mark30 = 90;
这样既浪费时间又浪费空间,于是这里提到另一种变量类型——数组,方便的同时存储多个同类型数据。
其使用过程如下:
(1)定义数组:类型名 变量名[数字],如 int a[10];
(2)遍历数组:打印或者继续使用
(3)对数组中的元素赋值:要用到循环
(4)使用数组中的元素:可以做判断、做运算等
二、数组使用方法
(一)基本定义
数组是C语言中一种重要的构造数据类型,它允许我们将多个相同类型的变量组织在一起,形成一个有序的集合。通过使用一个统一的名称(数组名)和下标(索引)来管理这些数据。
//<类型> 变量名称[元素数量];// 完全初始化
int arr1[5] = {1, 2, 3, 4, 5};// 部分初始化(未初始化的元素自动设为0)
int arr2[5] = {1, 2}; // 结果为:1, 2, 0, 0, 0// 自动确定数组大小
int arr3[] = {1, 2, 3}; // 编译器自动确定数组长度为3// C99指定的初始化器
int arr4[10] = {[2] = 5, [5] = 10}; // 只初始化特定位置的元素
定义一个整型数组:int arr[10];这就创建了一个名为arr的数组,它可以存储10个整数。
关于元素数量的说明:在C99标准之前,数组的大小必须是常量表达式。但从C99标准开始,支持使用变量来定义数组的大小,这就是变长数组(Variable-Length Array, VLA),如:int n = 10; int arr[n];
需要注意的是,变长数组的长度在数组创建后就是固定的,并非可以随时改变。
(二)核心特点
数组可以理解为一个容器,具有以下重要特性:
- 元素类型统一:数组中所有元素必须具有相同的数据类型
- 大小固定:数组一旦创建,其大小就不能改变
- 内存连续:数组中的元素在内存中是连续依次排列的
对于int a[10]这样的整型数组:
- 数组元素可以出现在赋值的左边(作为左值,被赋值)和右边(作为右值,参与表达式计算)
- 十个数组单元分别是a[0], a[1], a[2], ..., a[9],每个单元都是一个int类型的变量
- 下标(也称为"索引")从0开始,这是C语言数组的一个重要特点
(三)数组下标的有效范围与越界问题
有效的下标范围是编程中需要特别注意的问题。关于长度为零的数组:C语言允许定义长度为0的数组,如int a[0],但这种数组实际上没有什么实用价值。
对于int a[10]这样的数组:
- 有效下标范围是[0, 9],即从0到数组大小减1
- 数组中不存在a[10]这个元素,最后一个有效元素是a[9]
- 编译器和运行环境都不会检查数组下标是否越界,无论是对数组单元进行读还是写操作
- 程序员需要自己保证只使用有效的下标值,否则可能导致未定义行为
使用
sizeof(arr) / sizeof(arr[0])
来计算数组长度,提高代码的可维护性
(四)例子:统计个数
1. 写一个程序输入[0,9]范围内的整数,统计每一种数字出现的次数,输入-1表示结束。
2. 包括的部分:
a) 定义数组,数组的大小用const类型声明;
b) 利用for循环,初始化数组为0;
c) 数组参与运算;
d) 遍历数组并输出。
#include <stdio.h>int main() {// a) 定义数组,数组的大小用const类型声明const int ARRAY_SIZE = 10;int count[ARRAY_SIZE];// b) 利用for循环,初始化数组为0for(int i = 0; i < ARRAY_SIZE; i++) {count[i] = 0;}int input;printf("请输入[0,9]范围内的整数(输入-1结束):");scanf("%d", &input);// c) 数组参与运算 - 统计每个数字出现的次数while(input != -1) {if(input >= 0 && input <= 9) {count[input]++; // 对应数字的计数加1} else {printf("输入超出范围,请重新输入[0,9]的整数或-1结束:");}scanf("%d", &input);}// d) 遍历数组并输出结果printf("\n统计结果:\n");for(int i = 0; i < ARRAY_SIZE; i++) {printf("数字 %d 出现了 %d 次\n", i, count[i]);}return 0;
}/*
请输入[0,9]范围内的整数(输入-1结束):
3
5
2
3
5
5
7
-1统计结果:
数字 0 出现了 0 次
数字 1 出现了 0 次
数字 2 出现了 1 次
数字 3 出现了 2 次
数字 4 出现了 0 次
数字 5 出现了 3 次
数字 6 出现了 0 次
数字 7 出现了 1 次
数字 8 出现了 0 次
数字 9 出现了 0 次
*/
三、数组运算
1. 初始化数组
参照“二、(四)”。
2. 确定数组元素数量
在处理数组时,经常需要知道数组包含多少元素。sizeof运算符可以计算整个数组占用的字节数。用数组总字节数除以单个元素的字节数,就能得到元素个数:
int arr[] = {1, 2, 3, 4, 5};
int length = sizeof(arr) / sizeof(arr[0]); // 计算数组元素个数
需要注意的是,sizeof是编译时运算符,不会执行括号内的表达式。例如:
int a = 6;
sizeof(a++); // 执行后a的值仍是6,不是7
当表达式中包含不同类型时,sizeof会按类型提升规则计算大小:
int a = 6;
sizeof(a + 1.0); // 结果为8,因为a转换为double类型(占4个字节)
3. 数组的赋值与遍历
数组不能直接使用赋值运算符进行整体赋值,必须通过循环逐个元素处理:
int source[] = {1, 2, 3, 4, 5};
int dest[5];// 正确的赋值方法:使用for循环
for(int i = 0; i < 5; i++) {dest[i] = source[i];
}
遍历数组时的注意事项:确保循环变量在退出循环后不会被误用为数组下标,这可能导致数组越界访问。
4. 数组元素的运算
数组元素可以参与各种算术和逻辑运算,这是数组计算的核心。
(1)基本算术运算:可以对数组元素进行加、减、乘、除等操作
int arr[5] = {1, 2, 3, 4, 5};// 对每个元素进行算术运算
for(int i = 0; i < 5; i++) {arr[i] = arr[i] * 2 + 1; // 先乘2再加1
}
(2)逻辑运算:数组元素也可以用于条件判断
if(arr[0] > 0 && arr[1] > 0) {// 执行操作
}
(3)边界条件处理:特别是进行除法运算时,需要检查除数是否为零
for(int i = 0; i < size; i++) {if(arr[i] != 0) {result[i] = 100 / arr[i];} else {printf("除零错误发生在索引%d\n", i);}
}
5. 数组作为函数参数
将数组传递给函数时,需要特别注意:
- 函数参数中的数组声明不需要指定大小
- 必须额外传递一个参数表示数组大小
- 函数内部无法使用sizeof计算数组元素个数
// 正确的函数声明方式
int sumArray(int arr[], int size) {int sum = 0;for(int i = 0; i < size; i++) {sum += arr[i];}return sum;
}// 调用函数
int main() {int numbers[] = {1, 2, 3, 4, 5};int total = sumArray(numbers, 5); // 必须传入数组大小return 0;
}
6. 在数组中查找元素
查找是数组最常见的操作之一,主要有以下几种方法:
(1)线性查找:最简单直接的查找方法,适用于未排序数组。
int linearSearch(int arr[], int size, int target) {for(int i = 0; i < size; i++) {if(arr[i] == target) {return i; // 返回找到的索引}}return -1; // 未找到
}
(2)二分查找:针对已排序数组的高效查找算法
int binarySearch(int arr[], int size, int target) {int left = 0, right = size - 1;while(left <= right) {int mid = left + (right - left) / 2;if(arr[mid] == target) return mid;else if(arr[mid] < target) left = mid + 1;else right = mid - 1;}return -1;
}
写在最后:
更新C语言学习笔记
如有错误,烦请多多批评指正!