版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第八章一维数组与向量C++程序设计——大模型思维与实践2为什么需要使用数组?40名学生的成绩管理,使用40个不同的变量来存储每个学生的成绩?显然不现实!数组允许我们使用单一的变量名存储多个值。可以创建一个包含40个元素的数组,每个元素代表一个学生的成绩。这样,可以通过一个统一的结构来管理整个班级的成绩,而不是分散地处理40个不同的变量。数组的主要作用是存储和管理大量同类型的数据。它们使得数据的处理变得更加高效和有序。8.1引言内容导航章节的标题引言迭代器一维数组的定义与使用向量常用操作一维数组的指针实践探究一维数组作函数参数大模型实践应用实例大模型探究向量--动态数组本章小结4一维数组的定义遵循以下语法:类型名称数组名称[数组大小];类型名称:指定数组中元素的数据类型,如int、double等,又称为基类型。数组名称:为数组指定的标识符。数组大小:指定数组中可以存储的元素数量,必须是大于0的整数常量。假设需要存储一个班级中10名学生的成绩,可以定义一个一维数组如下:intscores[10];8.2.1定义数组5intscores[10];int指定了数组中元素的类型为整数,scores是数组的名称,10表示数组可以存储10个整数所有元素被连续地存储在内存中。数组的首元素存储在数组的起始地址处,每个后续元素都紧跟在前一个元素之后。每个元素占4个字节,scores[0](首元素)到scores[9](末元素)占据连续的40个字节。连续的存储方式使得用户可以通过下标(索引)访问数组元素。输出sizeof(scores)可查看数组所占的字节数。8.2.1定义数组scores[0]…scores[1]scores[7]scores[8]scores[9]2000地址20042036对于数组scores,sizeof(scores)将返回整个数组所占的字节数40。sizeof(变量)或sizeof(类型)可获得变量或数据类型所占内存空间大小:inta;sizeof(int):4sizeof(a):4sizeof(scores[0]):4简化画图6除了定义基类型为int的数组,还可以定义其它类型数组,例如:在定义数组时,需要特别注意以下几点:(1)数组大小必须是常量:在定义数组时,数组的大小必须是一个大于0的整数常量,或结果为整数的常量表达式,而不能是变量。8.2.1定义数组合法定义解释constintARRAY_SIZE=10定义一个const常量作为数组大小intscores[ARRAY_SIZE]使用const常量定义数组charsentence[10+1]使用常量表达式定义数组doubletemprature[ARRAY_SIZE+1]使用常量表达式定义数组定义解释charsentence[1000]一维数组可以存储1000个字符doubleprice[100]可以存储100个浮点数价格7(2)数组元素的初始值:在定义数组局部变量时,如果未显式初始化,则数组元素具有随机值,而不是0。定义为全局变量的数组,所有元素将自动初始化为0。(3)显式初始化:定义数组时提供一个初始化列表inta[5]={1,2,3,4,5};//a[0]到a[4]分别具有1到5的值。inta[5]={1,2,3};//a[0]到a[2]共3个元素分别初始化为1、2、3,其余元素自动初始化为0。inta[]={1,2,3,4,5};//如果为全部元素提供初值,可以省略数组大小,编译器自动计算大小为5,相当于定义inta[5]={1,2,3,4,5}。8.2.1定义数组不合法定义解释intn;cin>>n;inta[n];不能使用变量作为数组大小floatb[0];数组大小不能为0intd(2);这里定义了一个变量d,且初始化为2,而不是定义了一个数组8
数组名称[下标]如:scores[3]数组名称:定义数组时指定的标识符。下标:一个整数值,用于指定想要访问的元素在数组中的位置。C++中的一维数组不能作为一个整体进行操作,比如直接打印或赋值。只能访问数组中的单个元素,可以通过下标(也称为索引)来实现。访问一维数组元素的基本格式如下:定义的数组:intscores[10];8.2.2
引用数组元素
9数组的下标从0开始。大小为n的数组,有效的下标范围是从0到n-1。下标越界将导致未定义行为(程序崩溃或产生不可预测的结果)。例如,有定义:inta[5];访问元素使用a[0]、a[1]、a[2]、a[3]、a[4],以下使用都合法:a[1]=1;a[3]=2;a[a[3]]=a[1]-a[2+1];//将a[1]-a[3]的值“-1”赋值给a[a[3]](即a[2])以下使用将出现错误:a[5]=5;//数组大小为5,下标最大只能为4cout<<a[-1];//下标必须在0到4之间数组的下标既可以是常量,也可以是变量。以下使用合法:inti=3;a[i]=2*i;8.2.2
引用数组元素
10使用for循环遍历数组for循环通过控制下标(索引)的起始值、结束值以及下标的变化,可以访问数组中的每个元素。示例:从前往后循环:
for(inti=
0;i<5;i++)
{cin>>a[i];}下标的起始值是0,从数组的第0个元素开始遍历。循环的条件是i<5,确保了最后访问的元素是下标为4的元素,即数组的最后一个元素。下标的变化通过i++实现,确保了每次迭代后都会访问下一个元素。以上循环体中输入数据到a[i]中,可以替换成其它对a[i]操作的任何语句。8.2.2
引用数组元素
也可以从后往前循环,如下代码将实现数组的逆序输出:for(inti=4;i>=0;i--){cout<<a[i]<<"";}11使用for循环遍历数组可以使用基于范围的for循环访问数组,例如打印每个元素的值可以如下实现:intarr[]={1,2,3,4,5};for(intelem:arr)cout<<elem<<"";C++11引入了auto作为类型推导关键字,可将以上for循环修改成如下形式:intarr[]={1,2,3,4,5};for(autoelem:arr)cout<<elem<<"";如果需要在循环中修改数组的元素值,可以使用引用来声明循环变量:intarr[]={1,2,3,4,5};for(int&elem:arr)elem*=2;8.2.2
引用数组元素
可以写成auto&elem:arr12【例8-1】:写一个C++程序,从键盘输入一个整数n(n的值不超过80),计算并输出Fibonacci数列的第n个。Fibonacci数列定义为:第0项为0,第1项为1,之后每一项都是前两项之和。数列的前几个数字是:0,1,1,2,3,5,8,13,21,34,...8.2.3
使用一维数组解题步骤:1.接收输入:从键盘接收一个整数n。2.定义数组:大小至少为81(考虑到n的最大值为80,且数组下标从0开始)。由于Fibonacci数列的值迅速增大,需要使用一个足够大的数据类型来存储这些值,本例使用longlong。3.初始化数组:前两个值分别是0和1。4.计算Fibonacci数列:从数组的第三个元素开始,每个元素的值都是前两个元素之和。可以使用一个循环来计算直到第n个元素的值。5.输出第n个值13intmain(){intn;cin>>n;longlongfib[81]={0,1};for(inti=2;i<=n;i++){fib[i]=fib[i-1]+fib[i-2];}cout<<"第"<<n<<"个值是:"<<fib[n]<<endl;return0;}8.2.3
使用一维数组nii<=nfib[i]初始值第1次循环第2次循环第3次循环第4次循环第5次循环523456truetruetruetruefalse2351011235...012345ifib[i]由于n不超过80,使用longlong类型满足要求,否则可能会溢出。代码中,仅将“n不超过80”作为已知条件使用(从而需要选用longlong类型),而未在程序中检查n的值是否符合要求。14【例8-2】编写一个C++程序,实现功能:由用户输入一个值,在数组a中查找,如果找到该值,则输出其在数组中的下标;如果数组中不存在该值,则输出相应的提示信息。解题步骤:1.定义数组和变量2.输入数组元素3.输入需要查找的值4.直接查找并输出下标:遍历数组a,使用一个循环结构比较每个元素与用户输入的值。如果找到匹配的元素,立即输出该元素的下标。由于可能存在多个相同的值,需要遍历整个数组,输出所有匹配元素的下标。5.输出未找到的提示:如果在遍历结束后没有找到任何匹配的元素,输出提示信息说明数组中不存在该值。8.2.3
使用一维数组15代码:intmain(){inta[10];//定义一个包含10个整型元素的数组intvalue;//需要查找的特定值boolfound=false;//标记是否找到特定值cout<<"请输入10个整数:"<<endl;for(inti=0;i<10;i++){cin>>a[i];}//接收需要查找的值cout<<"请输入需要查找的值:"<<endl;cin>>value;通过for循环遍历数组中的每个元素,使用下标i作为访问数组元素的索引。8.2.3
使用一维数组012345ia[i]678916for(inti=0;i<10;i++){if(a[i]==value){cout<<"找到值"<<value<<"在数组的下标为:"<<i<<endl;found=true;}}if(!found){cout<<"数组中不存在值"<<value<<endl;}return0;8.2.3
使用一维数组ii<10a[i]==valuefound第1次循环第2次循环第3次循环第4次循环第5次循环第6次循环...第10次循环value=311310false1false2false3459falsetruefalsefalsetruetruetrue531103173131318311231found=falsetruetruetruetruetruetruetruetruefalsefalse10012345ia[i]678917//直接查找并输出下标for(inti=0;i<10;i++){if(a[i]==value){cout<<"找到值"<<value<<"在数组的下标为:"<<i<<endl;found=true;}}//输出未找到的提示if(!found){cout<<"数组中不存在值"<<value<<endl;}return0;}在循环体内,通过比较a[i]==value判断当前元素是否与用户输入的值相等。如果相等,则立即使用cout输出当前元素的下标i。使用布尔变量found来标记是否在数组中找到了至少一个匹配的元素。如果找到,将found设置为true。遍历结束后,如果found仍为false,则说明数组中不存在用户输入的值,此时输出相应的提示信息。8.2.3
使用一维数组18初学者可能犯的一种错误:在for循环中,通过比较a[i]==value判断是否找到特定值,如果不相等,则输出“不存在值”:
for(inti=0;i<10;i++){if(a[i]==value)cout<<"找到值"<<value<<"在数组的下标为:"<<i<<endl;elsecout<<"数组中不存在值"<<value<<endl;}8.2.3
使用一维数组19【例8-3】:定义一个包含36个成绩的一维数组,成绩存储为实数。请编写程序,找到并输出其中的最高分。解题步骤:1.定义数组:能够存储36个浮点数的一维数组2.输入成绩:通过循环从键盘读取36个学生的成绩3.遍历数组:使用一个变量(如maxScore)来跟踪遍历过程中遇到的最大值。开始时,可以将maxScore设置为数组的第0个元素的值,然后逐个与数组中的其它元素比较。4.比较与更新:在遍历过程中,如果发现某个元素的值大于maxScore,则更新maxScore为该元素的值。5.输出结果:遍历完成后,maxScore将包含数组中的最高分。此时,输出这个最高分。8.2.3
使用一维数组20#include<iostream>usingnamespacestd;intmain(){constintNUM_STUDENTS=36;//学生人数doublescores[NUM_STUDENTS];//存储成绩的数组//输入学生的成绩for(inti=0;i<NUM_STUDENTS;i++){cin>>scores[i];}代码:8.2.3
使用一维数组21doublemaxScore=scores[0];//假设第0个成绩是最高分for(inti=1;i<NUM_STUDENTS;i++){if(scores[i]>maxScore){maxScore=scores[i];}}cout<<"最高分是:"<<maxScore<<endl;return0;}8.2.3
使用一维数组22doublemaxScore=scores[0];//假设第0个成绩是最高分for(inti=1;i<NUM_STUDENTS;i++){if(scores[i]>maxScore){maxScore=scores[i];}}cout<<"最高分是:"<<maxScore<<endl;return0;}8.2.3
使用一维数组iscores[i]>maxScoremaxScore初始值\第1次循环第2次循环第3次循环第4次循环...第9次循环1239true15truefalsefalse10104true31315110571031101231NUM_STUDENTS=1010831231931331012345ia[i]678923
doublemaxScore=0;for(inti=0;i<NUM_STUDENTS;i++){if(scores[i]>maxScore){maxScore=scores[i];//更新最高分}}以上代码中,查找最高分的代码段,可能被错误地写成如下循环:如果所有学生的成绩都小于0,将错误地报告最高分为08.2.3
使用一维数组内容导航章节的标题引言迭代器一维数组的定义与使用向量常用操作一维数组的指针实践探究一维数组作函数参数大模型实践应用实例大模型探究向量--动态数组本章小结25数组用于存储一系列相同类型的元素,每个元素都有一个地址,这个地址可以通过数组名加下标来获取。例如:inta[10];&a[0]是数组第0个元素的地址&a[1]是第1个元素的地址。指针变量可以指向任何类型的数据,包括数组元素。针对以上数组a,以下示例:
int*p;
p=&a[0];p指针指向a数组的起始位置,可以认为p指向了a数组数组名有一个特殊的属性:代表数组首元素的地址,即数组的首地址。上面的赋值语句等价于:
p=a;指针不仅能指向数组的首地址,也可指向数组的其它元素,例如:int*p2=&a[7];8.3.1指向数组的指针p的值及其指向将数组a的第0个元素的地址赋给指针变量p将数组a的首地址(即首元素的地址,也即&a[0])赋给指针变量p268.3.2指针的运算(1)指针指向数组中的元素时,指针可以与整数运算加一个整数对指针变量进行加法运算时,如p+1,得到的指针指向数组中的下一个元素。注意:这里的加“1”得到的是数组中下一个元素的地址,而不是内存中下一个字节的地址。p=p+n将指针向下移动n个元素。减一个整数与加法运算相反,p–1得到的指针指向数组中的上一个元素。p=p-n将指针向上移动n个元素。自加运算p++或++p会使指针p指向数组中的下一个元素。自减运算p--或--p会使指针p指向数组中的上一个元素。例如:inta[10],*p1,*p2=&a[7];则:p2+1指向a[8]。注意,此时p2指针仍然指向a[7]。p2-2指向a[5]。p1=p2-5,使得p1指针指向a[2]。p2++,使得p2指针指向a[8]。27(2)指针之间的运算:当两个指针p1和p2都指向同一数组中的元素时,可以进行以下运算:两个指针相减p2-p1计算两个元素之间的距离(即下标的差值)。两个指针比较大小指针之间可以使用<、>、<=、>=操作符来比较大小。如果p1指向的数组元素在p2指向的元素之前,即p1指向的元素下标更小,那么p1<p2为true。8.3.2指针的运算不能进行指针的加法运算:如p1+p2这种运算在逻辑上没有意义28如有p=&a[0],即p=a从a的特性可知,a是一个地址,因此a也是一个指针,p与a均指向a[0]由此可知:p+1和a+1均指向a[1]p+i和a+i均指向a[i]右图中,i等于4,因此,p+i和a+i均指向a[4]。(3)指针与数组的关系指针与数组元素的地址:如果p=&a[0],那么p+i和a+i都指向a[i]。8.3.2指针的运算298.3.3通过指针访问数组元素访问数组中的元素有两种方法:下标法和指针法:(1)下标法①使用数组名访问:a[i]②使用指针访问:p[i](2)指针法①使用数组名和指针运算:*(a+i)即a[i]②使用指针变量和指针运算:*(p+i)即a[i],*p就是取a[0]的值。访问第0个元素,可使用:a[0]、p[0]、*(a+0)、*(p+0)、*a、*p已知p=a;
则a+i和p+i均指向a[i]a[i]具有两个别名:*(a+i)和*(p+i)。由于p=a,也可以用p[i]访问a[i]。308.3.3通过指针访问数组元素“*”操作和“++”、“--”操作综合运算如果p=&a[i]:*p++:先获取*p的值,然后执行p++例如:intb=*p++,等价于intb=*p;p++;执行时,b将获得*p即a[i]的值,随后p指向a[i+1]。*(p++):*(p++)在功能上与*p++等价,圆括号不改变操作的顺序或结果。例如:intb=*(p++),等价于intb=*(p);p++;*(++p):先执行++p,再获取*p的值例如:intb=*(++p),等价于++p;intb=*(p);执行时,先将p指向a[i+1],b再获得*p即a[i+1]的值。(*p)++:即a[i]++85318.3.3通过指针访问数组元素【注意事项】:(1)如果p=&a[2],那么*p、*(p+0)、p[0]访问的是a[2],而不是a[0]。(2)数组名与指针的区别:sizeof(a)将返回a数组所有元素占据的内存字节数,而sizeof(p)返回指针变量p所占的内存字节数(通常为8字节)。数组名是常量,不可改变,例如a++错误,而指针是变量。对于数组,可使用范围for循环对其遍历,但对于p不可使用范围for循环。详见进阶内容85328.3.4使用指针访问数组实例【例8-4】:程序实现以下功能:创建一个包含10个整型元素的一维数组a,通过用户输入为数组a的每个元素赋值,输出数组a中的所有元素。下面通过三个实现方法演示如何使用指针访问数组。intmain(){ inta[10];inti; cout<<"enter10integernumbers:\n"; for(i=0;i<10;i++) cin>>a[i]; for(i=0;i<10;i++) cout<<*(a+i)<<""; cout<<endl; return0;}方法1:输入数据使用下标法a[i]访问数组元素输出时使用*(a+i),其中a+i计算出了数组中第i个元素的地址。然后,通过解引用操作符*可以访问该地址处的值,即数组第i个元素的值。a[i]是*(a+i)的简写形式338.3.4使用指针访问数组实例intmain(){inta[10];int*p,i;cout<<"enter10integernumbers:\n";for(p=a;p<(a+10);p++)cin>>*p;for(p=a;p<(a+10);p++)cout<<*p<<"";cout<<endl;return0;}方法2:以第一个循环为例解释,该循环用于从标准输入读取10个整数并存储到数组a中。循环开始时,指针p被初始化为指向数组a的首元素(即p=a;)。循环条件p<(a+10)确保了p不会超出数组a的范围。在每次迭代中,cin>>*p;读取一个整数并存储到指针p所指向的位置,然后p通过p++移动到数组的下一个位置。348.3.4使用指针访问数组实例intmain(){inta[10];int*p,i;cout<<"enter10integernumbers:\n";for(p=a;p<(a+10);p++)cin>>*p;for(p=a;p<(a+10);p++)cout<<*p<<"";cout<<endl;return0;}一二三四五六七八九十p*paa+1a+2a+3a+4a+5a+6a+7a+8a+91510731829312pppppppp不能写成:for(i=0;i<10;i++,a++)cin>>*a;数组名是常量指针,a的值不能被改变35intmain(){inta[10];int*p,i;cout<<"enter10integernumbers:\n";p=a;for(i=0;i<10;i++,p++)cin>>*p;for(i=0;i<10;i++,p++)cout<<*p<<"";cout<<endl;return0;}方法3:将方法2的代码稍做修改如右。
代码错误!【建议】:避免在多个循环中递增同一个指针而不重新初始化:如果计划在另一个循环中再次使用同一个指针遍历数组,务必在新的循环开始前重新初始化该指针。8.3.4使用指针访问数组实例p此时p并不指向a[0]p省略前面步骤,此时i=9此时i=1036intmain(){inta[10];int*p,i;cout<<"enter10integernumbers:\n";p=a;for(i=0;i<10;i++,p++)cin>>*p;
p=a;
//重新初始化指针for(i=0;i<10;i++,p++)cout<<*p<<"";cout<<endl;return0;
}以上代码可改正为:8.3.4使用指针访问数组实例一维数组的指针37动态变量变量就像存放数据的“小盒子”,而内存则是堆放这些盒子的“仓库”。编译器会自动帮我们管理仓库里的盒子。编译器管理的“盒子”(如函数内的局部变量)只能在代码块(如函数、循环)内部使用,一旦离开这个范围,盒子就会被自动清理(销毁)。现实开发中,我们常遇到以下问题:数据需要“跨场合”使用:例如一个函数计算出的结果需要被其他函数共享,或程序运行时用户输入的数据量不确定(如存储100个名字还是1000个),自动盒子无法满足这种需求。程序需要“灵活应变”:编译时无法预知程序运行时需要多少盒子(如文件大小、网络数据量),必须等程序跑起来后再决定。8.3.5动态分配内存一维数组的指针38动态变量让程序员自己“动手”分配和释放变量,相当于把仓库的管理权交还给开发者:数据“长生不老”:只要程序员不主动清理,盒子里的数据可以一直存在,跨函数、跨模块共享。内存“按需分配”:根据程序运行时的情况,动态决定需要多少盒子,避免浪费或不足。动态变量是程序员通过显式操作在堆内存中创建的“特殊盒子”。动态变量打破了编译器自动管理的限制,让程序员自己决定变量的“诞生”和“消失”时间:分配变量:程序员用new命令在堆内存中申请一个变量,并拿到它的“地址标签”(指针)。释放变量:程序员用delete命令把变量销毁,将内存还给操作系统,避免资源浪费(就像用完工具后归还到工具箱)。8.3.5动态分配内存一维数组的指针39动态变量的创建动态变量存放在一个称为“堆”的内存区域中,局部变量存放在称为“栈”的内存区域中。堆和栈的区别为:堆内存由程序员控制分配和释放的时间,栈内存由系统控制分配和释放的时间。动态变量需要用运算符“new”创建,创建一个简单动态变量的语法格式如下:new数据类型以上操作申请一块能存放相应类型数据的内存空间,操作结果返回该内存空间的首地址。以下示例代码展示了如何使用new运算符动态分配内存,并通过指针操作该内存:int*p;p=newint;*p=5;cout<<*p<<endl;8.3.5动态分配内存p5别名*p一维数组的指针40动态变量的创建new操作返回的指针有类型,它只能赋值给同类型的指针,因此以下操作非法:int*p;p=newdouble;//p指针只能指向int型变量,不能指向double型变量创建动态变量时,还可以同时初始化:int*p;p=newint(5);//创建动态变量时,同时将其值初始化为5使用new也可以申请一维数组,格式如下:new数据类型[数组大小]该操作为一个一维数组申请一块连续的空间,并得到该数组的首地址。例如:int*arr=newint[100];可将arr当成数组名使用,如arr[2]=10可将数组第2个元素赋值为108.3.5动态分配内存一维数组的指针41动态变量的创建普通数组在定义时,其大小必须为常量,而动态数组的大小可以为变量或包含变量的表达式。例如:intn;cin>>n;int*arr=newint[2*n];//数组大小可以根据用户输入的n决定创建动态数组时,还允许进行初始化,例如:int*arr=newint[5]{1,2,3,4,5};申请了一个包含5个元素的动态数组,初值为“1,2,3,4,5”。如果给出的初值个数小于数组大小,剩余元素赋初值为0。8.3.5动态分配内存一维数组的指针42动态变量的销毁动态变量被创建后,在程序运行期间将一直存在。不再需要这个变量时,应使用delete关键字释放它,以防止内存泄漏。对应于动态变量和动态数组,delete语句有细微区别,语句如下:deletep;//释放动态变量delete[]arr;//释放动态数组,必须在delete后加上[]
以上语句执行后,p和arr指向的内存被释放,它们不再指向有效的内存,不应再访问*p或arr[i],否则将导致未定义的行为,甚至程序崩溃。8.3.5动态分配内存43动态变量的应用应用示例:用户首先输入一个整数n,随后输入n个整数,存入数组中。求出所有元素的和并输出结果。8.3.5动态分配内存intmain(){
intn;cin>>n;//输入数组的大小n
int*arr=new
int[n];//动态分配数组,由于n是变量,不能用intarr[n]方式定义数组
for(inti=0;i<n;i++)cin>>arr[i];
intsum=0;
for(inti=0;i<n;i++)sum+=*(arr+i);cout<<
"数组元素的和为:"
<<
sum<<endl;
delete[]arr;//释放分配的内存
return0;}newint[n]在堆上分配了一个包含n个int类型元素的数组空间,并让指针arr指向该数组的首元素。通过指针和索引,可以访问并修改数组中的每个元素。使用delete[]arr;释放内存。注意使用delete[]。44忘记调用delete释放内存会导致内存泄漏。释放后,指针成为悬空指针,应避免再解引用。以下程序错误:
int*ptr=newint;
deleteptr;
*ptr=10;//将导致程序崩溃不要尝试释放未通过new或new[]分配的指针。以下程序错误:
intarr[10];
delete[]arr;//delete的内存arr未由new分配不要重复释放同一个指针。例如以下程序错误:
int*arr=newint[5];
delete[]arr;
delete[]arr;//一块内存不能delete两次注意事项8.3.5动态分配内存内容导航章节的标题引言迭代器一维数组的定义与使用向量常用操作一维数组的指针实践探究一维数组作函数参数大模型实践应用实例大模型探究向量--动态数组本章小结468.4.1函数定义与调用定义函数时,函数形参中数组的声明语法格式类似于数组定义的语法,但通常在方括号中不指定数组的大小。同时,需要额外添加一个整型形参来表示数组的大小,这个参数对于函数内部进行循环、判断等操作至关重要。例如,定义以下函数计算并返回一维数组中所有元素的总和:intsumArray(intarr[],intsize){inttotal=0;for(inti=0;i<size;i++){total+=arr[i];}returntotal;}数组形参用于表示数组arr的大小47intsumArray(intarr[],intsize);intmain(){
inta[10];
for(inti=0;i<10;i++)a[i]=i;
//调用函数,传递数组名和大小
inttotal=sumArray(a,10);
cout<<"Thesumofthearrayelementsis:"<<total<<endl;
return0;
}函数调用时,直接使用数组名作为实参传递给函数的形参。注意不要写成以下两种形式:
inttotal=sumArray(a[],10);
inttotal=sumArray(a[10],10);8.4.1函数定义与调用以下main函数定义了一个数组,并调用sumArray函数计算全部元素的和:48intsumArray(int*arr,intsize){inttotal=0;for(inti=0;i<size;i++)total+=arr[i];returntotal;}数组形式intarr[]和指针形式int*arr在函数参数中完全等价,编译器会将它们都视为指针。所以,函数内部无法直接知道数组的大小,因此需要通过额外的参数(如size)传递数组长度。8.4.1函数定义与调用数组作为函数形参时,可以直接将参数定义为指针形式,例如:
指向int类型的指针数组作为函数参数传递时,实参是数组名。数组名被解释为数组首元素的地址。将数组名作为参数传递给函数时,实际上传递的是数组的首地址,而不是将整个数组复制一遍传给函数实参和形参共享内存中同一个数组,函数中修改形参数组,将导致实参数组也被修改。498.4.2参数的内存共享508.4.2参数的内存共享voidmodifyArray(intarr[],intsize){
for(inti=0;i<size;i++){
arr[i]+=5;
}}intmain(){
inta[10];
for(inti=0;i<10;i++)a[i]=i;
modifyArray(a,10);
for(inti=0;i<10;i++){
cout<<a[i]<<"";
}
cout<<endl;
return0;}main内存区amodifyArray内存区arrsize105678910111213140123456789i=0i=1i=2i=9i=10下面的示例展示了如何在函数中修改数组元素,并观察这些修改如何影响原始数组。输出结果为“567891011121314”51下面的示例展示了如何在函数中修改数组元素,并观察这些修改如何影响原始数组。8.4.2参数的内存共享参数传递时,arr和a实际上指向同一块内存区域,即它们代表的是同一个数组通过modifyArray函数对arr数组的元素进行修改,实际上也就修改了main函数中a数组的元素值。当modifyArray函数执行完毕并退出后,arr指针的作用域结束,它所占用的资源被释放。voidmodifyArray(intarr[],intsize){
for(inti=0;i<size;i++){
arr[i]+=5;
}}intmain(){
inta[10];
for(inti=0;i<10;i++)a[i]=i;
modifyArray(a,10);
for(inti=0;i<10;i++){
cout<<a[i]<<"";
}
cout<<endl;
return0;}注意:不可使用范围for循环遍历arr内容导航章节的标题引言迭代器一维数组的定义与使用向量常用操作一维数组的指针实践探究一维数组作函数参数大模型实践应用实例大模型探究向量--动态数组本章小结53思路整个程序定义两个函数:(1)insert函数:实现数组插入操作。(2)main函数:初始化数组和相关变量,获取用户输入(插入位置k和插入元素x),调用insert函数完成插入操作,最后输出结果。insert函数接受4个输入参数:数组arr、数组大小n、插入位置k、待插入元素x
首先判断插入位置k是否有效(应该在0到n之间),如果无效,直接返回for循环移动元素:为新元素x腾出空间。逻辑为:从数组的最后一个有效元素(arr[n-1])开始,逐个将元素向后移动一位,直到插入位置k。注意:循环从最后一个元素开始,从后向前循环。插入新元素:在for循环完成后,arr[k]的位置已经空出。将x放置到arr[k]。插入新元素后,数组的大小n增加1,通过引用形式的形参n将该结果返回给实参。8.5应用实例【例8-5】:编写一个函数,在数组的第k个位置插入元素x
。4310548.5.3应用实例void
insert(int
arr[],int&
n,int
k,int
x){if(k
<
0
||
k
>
n){cout
<<
"插入位置无效!"
<<
endl;return;}for(int
i
=
n;i
>
k;i--){ arr[i]=
arr[i
-
1];}arr[k]=
x;n++;
}nii>k初始值5第一轮第二轮第三轮012345传入:arr[10]={1,2,3,4,5}n=5k=2x=101234556789iarr[i]6543truetruetruefalse2558.5.3应用实例int
main(){int
arr[10]={1,2,3,4,5};//初始数组,容量为10,当前数组大小为5int
n
=
5;//当前数组大小int
k,x;cout
<<
"请输入要插入的位置k(从0开始计数):";cin
>>
k;cout
<<
"请输入要插入的元素x:";cin
>>
x;insert(arr,n,k,x);cout
<<
"插入后的数组:";for(int
i
=
0;i
<
n;i++)//n已在函数内被修改为6
cout
<<
arr[i]<<
"";return
0;}568.5.3应用实例【例8-6】:编写一个函数,删除数组的第k个位置的元素。解题思路和插入类似void
deleteElem(int
arr[],int
&n,int
k){//确保删除位置在数组范围内if(k
>=
0
&&
k
<
n){ //使用下标遍历数组,从要删除的元素开始for(int
i
=
k;i
<
n
-
1;i++) arr[i]=
arr[i
+
1];//将后续元素向前移动n--;//更新数组大小}else
cout
<<
"删除位置无效!"
<<
endl;}578.5.3应用实例void
deleteElem(int
arr[],int
&n,int
k){if(k
>=
0
&&
k
<
n){
for(int
i
=
k;i
<
n
-
1;i++) arr[i]=
arr[i
+
1];
n--;
}else
cout
<<
"删除位置无效!"
<<
endl;}543nii<n-1初始值6第一轮第二轮第三轮012345传入:arr[10]={1,2,3,4,5,6}n=6k=212667895234truetruetruefalse5456iarr[i]588.5.3应用实例int
main(){int
a[10]={1,2,3,4,5,6},n
=
6;int
k
=
2;//假设我们要删除下标为2的元素deleteElem(a,n,k);//调用函数for(int
i
=
0;i
<
n;i++)//注意,n已经减小了1 cout
<<
a[i]<<
"";cout
<<
endl;return
0;}598.5.3应用实例【例8-7】:编写一个函数,将数组中等于num值的所有元素删除。结合查找和删除元素两个程序的代码:使用for(inti=n-1;i>=0;i--)从数组的最后一个元素开始,逐个向前检查。如果当前元素等于num,参考deleteElem函数的代码删除该元素。//删除数组中所有等于num的元素(从后向前遍历)void
deleteAll(int
arr[],int&
n,int
num){for(int
i
=
n
-
1;i
>=
0;i--){//从数组末尾向前遍历if(arr[i]==
num){//查找当前元素是否等于num//deleteElem(arr,n,i);//可以调用deleteElem函数删除当前元素for(int
j
=
i;j
<
n
-
1;j++)//删除第i个元素 arr[j]=
arr[j
+
1];//将后续元素向前移动n--;//更新数组大小}}}608.5.3应用实例void
deleteAll(int
arr[],int&
n,int
num){for(int
i
=
n
-
1;i
>=
0;i--){if(arr[i]==
num){for(int
j
=
i;j
<
n
-
1;j++) arr[j]=
arr[j
+
1];
n--;
}}}422nii>=0arr[i]==numjj<n-1初始值7第A轮第B轮第B.1轮第B.2轮第C轮第D轮第E轮第F轮第F.1轮第F.2轮第F.3轮第G轮012345传入:arr[10]={1,2,2,2,4,2,5}n=7num=212267896truefalse5truetrue5true6false4truefalse3truetrue652truetrue41truetrue30truefalse551true2true3false55544iarr[i]618.5.3应用实例int
main(){int
a[10]={1,2,2,2,4,2,5};//初始数组int
n
=
7;//当前数组大小int
num
=
2;//要删除的值deleteAll(a,n,num);//删除所有等于num的元素for(int
i
=
0;i
<
n;i++) cout
<<
a[i]<<
"";return
0;}输出结果:输出数组中的5个元素:145
628.5.3应用实例void
deleteAll(int
arr[],int&
n,int
num){for(int
i
=
n
-
1;i
>=
0;i--){if(arr[i]==
num){for(int
j
=
i;j
<
n
-
1;j++) arr[j]=
arr[j
+
1];
n--;
}}}传入:arr[10]={1,2,2,2,4,2,5}n=7num=2如果改成:for(inti=0;i<n;i++)将得到输出结果:“删除后的数组:1245”数组中还留了一个2未被删除。638.5.3应用实例【例8-8】:编写一个函数,向一个有序数组中插入一个num,要求数组仍然保持有序。可以基于现有的insert函数实现。确定插入位置:遍历数组,找到第一个大于或等于num的位置k,k即为插入位置。如果num大于数组中的所有元素,则需要插入到数组末尾。调用insert函数:使用insert函数将num插入到位置k。由于插入位置k是根据num的大小确定的,插入后数组仍然保持有序。voidinsertSorted(intarr[],
int&n,
intnum)
{//向有序数组中插入元素intk=
0;
//插入位置
while
(k<n&&num>arr[k])
//找到第一个大于或等于num的位置
k++;
//insert(arr,n,k,num);//可以调用insert函数插入元素
for
(inti=n;i>k;i--)
//从后向前循环,将元素向后挪一个位置,为新元素腾出空间
arr[i]
=arr[i-
1];
arr[k]
=num;//插入新元素
n++;
//更新数组大小}例如:初始数组是{1,3,5,7,9},要插入num=664intk=
0;
while
(k<n&&num>arr[k])
k++;
for
(inti=n;i>k;i--)
arr[i]
=arr[i-
1];
arr[k]
=num;
n++;
8.5.3应用实例kk<5arr[k]num>arr[k]第1次循环第2次循环第3次循环第4次循环6101132537636567truetruetruetrue01234ia[i]传入:arr[10]={1,3,5,7,9}num=6;n=5;truetruetruefalse13579num=6插入数组arr中k=3的位置1.初始数组是{1,3,5,7,9},要插入的元素num=665intk=
0;
while
(k<n&&num>arr[k])
k++;
for
(inti=n;i>k;i--)
arr[i]
=arr[i-
1];
arr[k]
=num;
n++;
8.5.3应用实例kk<5arr[k]num>arr[k]第1次循环第2次循环第3次循环第4次循环第5次循环第6次循环10101132537103105107truetruetruetrue01234ia[i]传入:arr[10]={1,3,5,7,9}num=10;n=5;truetruetruetrue13579num=10插入数组arr中k=5的位置4true9true5false1092.初始数组是{1,3,5,7,9},要插入的元素num=10一维数组的指针66要编写一个函数对一维数组中的元素进行从小到大的排序,可以采用多种排序算法,如冒泡排序、选择排序、插入排序等。这里使用冒泡排序算法。冒泡排序是一种简单的排序算法,它重复地遍历要排序的数组,比较每对相邻元素,如果它们的顺序错误就把它们交换过来。包含两重循环:(1)外循环外循环的作用是控制整个排序过程需要遍历数组的次数。每完成一次外循环,数组中的一个元素就会被放置到其最终位置上。(2)内循环内循环的作用是在每次外循环中,通过比较和交换相邻元素,将当前未排序部分的最大元素移动到其正确的位置。8.5.3应用实例【例8-9】:编写一个函数,该函数的功能是对一个一维数组中的元素从小到大排序。用户将在main函数中输入数组的元素。void
bubbleSort(int
arr[],int
size){for(int
i
=
0;i
<
size
-
1;i++){for(int
j
=
0;j
<
size
-
i
-
1;j++){if(arr[j]>
arr[j
+
1]){ int
temp
=
arr[j];arr[j]=
arr[j
+
1];arr[j
+
1]=
temp;}}}}678.5.3应用实例ii<size-1ji<size-i-1arr[j]arr[j+1]arr[j]>arr[j+1]temp第A.1轮第A.2轮第A...轮第A.6轮0123456iarr00truetrue85true81true87true85true83true87214358578831483886false85782传入:arr[7]={8,5,7,2,1,4,3}size=7;void
bubbleSort(int
arr[],int
size){for(int
i
=
0;i
<
size
-
1;i++){for(int
j
=
0;j
<
size
-
i
-
1;j++){if(arr[j]>
arr[j
+
1]){ int
temp
=
arr[j];arr[j]=
arr[j
+
1];arr[j
+
1]=
temp;}}}}688.5.3应用实例ii<size-1ji<size-i-1arr[j]arr[j+1]arr[j]>arr[j+1]temp第B.1轮第B.2轮第B...轮第B.5轮0123456iarr10truetrue57false1true72true74true3true75278727721435false7147373void
bubbleSort(int
arr[],int
size){for(int
i
=
0;i
<
size
-
1;i++){for(int
j
=
0;j
<
size
-
i
-
1;j++){if(arr[j]>
arr[j
+
1]){ int
temp
=
arr[j];arr[j]=
arr[j
+
1];arr[j
+
1]=
temp;}}}}698.5.3应用实例0123456iarr1234578ii<size-1ji<size-i-1arr[j]arr[j+1]arr[j]>arr[j+1]temp第F轮50truetrue12false1false6false708.5.3应用实例int
main(){int
a[10];for(int
i
=
0;i
<
10;i++)
cin>>a[i];bubbleSort(a,10);for(int
i
=
0;i
<
10;i++) cout
<<
a[i]<<
"";return
0;}更多应用实例、数组指针编程以及循环数组请学习进阶内容内容导航章节的标题引言迭代器一维数组的定义与使用向量常用操作一维数组的指针实践探究一维数组作函数参数大模型实践应用实例大模型探究向量--动态数组本章小结8.6.1基本用法向量(vector)是一个容器,能存放各种类型对象,还能动态改变大小。向量简介如使用vector<int>myVec(100)创建,初始大小为100,可以往里面无限地添加元素,向量将动态扩充。可以创建空向量vector<int>myVec;,初始时里面没有数据,可以使用插入的方式往里添加向量--动态数组如intmyHouse[100],声明为100个元素,无法存储更多。如果无法在编写代码时确定数组的大小,则不能使用静态数组。静态数组限制72需要包含<vector>头文件定义的语法格式:vector<基类名>向量名(初始大小,初始值);vector<基类名>:vector是关键字,基类名指定了向量中将要存储的元素的类型。向量名:定义的vector对象(变量)的名称,用于在代码中引用该向量。初始大小:指定了向量初始时应包含的元素数量。初始值:指定了所有元素的初始值。在创建向量时,所有元素都会被设置为这个值。vector的使用738.6.1基本用法初始化(1)默认初始化:创建一个空的vector。vector<int>myVec;(2)指定大小和初始值:vector<int>myVec(10);//大小为10,所有元素的初始值为0vector<int>myVec2(10,1);//大小为10,所有元素的初始值为1(3)使用初始化列表:vector<int>myVec={1,2,3,4,5};vector<int>myVec{1,2,3,4,5};748.6.1基本用法语法格式:vector<基类名>向量名(初始大小,初始值);758.6.2添加和删除元素添加元素:使用push_back在vector的末尾添加一个元素。删除元素:使用pop_back删除vector末尾的元素。下面的示例代码将3个整数3、10和19,添加到vector容器v中,然后再删除末尾元素。#include<iostream>#include<vector>//使用向量需要包含的头文件using
namespace
std;int
main(){vector<int>v;//创建一个空向量v.push_back(3);//此时v中的元素为[3]v.push_back(10);//此时v中的元素为[3,10]v.push_back(19);//此时v中的元素为[3,10,19]v.pop_back();//移除后v中的元素为[3,10]return
0;}vector元素访问768.6.3遍历操作(1)基于下标方式的遍历
利用v[i]或v.at(i)函数获取下标i处的元素at函数和“[]”区别:at函数会进行越界检查,如果越界,将抛出异常。程序运行输出结果如下:00031019int
main(){vector<int>
v(3);//创建一个向量对象v,初始包含3个元素,初始值都为0v.push_back(3);//在尾部插入3,现在v包含4个元素
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 黄庭坚与江西诗派
- 2025-2026月考试卷八年级数学上学期期末押题卷(浙教版)(原卷版)
- 方孝孺的刚直不屈
- JJF(鄂) 200-2026 陆域国土空间碳汇核算计量规程
- 新教材统编版八年级语文下册期末考前划重点知识清单
- 2026年会计学专业未来职业规划
- 2026年学校春季开学工作安排方案
- 2026年经营管理行业现状调查报告
- 2026年市场营销案例企业分析报告
- 2026年城市详细规划原理分析报告
- 心理健康课题中期报告范文
- 2025年重庆高一康德期末语文试卷及答案
- 2025年重庆市中考生物试卷真题(含标准答案)
- 2025河南大河网数字科技有限公司招聘74人522截止笔试参考题库附带答案详解
- (高清版)DG∕TJ 08-110-2021 餐饮单位清洁设计技术标准
- 非法金融活动类型与防范指南
- 农业固废处理及资源化
- JJG 894-1995 国家检定校准 规范
- 中外航海文化知到课后答案智慧树章节测试答案2025年春中国人民解放军海军大连舰艇学院
- 商标使用申请书
- 《SPIN销售法精髓》课件
评论
0/150
提交评论