前言
你们的CMZ要趋势了,所以她请来了她的“助理”其实就是AI来帮忙写作,都懒得搞Markdown了
第三章·终于开始写代码啦!
四、数据的容器——数组
一、初识数组
AAA小剧场——
A:叮铃铃!上课啦!今天我们要学习一个非常重要的概念——数组。数组就像是一个可以存放多个相同类型数据的"容器"。想象一下,如果你有100个学生的成绩需要存储,难道要定义100个不同的变量吗?
T:那太麻烦了!我之前试过这样写:
intscore1,score2,score3,...,score100;光是定义变量就写了好长一行!
C:老师,我知道数组可以解决这个问题。数组的基本格式是:
数据类型 数组名[数组大小];比如:int scores[100];这样就一次性定义了100个整型变量。
A:非常正确!但是要注意,数组的下标(索引)是从0开始的,而不是1。所以scores[0]代表第一个元素,scores[99]代表第100个元素。
Q:老师,我有点懵…为什么从0开始计数呢?
S:这个嘛,和计算机内存的寻址方式有关。简单来说,数组名代表数组第一个元素的地址,而数组名+索引值就能直接计算得到对应元素的地址。如果从0开始,scores[0]的地址就是数组首地址+0,scores[1]的地址就是首地址+1*元素大小,这样计算起来更直接。
二、数组的基本操作
A:让我们看一个简单的例子。假设我们要存储5个学生的成绩,并计算平均分:
#include<bits/stdc++.h>usingnamespacestd;intmain(){intscores[5];// 定义一个可以存储5个整数的数组// 输入5个学生的成绩cout<<"请输入5个学生的成绩:"<<endl;for(inti=0;i<5;i++){cin>>scores[i];// scores[i]表示数组的第i+1个元素}// 计算总分intsum=0;for(inti=0;i<5;i++){sum+=scores[i];// 累加每个学生的成绩}// 计算并输出平均分doubleaverage=sum/5.0;cout<<"平均分是:"<<average<<endl;// 输出所有成绩cout<<"所有成绩为:";for(inti=0;i<5;i++){cout<<scores[i]<<" ";}cout<<endl;return0;}T:我注意到一个细节!在计算平均分时,用的是sum / 5.0而不是sum / 5,这是为什么呢?
C:因为如果两个整数相除,结果会向下取整变成整数。比如7/2=3,而不是3.5。用5.0可以让除法变成浮点数除法,得到正确的小数结果。
三、数组的初始化
A:数组在定义时可以直接初始化。有几种不同的初始化方式:
#include<bits/stdc++.h>usingnamespacestd;intmain(){// 方式1:完全初始化intarr1[5]={1,2,3,4,5};// 方式2:部分初始化,未指定的元素自动为0intarr2[5]={1,2,3};// arr2[3]和arr2[4]都是0// 方式3:不指定大小,让编译器自己计算intarr3[]={1,2,3,4,5};// 数组大小自动确定为5// 方式4:所有元素初始化为0intarr4[5]={0};// 所有5个元素都是0// 错误示例:不能这样写!// int arr5[5];// arr5 = {1, 2, 3, 4, 5}; // 错误!只能在定义时这样初始化return0;}Q:老师,如果我想在程序运行过程中给数组的所有元素赋值,该怎么办呢?
S:那就要用到循环啦!看我的例子:
#include<bits/stdc++.h>usingnamespacestd;intmain(){intarr[10];// 使用循环给数组赋值for(inti=0;i<10;i++){arr[i]=(i+1)*10;// 赋值10, 20, 30, ..., 100}// 输出数组for(inti=0;i<10;i++){cout<<"arr["<<i<<"] = "<<arr[i]<<endl;}return0;}四、数组与循环的完美结合
A:数组和循环简直是天生一对!让我们来看几个实际应用的例子。
例子1:寻找最大值
#include<bits/stdc++.h>usingnamespacestd;intmain(){intn;cout<<"请输入数字的个数:";cin>>n;intnumbers[n];// 注意:有些编译器可能不支持这种动态大小的数组// 更好的写法:int numbers[1000]; 然后确保n不超过1000cout<<"请输入"<<n<<"个整数:"<<endl;for(inti=0;i<n;i++){cin>>numbers[i];}// 寻找最大值intmax_value=numbers[0];// 假设第一个元素是最大的for(inti=1;i<n;i++){if(numbers[i]>max_value){max_value=numbers[i];}}cout<<"最大值是:"<<max_value<<endl;return0;}例子2:数组逆序输出
C:老师,我可以用数组和循环来实现倒序输出:
#include<bits/stdc++.h>usingnamespacestd;intmain(){intn;cout<<"请输入数组大小:";cin>>n;intarr[n];cout<<"请输入"<<n<<"个整数:"<<endl;for(inti=0;i<n;i++){cin>>arr[i];}cout<<"正序输出:";for(inti=0;i<n;i++){cout<<arr[i]<<" ";}cout<<endl;cout<<"逆序输出:";for(inti=n-1;i>=0;i--){// 注意:从n-1开始,到0结束cout<<arr[i]<<" ";}cout<<endl;return0;}例子3:统计各个分数段的人数
T:我想到一个实际的应用!统计一个班级的成绩分布:
#include<bits/stdc++.h>usingnamespacestd;intmain(){intscores[10]={85,92,78,90,65,88,72,95,60,82};intcount[5]={0};// 0:优秀(90-100), 1:良好(80-89), 2:中等(70-79), 3:及格(60-69), 4:不及格(<60)for(inti=0;i<10;i++){if(scores[i]>=90){count[0]++;// 优秀人数+1}elseif(scores[i]>=80){count[1]++;// 良好人数+1}elseif(scores[i]>=70){count[2]++;// 中等人数+1}elseif(scores[i]>=60){count[3]++;// 及格人数+1}else{count[4]++;// 不及格人数+1}}cout<<"成绩分布情况:"<<endl;cout<<"优秀(90-100): "<<count[0]<<"人"<<endl;cout<<"良好(80-89): "<<count[1]<<"人"<<endl;cout<<"中等(70-79): "<<count[2]<<"人"<<endl;cout<<"及格(60-69): "<<count[3]<<"人"<<endl;cout<<"不及格(<60): "<<count[4]<<"人"<<endl;return0;}五、数组的边界问题
A:非常重要的一点!数组不能越界访问。C++不会检查数组下标是否越界,但如果访问了不属于数组的内存,可能会导致程序崩溃或产生不可预料的结果。
#include<bits/stdc++.h>usingnamespacestd;intmain(){intarr[5]={1,2,3,4,5};// 正确的访问for(inti=0;i<5;i++){cout<<arr[i]<<" ";}cout<<endl;// 危险的越界访问!可能会导致程序崩溃// cout << arr[5] << endl; // arr[5]不存在!最大下标是4// cout << arr[-1] << endl; // 负下标也是错误的!// 同样,越界赋值也是危险的// arr[10] = 100; // 错误!return0;}Q:老师,如果我确实不知道需要多大的数组怎么办?
A:这时候可以定义一个足够大的数组,然后用一个变量记录实际使用了多少:
#include<bits/stdc++.h>usingnamespacestd;intmain(){constintMAX_SIZE=1000;// 定义最大容量intarr[MAX_SIZE];intn;// 实际元素个数cout<<"请输入元素个数(不超过"<<MAX_SIZE<<"):";cin>>n;if(n>MAX_SIZE){cout<<"输入的数量太大!"<<endl;return1;// 非0返回值通常表示程序异常结束}cout<<"请输入"<<n<<"个整数:"<<endl;for(inti=0;i<n;i++){cin>>arr[i];}// ... 其他操作return0;}六、字符数组
A:字符数组是一种特殊的数组,用来存储字符串。在C++中,字符串实际上就是字符数组。
#include<bits/stdc++.h>usingnamespacestd;intmain(){// 方式1:字符数组charstr1[10]={'H','e','l','l','o','\0'};// '\0'是字符串结束标志charstr2[10]="Hello";// 自动添加'\0'cout<<str1<<endl;cout<<str2<<endl;// 输入字符串charname[20];cout<<"请输入你的名字:";cin>>name;// 注意:遇到空格会停止cout<<"你好,"<<name<<"!"<<endl;// 使用循环处理字符数组charword[]="Programming";intlength=0;// 计算字符串长度(不包括'\0')while(word[length]!='\0'){length++;}cout<<"单词\""<<word<<"\"的长度是:"<<length<<endl;// 逆序输出字符串cout<<"逆序输出:";for(inti=length-1;i>=0;i--){cout<<word[i];}cout<<endl;return0;}C:老师,我发现字符数组和普通数组有一点不同:我们可以直接输出整个字符数组,但不能直接输出整个整数数组。
A:观察得很仔细!这是因为cout对字符数组有特殊处理,它会一直输出字符,直到遇到’\0’为止。而对于其他类型的数组,cout只会输出数组第一个元素的地址。
七、二维数组
A:有时候我们需要表格形式的数据,这时候就需要二维数组了。想象一下一个班级的成绩表:有多个学生,每个学生有多门成绩。
#include<bits/stdc++.h>usingnamespacestd;intmain(){// 定义一个3行4列的二维数组intmatrix[3][4];cout<<"请输入3行4列的矩阵:"<<endl;// 输入二维数组for(inti=0;i<3;i++){// 行循环for(intj=0;j<4;j++){// 列循环cin>>matrix[i][j];}}cout<<"你输入的矩阵是:"<<endl;// 输出二维数组for(inti=0;i<3;i++){for(intj=0;j<4;j++){cout<<matrix[i][j]<<"\t";// 用制表符对齐}cout<<endl;// 每输出完一行换行}// 计算每行的和cout<<"\n每行的和:"<<endl;for(inti=0;i<3;i++){introw_sum=0;for(intj=0;j<4;j++){row_sum+=matrix[i][j];}cout<<"第"<<i+1<<"行的和:"<<row_sum<<endl;}// 计算每列的和cout<<"\n每列的和:"<<endl;for(intj=0;j<4;j++){intcol_sum=0;for(inti=0;i<3;i++){col_sum+=matrix[i][j];}cout<<"第"<<j+1<<"列的和:"<<col_sum<<endl;}return0;}T:二维数组的初始化也和一维数组类似吧?
A:是的!可以这样初始化:
#include<bits/stdc++.h>usingnamespacestd;intmain(){// 二维数组初始化intarr1[2][3]={{1,2,3},{4,5,6}};// 也可以写成一行intarr2[2][3]={1,2,3,4,5,6};// 部分初始化,未指定的为0intarr3[3][4]={{1},{2,3},{4,5,6}};// 输出arr3for(inti=0;i<3;i++){for(intj=0;j<4;j++){cout<<arr3[i][j]<<" ";}cout<<endl;}return0;}课堂练习
A:现在我们来几个练习,巩固今天学到的知识:
1.编写程序,输入10个整数,找出其中的最小值和最大值。
2.编写程序,输入一个字符串(不超过100个字符),统计其中字母、数字和其他字符的个数。
3.编写程序,输入一个5×5的矩阵,计算两条对角线上的元素之和。
作业
作业:
编写程序,输入n个学生的成绩(n由用户输入),存储到数组中,然后:
- 计算平均分
- 找出最高分和最低分
- 统计及格(≥60分)的人数
编写程序,实现冒泡排序:输入n个整数,使用冒泡排序算法将它们从小到大排序后输出。
(提示:冒泡排序通过多次比较和交换相邻元素来实现排序)
编写程序,输入一个5×5的矩阵,将其转置(行列互换)后输出。
挑战题:编写程序,输入一个字符串,判断它是否是回文(正读反读都一样)。
例如:“level”、"radar"是回文,"hello"不是回文。
下节预告
A:今天我们一起学习了数组这个强大的工具。下节课我们将学习函数,它可以让我们的代码更加模块化、可重用。请大家提前预习:
- 函数的定义和声明
- 参数传递(值传递、引用传递)
- 返回值
- 递归函数
函数是结构化程序设计的基础,也是减少代码重复的关键技术!
番外(结语)
编程就像搭积木,数组就是那一盒整齐的积木块
循环就是你的双手,一遍遍搭建心中的城堡
函数将是你的蓝图,让建筑有章可循
指针会是你的魔法,直接与内存对话
对象则是你的团队,分工合作各司其职
算法乃是你的大脑,思考最高效的路径
调试便是你的耐心,查找每一处不完美
编程路上不孤单,我们都是筑梦师
一行代码一世界,半屏程序半人生
记住:数组越界是程序员最常见的错误之一,写循环时一定要仔细检查边界条件!
完结撒花✿✿ヽ(°▽°)ノ✿
你就说这次撒的花多不多吧!
是不是比上次更详细更系统了?
快关注我,学习更多编程知识!
没想到吧,后面还有。
不是快元旦了吗?提前祝大家新年快乐!
最近要搞那什么元旦文艺汇演,还有老师给的一堆作业,所以懒懒的CMZ准备停更这一期,毕竟字数要求太高了。
好啦,我们寒假再见,本期课程暂时停更于2025/12/16,作者放假日期为2026/1/31
ヾ( ̄▽ ̄)Bye~