890 likes | 1.02k Views
数 组. 数组:是可以通过下标访问的同类型数据元素的集合 数组的每个元素具有相同数据类型 数组由数组名和下标构成 形如: A[i] , A 为数组名, i 为下标. 一维数组. 定义与初始化 类型修饰符 数组名 [ 元素个数 ] ; 类型修饰符 数组名 [ 〖 元素个数 〗 ]= { 初值表 } ; 说明: 1 、定义时,若不进行初始化,则必须有 [ 元素个数 ] 2 、数组元素最小下标是 0 ,最大下标是个数减 1
E N D
数 组 • 数组:是可以通过下标访问的同类型数据元素的集合 • 数组的每个元素具有相同数据类型 • 数组由数组名和下标构成 • 形如:A[i],A为数组名,i为下标
一维数组 • 定义与初始化 类型修饰符数组名[元素个数]; 类型修饰符数组名[〖元素个数〗]= {初值表}; 说明: 1、定义时,若不进行初始化,则必须有[元素个数] 2、数组元素最小下标是0,最大下标是个数减1 3、若定义时进行初始化(即有初值表),则元素个数可有也可没有。有元素个数时,数组元素的个数以[元素个数]来确定,若决定元素无元素个数,则以初值表中初值的个数个数。
例1:int data[10]; ——定义了一个元素类型为整型的数组,数组共有10个元素,分别为data[0],data[1],……data[9] • 例2:int d[]={1,2,3,4,5,6} ——省略元素个数(中括号不省),数组d共有6个元素 • 例3:int d[6]={1,2} ——数组中前两个元素初值分别为1、2,其余四个元素初值为0,即d[0]的值是1
一维数组应用举例 • 例:输入8个整数,然后按输入的相反顺序输出显示这些数据。 #include <iostream.h> void main( ){ int data[8]; cout<<endl<<“请输入8个整数:”; int i; for(i=0;i<8;i++) cin>>data[i]; //输入8个整数到数组中 cout<<endl: for(i=7;i>=0;i--) cout<<data[i]<<““; //输出8个数组元素的值 }
例4.2(P89) • 输入10个整数到一个数组中,调整这10个数在数组中的排列位置,使得其中最小的一个数成为数组的首元素 • 用选择法:将最小的一个数组元素的下标记下来,与第一个元素交换
#include <iostream.h> void main( ){ int data[10]; int i; for(i=0;i<10;i++) cin>>data[i]; //输入10个整数到数组中 int j=0; //假设最小元素为0号元素,用j记住位置0 for(int i=1;i<10;i++) if(data[i]<data[j]) j=i; //若data[i]小于j号元素,则下标赋值给j if(j>0){ //j>0说明最小元素不是0号元素,因此进行交换 int k=data[0]; data[0]=data[j]; data[j]=k; } cout<<endl; for(m=0;m<10;m++) cout<<data[m]<<‘’; //输出处理后的数据 }
例4.3(P90) • 重新安排12,23,9,34,45,7,78,-33,59,3的顺序,使其按升序排列。显示排序前后的这两个整数序列。
掌握“选择法”排序的基本思想:先从这10个数中挑选出最小的,并通过交换而成为这10个元素的首元素;再从其后的9个数中选出最小的,并通过交换而成为后9个元素的首元素,再从其后的8个数中选出最小的,并通过交换而成为后8个元素的首元素,如此往复,当只剩下最后一个数据时,排序完成。掌握“选择法”排序的基本思想:先从这10个数中挑选出最小的,并通过交换而成为这10个元素的首元素;再从其后的9个数中选出最小的,并通过交换而成为后9个元素的首元素,再从其后的8个数中选出最小的,并通过交换而成为后8个元素的首元素,如此往复,当只剩下最后一个数据时,排序完成。 • 选出最小元素的算法在前一例中已解决
#include <iostream.h> void main( ){ int data[]={12,23,9,34,45,7,78,-33,59,3}; int i,m; for(i=0;i<10;i++) cout<<data[i]<<‘ ’; //显示排序前的10个元素 for(m=0;m<9;m++){ int j=m; //用j记住最小元素位置,先假定data[m]最小 for(int i=m+1;i<10;i++) //将data[m+1]……依次与data[j]比较 if(data[i]<data[j]) j=i; //若data[i]小于j号元素,则下标赋值给j if(j>m){ //j大于m说明不是m号元素最小,需要交换 int k=data[m]; data[m]=data[j]; data[j]=k; } } cout<<endl; for(m=0;m<10;m++) cout<<data[m]<<‘’; //输出排序后的10个元素 }
二维数组的定义和初始化 • 定义二维数组的格式: 类型修饰符数组名[行数] [列数] ; 类型修饰符数组名[〖行数〗] [列数] ={{初值表}, 〖{初值表} 〗} ; 说明:1、行数与列数的下标均从0开始 2、若定义时初始化(即第二种格式),则行数可省,列数不可省,数组的行数由{初值表}的个数决定。
例: float d[4][5]; —定义了一个4行5列单精度数组,未初始化 int num[][3]={{1,3,5},{0},{2,4,6}}; —定义了3行3列的整型数组,并分别初始化为第一行:1,3,5;第二行为0,0,0;第三行为:2,4,6 double data[5][3]={{1,3},{5},{2,4,6}} —定义了5行3列的数组,每一行分别被初始化为 1,3,0;5,0,0;2,4,6;0,0,0;0,0,0
访问二维数组的元素 • 格式:数组名[行下标][列下标] • 注:n行m列的数组,最大行下标是n-1,最大列下标是m-1 • 例: int num[5][3]; //定义 num[4][2]=6.7; //对数组元素赋值 k= num[4][2]; //取数组元素的值
例:输入一个5×5的整数矩阵,然后将之转置并显示这个转置后的矩阵。例:输入一个5×5的整数矩阵,然后将之转置并显示这个转置后的矩阵。 • 所谓转置,是指行列对调,应将i行j列的值与j行i列交换 • 本例中,掌握输入二维数组的方法和输出二维数组的方法,用二重循环实现
#include <iomanip.h> void main( ) { int data[5][5],i,j; for(i=0;i<5;i++) //输入矩阵 for(j=0;j<5;j++) cin>>data[i][j]; for(i=0;i<4;i++) //转置矩阵 for(j=0;j<5;j++){ int d=data[i][j]; data[i][j]=data[j][i]; data[j][i]=d; } for(i=0;i<5;i++) { //输出转置后的矩阵 cout<<endl; for(j=0;j<5;j++) cout<<setw(8)<<data[i][j]; } }
例:输出6行6列数组h的主对角线上的所有元素的语句例:输出6行6列数组h的主对角线上的所有元素的语句 对角线上的元素是行号与列号相等的元素,可用 一重循环实现。 语句: for(int I=0;I<5;I++) cout<<h[I][I]<<‘‘;
字符串数组与字符串 • C++的字符串是一个用双引号括起来的字符序列。 • ‘\0’是一个ASCII码为0的不可显示的字符,称为字符串结束符,每个字符串均有字符串结束符 • 字符串的长度是指引号内字符的个数 • 字符串占用空间:长度为n的字符串需要占用n+1个字节的空间,即每个字符1字节加上字符串结束符1字节。 • 计算字符串长度和占用空间时注意一个转义字符长度为1,占用的空间数也为1字节
例: • “C++程序设计” 字符串长度是11,字符串占用空间12B • “First line\nSecond line” 字符串长度是22(\n是一个转义字符换行) 字符串占用空间23B
字符型数组 • 定义一维字符型数组的方法 char s1[]={‘A’,‘’, ‘s’, ‘t’, ‘r’, ‘i’, ‘n’, ‘g’, ‘\0’}; char s2[]=“A string”; 以上定义的s1和s2是两个初始值完全相同的字符型数组,也可称为是字符串变量。 • 作为字符串变量的一维数组,一般不再使用下标, 而是直接通过数组名访问存在于其中的字符串,如 cout<<s1<<endl<<s2;//将字符串s1,s2分两行显示在屏幕上。
在定义一维字符数组时,注意数组元素个数不能小于字符串长度+1在定义一维字符数组时,注意数组元素个数不能小于字符串长度+1 例: char str[6]=“Hello!” //错误,字符串需7个数组元素空间存放
二维字符数组与字符串 • 二维字符数组定义,如: char WD[][4]={“Sun”, “Mon”, “Tue”, “Wed”, “Thu”, “Fri”, “Sat”} //定义了一个7行4列的二维字符数组 • 若定义时,二维数组的行数省略,则由初始化数据的个数决定,列数则不能省,且列数不能小于最长的初始字符串的长度加1。 • 二维字符数组可看成是数组元素为字符串的一维数组,因此可像通常一维数组一样通过下标访问数组中指定的字符串,如: Cout<<endl<<WD[4]; //输出 Thu
字符串的主要操作 • 求字符串长度strlen(字符串) 求字符串的长度 例:cout<<strlen(“How long?”) //输出9
字符串复制 strcpy(字符串变量,字符串) 功能:字符串复制到字符串变量中,该变量原有内容被覆盖 例:char s[]=“12345”; cout<<strcpy(s, “ABCD”)<<‘’<<s 输出ABCD ABCD
字符串连接 strcat(字符串变量,字符串) 功能:字符串复制到字符串变量中原有字符串后面连接起来。 例:char s[]=“12345”; cout<<strcat(s,“ABCD”)<<‘’<<s; 输出结果:12345ABCD 12345ABCD
字符串比较 strcmp(字符串1,字符串2) 功能:对字符串1和字符串2进行比较,若字符串1和字符串2相等,则返回0,若字符串1大于字符串2,则返回1,若字符串1小于字符串2,则返回-1 例:表达式!strcmp(“ABCD”,”abcd”)作为条件表达式,则该条件为false
求子串位置 strstr(字符串,子串) 功能:在字符串中寻找与子串相同的子串,如找到,返回该字符串的从子串起始处开始的后部分,否则返回一空字符串。 • 字符串输出 cout<<字符串 例:cout<<“Hello!”
字符串输入 方法一:cin>>字符串变量 功能:输出一个无空白字符的字符串 例:cin<<s; //若从键盘输入ABCD 123,则s得到的是ABCD,即遇到空白字符时,滤掉从空白字符开始的后部分 方法二:cin.getline(字符串变量,变量大小) 功能:从键盘输出一个以Enter键结束的字符串 例:char s[81]; cin.getline(s,81); //则键盘输入字符串时,s得到的值是按回车键以前的所有字符
当程序中含有字符串处理函数需包含头文件ctype.h当程序中含有字符串处理函数需包含头文件ctype.h
字符串应用处理举例 • 例:输入一字符串,将其中所有的小写字母换为大写字母,大写字母转换成小写字母,然后显示输出转换后的字符串。 #include<iostream.h> #include<ctype.h> void main( ){ char s[81]; cin.getline(s,81); //字符串输入,可输入空白字符 for(int i=0;s[i];i++) //条件s[i]为字符串结束符时条件不成立 s[i]=(islower(s[i])?toupper(s[i]):tolower(s[i])); cout<<s; }
函数的定义 • 函数定义的基本格式: 类型修饰符函数名(形式参数表)函数体 • 几点说明: 函数体:一个复合语句,用{ }括起来的语句序列。 形式参数表:一系列用逗号隔开的形式参数说明。可以没有参数,但必须有()。函数根据有无参数分为有参函数和无参函数两类。 类型修饰符:指明函数返回值的类型,如int,double,bool等,类型修饰符也可为void,表示无返回值的函数。函数根据返回值的情况分为有返回值函数和无返回值函数两类
有返回值函数 • 必须用int等类型修饰符说明返回值类型 • 必须在函数体采用:return 表达式;结束函数 • 例: double sqare(double n) {return n*n} bool isPositive(int n){ if(n>0) return true; else return false; } 简化为 return n>0;
无返回值函数 • 无返回值函数用void作为类型修饰符,也称为void函数。 • 在无返回值的函数中可以用return;结束函数的运行也可以不用任何return语句 • 例:(以下两种函数定义均可) • void Hi(void) {cout<<“Hi!”<<endl; return;} • void Hi( ) {cout<<“Hi!”<<endl;}
函数的调用 • 函数调用格式: • 函数名(实在参数表) • 函数调用说明: • 实在参数表(简称实参)就是一个表达式 • 调用时必须保证实参在数量和类型上与函数定义中的形式参数表一致 • 若实参与形参在类型上不一致,则进行必要的转换,若类型不兼容,则产生错误。
函数定义为 double sqare(double n) {return n*n} void Hi( ) {cout<<“Hi!”<<endl;} • 则调用为 result=sqare(5.0); 函数调用时,实参5.0传递给n,返回5.0乘5.0的值。 Hi( ) 函数调用时,没有参数,因此不传递参数,函数调用的结果是输出Hi!
作为表达式的函数调用和作为语句的函数调用 • 作为表达式调用:result=sqare(5.0); (有返回值的函数一般作为表达式调用,作为某表达式的一个子表达式,若是无返回值函数则不可作为表达式调用。) • 作为语句调用:Hi( ); (无返回值函数只能作为语句调用,不能作为某表达式的子句,函数调用的功能通过函数的副作用体现,如调用Hi( );显示Hi!) • sqare(5.0);作为语句调用无意义
函数的递归调用* • 函数直接或间接地调用自身,称为递归调用 一般递归算法都必须满足三个条件: • 要有明确的结束递归的条件:如n=0,n=1,此条件可以直接得出结果 • 要解决的问题可以转化为相对简单的同类型的问题:如n!可转化为n*(n-1)!, (n-1)!就是比n!稍简单的同类型的问题 • 随着问题的逐次转换,最终能达到结束递归的条件:算法中的参数n在递归过程中的逐次减少,必然会到达n=0或n=1的时候。
函数原形与头文件 • 函数原形:提供完成函数调用所必需的接口信息的说明性语句 • 函数原形 • 函数原形就是在函数定义格式的基础上去掉了函数体。 • 函数必须先说明后使用函数原形必须位于对该函数的第一次调用处之前。 • 函数原形所能提供的接口信息,函数定义也能提供,因此若函数定义位于对该函数的调用之前,也可不必给出函数原形
函数定义是一种定义性说明,函数原形是一种参考性说明函数定义是一种定义性说明,函数原形是一种参考性说明 • 在典型的应用系统中,函数定义与函数原形的分工被明确化,提供接口信息的任务由函数原形专门担任。 • 将程序文件中函数的原形记录在头文件中 • 在程序开始处用include 命令包含该头文件
C++参数传递的基本方式——传值 • 传值,即只把实参表达式的值传递给被调用的函数中的对应形参变量 • 若形参是一个简单变量,则函数调用时,对应形参变量所获得的值只是实参变量值的一个副本,因此,即便函数中有改变形参变量的值的操作,也只是改变那个实参变量的副本,不会改变实参变量本身。
例: double DOUBLE(double n){ n*=2; //形参变量n的值被改变 return n; } void main( ){ double m=7.0; cout<<endl<<m; //换行后输出7.0 cout<<endl<<DOUBLE(m); //换行后输出函数返回值 14.0 cout<<endl<<m; //输出7.0,函数调用时对 形参的改变不能改变实参的值 }
数组参数 • 一维数组作为函数参数时,可以不限定数组元素的个数。二维以上的数组作为形参其第一维可不限定,其余各维须加以限定。 • 在调用具有数组参数的函数时,须以单独的数组名作为实在参数 • 函数调用,形参数组是对应实参数组的代表,而不是它的副本,因此对形参数组的任何改变实际上就是对实参数组的改变。
例:设计函数sum,它计算并返回参数数组中所有元素的合计值。例:设计函数sum,它计算并返回参数数组中所有元素的合计值。 #include <iostream.h> int sum(int array[],int size){ int s=0; for(int i=0;i<size;i++) s+=array[i]; return s;} void main(){ cout<<sum(v1,5)<<endl; //实参用数组名 }
设计函数sumAll,计算5列二维数组data第一行元素的合计,并把结果存入一维数组result的对应元素中。设计函数sumAll,计算5列二维数组data第一行元素的合计,并把结果存入一维数组result的对应元素中。 #include<iostream.h> void sumAll(int data[][5],int result[],int rows) { for(int i=0;i<rows;i++){ result[i]=0; for(int j=0;j<5;j++)result[i]+=data[i][j]; } } void main(){ int v[][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}}; int s[3]; sumAll(v,s,5); //二维数组v作为函数第一个参数,一维数组s作为第二个参数,参与函数运算,运算结果是v数组每行的和放在一维数组s中,实参直接参与函数运算,且运算结果带回主函数中 for(i=0;i<3;i++)cout<<s[i]; }
可选参数* • 说明一个函数时为形参表中的最后若干个参数设定默认值,被设置默认值的参数称为可选参数 • 在调用这个函数时,若没有给出可选参数对应的实参,则以设定的默认值作为实参传递给函数。 • 调用时,被省略的是最后的连续的若干个可选参数(即不能间隔省略)
例: • 函数具有如下原形: int f(int a, char b, char c=‘Z’,char *s=“READY”); • 函数调用时,可省略最后的连续的若干可选参数。 f(3,’a’,’b’)省略了变量s的实参,等同于 f(2,’a’,’b’,”READY”) f(3,’a’)等同于f(2,’a’,’Z’,”READY”) f(3,’a’,”NOT_READY”)是错误的,不能间隔省略
内联函数* • 在一般函数定义前加上保留字inline,该函数即被说明为内联函数 • 内联函数的作用 • 在程序编译运行时,可以内联展开:即直接用函数体代码来替代对函数的调用 • 对于一些简单的,使用频繁的小函数,将之说明为内联函数可提高运行效率。 • 内联函数的说明是一种参考性说明,可放在头文件中
函数重载与名字混成* • 函数重载即允许定义同名的函数, • 函数重载的条件:重载的函数必须在参数的数量上或类型上与其他同名函数有所不同。 • 在调用同名函数时,编译系统为区分同名的不同函数,用一种特殊方法生成内部函数名,其中不但包含了函数名本身,还包含了函数的参数信息。这种生成内部函数名的方法称为名字混成。
判断多个同名函数是否允许重载* • 重载的函数必须在参数的数量上或类型上与其他同名函数有所不同。 • 若同名函数中有可选参数时,必须保证在逐个去掉可选参数后,仍然在参数个数或类型上与同名函数有所不同。
若函数原形为: • int f(int k, int m=0, double d=0.0); • 则它不能与以下任一同名函数重载: • int f(int); • int f(int,int); • int f(int,int,double); • int f(int,double=0.0); • 因为去掉某些可选参数后,参数与上述函数的参数在数量和类型上都相同
函数原形为 • int fp(char c,int k=0,double d=100.0) • 它可以与同名函数int fp( )重载 • 不能与void fp(char c) 、int fp(char,int) 及void fp(char,int,int)函数重载
函数和变量的作用域 • 函数的作用域 • 一般函数作用域是全局的,不但在定义它的文件中可以调用,而且在同一应用系统的其他程序文件中也可以调用。 • 在说明函数时在前面加static,则函数的作用域为文件作用域,只允许被同一程序文件中的函数调用。