560 likes | 756 Views
大学 C++ 程序设计教程. 西安交通大学 计算机教学实验中心 http://ctec.xjtu.edu.cn. 第 4 章 数组和结构体. 本章目标 掌握数组定义的规则。 掌握数组的初始化方法及数组元素的引用。 掌握有关数组的基本算法。 掌握字符串处理函数的应用。 掌握结构体定义和使用的规则 学会使用 VC++6.0 开发环境中的 Debug 调试功能:单步执行、设置断点、观察变量值。. 授 课 内 容. 4.1 数组 4.2 字符型数组和字符串处理库函数 4.3 结构体类型 4.4 数组 和结构体 4.5 构体嵌套 程序设计举例
E N D
大学C++程序设计教程 西安交通大学 计算机教学实验中心http://ctec.xjtu.edu.cn
第4章 数组和结构体 • 本章目标 • 掌握数组定义的规则。 • 掌握数组的初始化方法及数组元素的引用。 • 掌握有关数组的基本算法。 • 掌握字符串处理函数的应用。 • 掌握结构体定义和使用的规则 • 学会使用VC++6.0开发环境中的Debug调试功能:单步执行、设置断点、观察变量值。
授 课 内 容 • 4.1 数组 • 4.2 字符型数组和字符串处理库函数 • 4.3 结构体类型 • 4.4 数组和结构体 • 4.5 构体嵌套 • 程序设计举例 • 调试技术
4.1、数组 • 迄今为止,我们使用的都是属于基本类型(整型、字符型、实型)的数据,c语言还提供了构造类型的数据,它们有:数组类型、结构体类型、共用体类型。 • 构造类型数据是由基本类型数据按一定规则组成的,因此有的书称它们为“导出类型”。
问题的引出: • 实际应用的程序设计中,只用几个变量的情况是极少的;更多的情况是处理大批量的相同类型或不同类型的数据。 • 相同类型数据举例:统计交大15,000学生英语4级统考成绩; • 不同类型数据举例:管理交大15,000学生学籍信息记录,包括:姓名、学号、出生日期、班级、各科成绩等。 • 用什么样的数据结构来描述这类应用更简洁?
一维数组 例如: int array[10]; • 常用于处理大批量数据; • 数据特点:存在内在联系; • 数组——具有相同数据类型的变量集合; • 这些变量都有相同名字,但下标不同; • 称这些变量为数组元素; • 只有一个下标——一维数组; • 有两个下标——二维数组
一维数组定义 • 数组是具有一定顺序关系的若干变量的集合体,组成数据的变量称为该数组的元素变量,简称元素。 • 一维数组的定义方式为: • 类型说明符 数组名[常量表达式] • 例如: int a[10]; • 它表示数组名为a,有10个元素。
说明 • (1) 数组名定名规则和变量名相同,遵循标识符定名规则。 • (2) 数组名后是用方括弧括起来的常量表达式,不能用圆括弧,下面用法不对:int a(10); • (3)方括弧中的下标表示元素在数组中的位置。C语言的下标从0,必须是整型变量或常量。 • (4)编译系统处理数组说明语句时,为它在内存中分配一定的存储空间,数组在内存中存储时,按下标递增的顺序连续存储各元素的值。
一维数组的初始化 • (1) 在定义数组时对数组元素赋以初值。 • 例如:int a[10]={0,1,2,3,4,5,6,7,8,9}; • (2) 可以只给一部分元素赋值。例如: • int a[10]={0,1,2,3,4}; • 定义a数组有10个元素,但花括弧内只提供5个初值,这表示只给前面5个元素赋初值,后5个元素值为0。
(3) 如果想使一个数组中全部元素值为0,可以写成 • int a[10]={0,0,0,0,0,0,0,0,0,0}; • 不能写成 int a[10]={0*10};
(4) 在对全部数组元素赋初值时,可以不指定数组长度。例如: • int a[5]={1,2,3,4,5}; • 可以写成 int a[]={1,2,3,4,5}; • 在第二种写法中,花括弧中有5个数,系统就会据此自动定义a数组的长度为5。
A[0] A[1] A[2] A[3] A[4] 一维数组初始化 • 例:int A[5]; 在内存存储如图 • 数组的首地址是数组名A • 数组的首地址也是第一个元素的地址&A[0] • C++语言中,数组的整体不能参加数据处理,参加处理的只能是数组中的元素变量。所以要对数组进行初始化。 • 例如:int data[5]={,4,,8,};赋值如图
例4-1 • 题目:给一维数组x输入10个整数,找出x数组中的最大数和最小数。 • 算法分析: • 1、假设数组中第1个元素最大, • 令xmax=a[0] • 2、将a[i](0<= i < n)与max进行比较, • 若a[i] < xmax ,i=i+1,再执行2 • 否则,令xmax=a[i],i=i+1,再执行2 • 3、循环结束,求出最大元素并输出max。 输入 2 1 7 3 12 4 9 输出 max=12
// Example 4-1: • #include <iostream.h> • int main() • { int array[7]; • cout<<"Please input an array with seven elements: "<<endl; • for(int i=0; i<7; i++) cin>>array[i]; • int big = array[0]; • for(int j=0; j<7; j=j+1) • if(array[j]>big) big = array[j]; • cout<<"max="<<big<<endl; • return 0;}
二维数组 • 定义格式: • <类型> <数组名>[<常量表达式1>][<常量表达式2>]; • 例如,三个学生四门课程成绩数据如下: • 85 87 93 88 • 86 90 95 89 • 78 91 82 95 • 利用二维数组存放这些数据更能表现数据之间相互联系的特征。每一行数据表示该学生的各门课程的成绩,而每一列数据表示该门课程各学生的成绩。该数组定义为: • int matrix[3][4];
二维数组存储结构 • 逻辑结构: • 二维数组恰似一张表格(或矩阵)。数组元素中的第一个下标值表示该元素在表格中的行号,第二个下标为列号。M[3][3]具有如下逻辑结构: • M[0][0] M[0][1] M[0][2] • M[1][0] M[1][1] M[1][2] • M[2][0] M[2][1] M[2][2] • 存贮结构: • 二维数组在内存中按一维数组存放、占据一片连续的存贮单元;是“按行顺序”在内存中分配存贮单元。
二维数组初始化 • 1.按照二维数组元素的物理存储次序给所有或部分数组元素提供数据值 • int score[3][4]={ 85,87,93,88,86,90,95,89,78,91,82,95}; • //给数组stu_score每个元素都提供初值 • float matrix[2][3]={ 1.0,3.0}; • //仅为数组matrix的前2个元素提供初值
2.以行结构方式提供各数据值 • int score[3][4]={ {85,87,93,88}, {86,90,95,89}, • {78,91,82,95} };
4.2 字符型数组和字符串处理库函数 • 字符串用双引号括起来,例如,”abc”; • 用字符型数组存放字符串,存放时,在有效字符后自动加’\0’; • 称’\0’为空值,是字符串结束标志; • 有效字符的个数称为字符串长度。 • 例如,”abc”的长度为3,但占4个字节 • (’\0’占一位) 。
字符型数组的定义和初始化 • char weekday [7]={ "MONDAY"}; • char weekday [7]= "MONDAY"; • 字符串的输入与输出 • char name[20]; • cin>>name; • cin.get(name, n); • //第一个是字符数组变量,第二个指定向这个变量//中读入几个字符 • cout<<name;
例4-2 字符串的输入与输出 • 输入和输出 • Please input a name with blank(within 19 characters): • Cong Zhen • Please input the name again • Cong Zhen
例4-2 源程序 • #include <iostream.h> • int main() • { char name1[20], name2[20]; • cout<<"Please input a name with blank(within 19 characters): "<<endl; • cin.get(name1, 20); • cout<<"Please input the name again"<<endl; • cin>>name2; • cout<<"Using function get, the name storing in the variable is: "<<name1<<endl; • cout<<"Using operater <<, the name storing in the variable is: "<<name2<<endl; • return 0; • }
字符串处理库函数 • 需要添加#include <string.h> • stpcpy(): 字符串拷贝; • strcat(): 字符串连接; • strchr(): 在字符串中查找字符; • strcmp(): 字符串比较; • strlen(): 求字符串长度; • strlwr(): 将字符串中的大写字母转换为小写字母; • strrev(): 反转字符串; • strstr(): 在字符串中查找另一个字符串; • strupr(): 将字符串中的小写字母转换为大写字母;…
例4-3 • 编写一个用来计算字符串长度的函数mystrlen(),并用主函数验证 • 算法分析: • 1)设一个计数器变量len=0 • 2)从数组s[len]第一个元素开始进行处理 • 3)若当前的元素值s[len]非空(‘\0’),则len+1,继续执行3;否则,退出循环。 • 4)打印结果len
程序逻辑功能框图 len = 0 str[n] str[len]=‘\0’? 是 否 len=len+1 打印结果len
// Example 4-3:求字符串的长度 • #include <iostream.h> • //计算字符串的长度的函数 • int mystrlen(char string[]) • { • int len = 0; • while(string[len]!='\0') • len = len+1; • return len; • }
//测试计算字符串长度的主函数 • int main() • { char string[100]; • int len = 0; • cout<<"Please input a string (within 99 characters): "<<endl; • cin>>string; • cout<<"The length of the string is:"<<mystrlen(string)<<endl; • return 0; • } 输入 china 输出 The length of the string is:5
4.3 结构体类型 • 迄今为止,已介绍了基本类型(或称简单类型)的变量(如整型、实型、字符型变量等),也介绍了一种构造类型数据——数组,数组中的各元素是属于同一个类型的。 • 但是只有这些数据类型是不够的。有时需要将不同类型的数据组合成一个有机的整体,以便于引用。这些组合在一个整体中的数据是互相联系的。
例如,工人工资单:姓名、单位、编号..... • 例如,学生成绩单:学号、姓名、性别、各科成绩等 • 这些项都与某一学生相联系。 • 可以看到性别(sex)、年龄(age)、成绩(score)、地址(addr)是属于学号为10010和名为“Li Fun”的学生的。 • 如果将num、name、sex、age、score、addr分别定义为互相独立的简单变量,难以反映它们之间的内在联系。
4.3.1 结构体类型的定义 • 结构体作为一种数据构造类型,在C 语言程序中也许需要经历定义——声明——调用的过程。 • 结构体是由不同的数据类型的数据组成的。组成结构体的每个数据成为该结构体的成员项简称成员。 • 在程序使用结构体时,首先要对结构体进行描述,这称为结构体的定义。
struct 结构名 { 数据类型 成员名1; 数据类型 成员名2; …… 数据类型 成员名n; } ; struct student { char name[20]; unsigned long number; float math; float english; float physics; }; 4.3.1 结构体类型的定义
三种结构体变量的声明 • (1)先定义结构体类型,再定义结构体类型变量。 • 例如,日期类型可以定义为 • struct date • { int da_year; • char da_mon; • char da_day; • }; • struct date yesterday,today,tomorrow;
三种声明结构体变量的方式(2) • (2)定义类型的同时声明变量。例如, • struct date • { • int da_year; • char da_mon; • char da_day; • } yesterday, today, tomorrow; • 声明了3个日期类型的变量: yesterday、today和tomorrow。
三种声明结构体变量的方式(3) • (3)直接定义结构体类型变量。例如, • struct • { • int da_year; • char da_mon; • char da_day; • } yesterday, today, tomorrow; • 不出现结构体类型名。
程序设计举例 • 例4-5 编写一个程序,实现矩阵相乘运算 • 例4-6 编写一个用于对整型数组进行排序的程序,排序方法使用简单的交换排序法 • 例4-7 编写一个字符串处理程序,将一个字符串之中的所有小写字母转换为相应的大写字母 • 例4-8 使用数组编写一个统计学生课程平均分的程序 • 例4-9 使用结构体重新编写上题的程序
例4-5 实现矩阵相乘运算 • 算法说明: • 矩阵S(LxN)和矩阵T(NxM)相乘。 • S是L行、N列;T是N行、M列。 • 要求:S的列数和T的行数必须相同。
算法说明(续) 3 1 2 2 0 1 1 2 1 1 0 3 2 1 1 T = S = r11 r12 r13 1*3+0*2+3*1 1*1+0*0+3*2 1*2+0*1+3*1 2*3+1*2+1*12*1+1*0+1*2 2*2+1*1+1*1 SxT = r21 r22 r23 = R
矩阵乘法算法 • 用两重循环实现对Cij的求值: • for(i=0; i<l; i=i+1) • for(j=0; i<n; j=j+1) • 求Cij; • 其中“求Cij”又可以细化为: • Cij = 0; • for(k=0; k<m; k=k+1) • Cij = Cij+Aik×Bkj
// 4-5:计算两个矩阵的乘积 • #include <iostream.h> • int main() • {const int L=4; const int M=5;const int N=3; • double a[L*M]={1.0, 3.0, -2.0, 0.0, 4.0, • -2.0, -1.0, 5.0, -7.0, 2.0, • 0.0, 8.0, 4.0, 1.0, -5.0, • 3.0, -3.0, 2.0, -4.0, 1.0 }; • double b[M*N]={4.0, 5.0, -1.0, • 2.0, -2.0, 6.0, • 7.0, 8.0, 1.0, • 0.0, 3.0, -5.0, • 9.0, 8.0, -6.0 }; • double c[L*N]; int i, j, k;
// 4-5:计算两个矩阵的乘积(续) for(i=0; i<L; i=i+1) for(j=0; j<N; j=j+1) { c[i*N+j] = 0; for(k=0; k<M; k=k+1) c[i*N+j] = c[i*N+j] +a[i*M+k]*b[k*N+j]; } cout << "The result is c=" << endl; for(i=0; i<L; i=i+1) { for(int j=0; j<N; j=j+1) cout << c[i*N+j] << " "; cout << endl; } return 0; }
例4-6 、冒泡排序 • 算法分析: • (1)两两比较相邻元素A(I)和A(I+1)(I=1,2,…N-1),如果A(I)>A(I+1),则交换它们的位置 A(I) A(I+1); • (2)对剩下的N-1个元素,再两两进行比较,按同样规则交换它们的位置,经过N-2次比较,将次最大值交换到A(N-1)的位置; • (3)如法炮制,经过N-1趟的“冒泡处理”,每趟进行N-i次的比较,全部数列有序。
// Example 4-6:冒泡排序 • #include <iostream.h> • int main() • { const int COUNT=16; • int list[COUNT]={503, 87, 512, 61, 908, 170, 897, 275, • 653, 426, 154, 509, 612, 677, 765, 703 }; • for(int i=0; i<COUNT; i=i+1) • for(int j=COUNT-1; j>i; j=j-1) • if(list[j-1]>list[j]) • {int tmp = list[j-1];list[j-1] = list[j];list[j] = tmp;} • cout << "The result is :" << endl; • for(int k=0;k<16;k++)cout << list[k] << " "; • cout<<endl; return 0; • }
例4-7将小写字母转换为大写字母 #include <iostream.h> int main() { char str[]="This is a sample"; cout<<"The original string is: "<<str<<endl; int i = 0; while(str[i]!=0) { if(str[i]>='a' && str[i]<='z') str[i] = str[i]-'a'+'A'; i = i+1; } cout<<"After transform: "<<str<<endl; return 0; }
例4-8 统计学生课程平均分的程序 • 定义二维数组student[6][5], • 其中,给数组student前4列元素读值,第1列为学号,第2列到第4列为4门课程的成绩。第5列为平均分,通过计算求得。
//4-8: 统计学生课程的平均分 • #include <iostream.h> • #define PERSON 6 • #define COURSE 3 • int main() • { int student[PERSON][COURSE+2]; • int i, j; • cout<<"Please input data of student :"<<endl;
for(i=0; i< PERSON; i=i+1) • { cin>>student[i][0];student[i][COURSE+1]=0; • for(j=1; j<= COURSE; j=j+1) • { cin>>student[i][j]; • student[i][COURSE+1]=student[i][COURSE+1]+student[i][j]; • } • student[i][COURSE+1]=student[i][COURSE+1]/ COURSE; • }
//4-8: 统计学生课程的平均分 cout<<"学号 高数 英语 体育 平均分"<<endl; cout<<"--------------------------------------"<<endl; for(i=0; i< PERSON; i=i+1) { for(j=0; j<= COURSE+1; j=j+1) cout<<student[i][j]<<"\t"; cout<<endl; } return 0; }
例4-9 • 使用结构体重新编写上题的程序。 • 算法 定义一个结构体类型StudentType,其中包含学号、各门课程成绩和平均分等数据成员,其值分别通过输入和计算求得。
//Example 4-9: 统计学生课程的平均分 #include <iostream.h> #define PERSON 6 #define COURSE 3 struct StudentType {char id[10]; //学号 int score[COURSE]; //课程成绩 int GPA; //平均分 };