当前位置:首页 >> >>

实验一C++开发环境与程序设计步骤

实验一
一、目的和要求

C++开发环境与程序设计步骤

1. 学习 Visual C++6.0 集成环境,掌握源程序编辑方法; 2. 掌握在 Visual C++6.0 集成开发环境中编译、调试与运行程序的方法; 3. 通过运行简单的 C++程序,初步了解 C++源程序的特点。

二、实验设备及分组
1. Windows2000 以上操作系统; 2. Visual C++6.0 语言环境; 3. 每人一台 PC 机。

三、内容和步骤
(一)C++程序设计步骤
一个 C++程序的设计可分成 5 个步骤: 1. 分析问题。根据实际问题,分析需求,确定解决方法。 2. 编辑源程序。编写 C++源程序,并利用一个编辑器将源程序输入到计算机中的某一个文件中。C++源文件的扩展名为 “.cpp” 。 3. 编译程序。编译源程序,检查语法错误,生成目标代码文件。目标代码文件的扩展名为“.obj” 。 4. 连接程序。将一个或多个目标程序与库函数进行连接后,生成一个可执行文件。可执行文件的扩展名为“.exe” 。 5. 运行程序。执行可执行文件,分析运行结果。若有算法错误,可进一步进行修改、编译、调试。 在编译、连接和运行程序的过程中,都有可能出现各式各样的错误,要不断地修改源程序,重复以上过程,直到获得正 确的结果为止。

(二)Visual C++6.0 上机操作方法
Visual C++6.0 系统包含了许多独立的组件,如编辑器、编译器、调试器以及各种各样为开发 Windows 环境下的 C++程序 而设计的工具。其中最重要的是一个名为 Developer Studio 的集成开发环境(IDE) 。Developer Studio 把所有的 Visual C++工具 结合在一起,集成为一个由窗口、对话框、菜单、工具栏、快捷键及宏组成的和谐系统,通过该集成环境,程序员可以观察 和控制整个开发进程。 使用 Visual C++6.0 调试 C++程序要经过以下几个步骤: 1. 启动 Visual C++6.0 系统 启动 Visual C++6.0 系统有很多种方法, 最常见的是通过鼠标单击 “开始” 菜单, 选择 “程序” , 选择 “Microsoft Visual Studio 6.0” ,选择“Microsoft Visual C++ 6.0”启动 Visual C++6.0。如果已经在桌面上建立了“Microsoft Visual C++ 6.0”图标,则也 可用鼠标双击该图标启动 Visual C++6.0。Visual C++6.0 启动成功后,就产生如图 1.1 所示的 Visual C++集成环境。

图 1.1 典型的 Developer Studio 窗口 图 1.1 显示了一个典型的 Developer Studio 主窗口。它分为几个部分:窗口顶部是菜单和工具栏,其中包括“File(文件) ” 、 “Edit (编辑) ” 、 “View (视图) ” 、 “Insert (插入) ” 、 “Project (项目) ” 、 “Build (编译、 连接和运行) ” 、 “Tools (工具) ” 、 “Windows

(窗口) ” 、 “Help(帮助) ”等菜单,分别对应一个下拉子菜单。左面的一个子窗口是工作区窗口,工作区的右面是编辑子窗口。 最下面是输出子窗口。 除了各种对话框外,Developer Studio 显示两种类型的窗口,即文档窗口和停靠窗口。文档窗口是一般的带边框子窗口, 其中含有源代码文本或图形文档。Window 子菜单中列出了在屏幕上以平铺方式还是以层叠方式显示文档窗口的命令。所有其 他的 Developer Studio 窗口,包括工具栏和菜单栏,都是停靠式窗口。 开发环境有两个主要的停靠窗口――Workspace(工作区)窗口和 Output(输出)窗口。另外还有一个 Debugger(调试器) 停靠窗口,只在调试过程中显示。 停靠窗口可以固定在 Developer Studio 用户区的顶端、底端或侧面,或者浮动在屏幕上任何地方。停靠窗口,不论是浮动 着的或是固定着的,总是出现在文档窗口的上面。这样,就保证了当焦点从一个窗口移到另一个时,浮动的工具栏一直都是 可见的。但这也意味着,文档窗口偶尔会看起来像消失了似的。例如,如果你正在文本编辑器中编辑源代码,此时打开一个 占据整个 Developer Studio 用户区的停靠窗口,源代码文档就会消失,它隐藏在新窗口之下。解决方法是要么关了覆盖的窗口, 要么把它拖到不挡眼的地方去。 值得注意的是,上述各种部件,包括子窗口、菜单栏和工具栏的位置不是一成不变的,可以根据个人的喜好重新安排。 2. 创建项目文件 通常都是使用项目的形式来控制和管理 C++程序文件的,C++的项目中存放特定程序的全部信息,包含源程序文件、库文 件、建立程序所用的编译器和其他工具的清单。C++的项目以项目文件的形式存储在磁盘上。

图 1.2 新建项目对话框

图 1.3 新建项目向导对话框 生成项目的操作步骤为:

(1)选择集成环境中的“File”菜单中的“New”命令,产生“New”对话框,如图 1.2 所示。 (2)选择对话框中的“Projects”标签,以便生成新的项目。在产生新项目时,系统自动生成一个项目工作区,并将新的 项目加入到该项目工作区中。 (3)在项目类型清单中,选择“Win32 Console Application”项目,表示要生成一个 Windows 32 位控制台应用程序的项 目。 (4)在“Location”文本框中输入存放项目文件的文件夹路径,如“C:\DOCUMENTS AND SETTINGS\YU YONG YAN\ 桌面\新建文件夹” 。 (5)在“Project Name”文本框中输入项目名。例如:Exe1_1。 (6)检查“Platforms”文件框中是否已显示“Win 32” ,表示要开发 32 位的应用程序。 (7)单击“New”对话框中的“OK”按钮。产生一个对话框向导,如图 1.3 所示。 选“An empty project” ,按下“Finish”按钮,显示验证对话框,直接按“OK”按钮,这时就产生了一个项目文件。系统 自动加上文件扩展名“.dsw” 。 3. 创建C++源程序文件并将其加入到项目文件 (1)选择“File”菜单中的“New”命令,则产生“New”对话框,如图 1.4 所示。

图 1.4 新建文件对话框 (2)选择对话框中的“Files”标签。 (3)在文件类型清单中,选择“C++ Source File”项目,表示要生成一个C++源程序。 (4)在“File”文本框中输入C++源程序文件名。系统自动加上文件扩展名“.cpp” 。例如:Exe1_1_1.cpp。 (5)若“Add to project”复选框没有选中,则单击该复选框使其选中,表示系统要将指定的源程序文件加入到当前的项 目文件中。 (6)单击“OK”按钮。这时就建立了一个新的C++源程序文件,并已加入到了当前的项目文件中。产生如图 1.5 所示的 窗口。 该窗口有三个子窗口,左边的子窗口为项目工作区窗口;右边的子窗口为源程序编辑窗口,用于输入或编辑源程序;下 边的窗口为信息输出窗口,用来显示出错信息或调试程序的信息。 4. 输入和编辑源程序 在源程序编辑窗口输入例 1.1 中的源程序代码,如图 1.5 所示。 5. 保存源程序文件 选择“File”菜单中的“Save”命令,将源程序保存到相应的文件中。 6. 编译和连接

图 1.5 Visual C++6.0 工作窗口 选择“Build”菜单中的“Compile”或“Build”命令,将源程序编译或编译连接,产生可执行文件。系统自动加上文件扩 展名“.exe” 。例如:Exe1_1_1.exe。 在编译和连接期间,若出现错误,则在信息输出窗口给出错误或警告信息。改正错误后,重新编译或编译连接源程序, 直到没有错误为止。 7. 运行 选择“Build”菜单中的“Execute”命令,则在VC++集成环境的控制下运行程序。被启动的程序在控制台窗口下运行, 与 Windows 中运行 DOS 程序的窗口类似。见下图。

图 1.6 运行结果 注意:也可以单击工具栏中的“! ”按钮(BuildExecute)或者按快捷键“Ctrl+F5” ,直接编译与运行源程序。 8. 打开已存在的项目文件 可用两种方法打开已存在的项目文件: (1)选择“File”菜单中的“Open workspace”命令,然后在弹出的对话框中选择要打开的项目文件。 (2)选择“File”菜单中的“Recent workspaces”命令,然后再选择相应的项目文件。 特别提醒:在调试一个应用程序时,Visual C++集成环境一次只能打开一个项目文件。当一个程序调试完成后,要开始 输入另一个程序时,必须先关闭当前的项目文件,然后为新源程序建立一个新的项目文件。否则将出现不可预测的错误。 关闭当前的项目文件的方法是:选择“File”菜单中的“Close workspace”命令。 9. 退出 Visual C++集成环境 选择“File”菜单中的“Exit”命令,可以退出集成环境。

(三)验证分析程序
1.设计一个 C++程序,输出以下信息: *************** Hello! *************** 解: # include <iostream.h> void main() { cout<<" ***************"<<'\n'; cout<<" Hello!"<<'\n'; cout<<" ***************"<<'\n'; } 运行结果:

*************** Hello! *************** 2.设计一个程序,从键盘输入一个圆的半径,求其周长和面积。 解: # include <iostream.h> void main() { float s,r; cout<<"请输入圆的半径:"<<endl; cin>>r; s=3.14159*r*r; cout<<" 圆的面积为:" <<s<<endl; } 运行结果:请输入圆的半径:5 圆的面积为:78.5397

(四)完成实验项目
1. 2. 设计一个程序,从键盘输入一个小写字母,将它转换成大写字母输出。 输入一个球的半径,求其表面积和体积。

四、课后作业
撰写实验报告。

五、实验机时
2 个标准学时。

实验二
一、目的和要求

数据类型、表达式和输入输出

1.掌握 C++语言数据类型,熟悉如何定义一个整型、字符型、实型变量,以及对它们赋值的方法,了解以上类型数据输 出时所用的格式转换符; 2.学会使用 C++的有关算术运算符,以及包含这些运算符的表达式,特别是自加(++)和自减(——)运算符的使用; 3. 进一步熟悉 C++程序的编辑、编译、连接和运行的过程; 4. 掌握数据的输入输出方法。

二、实验设备及分组
1. Windows2000 以上操作系统; 2. Visual C++6.0 语言环境; 3. 每人一台 PC 机。

三、内容和步骤
(一)验证分析程序
1.编写程序完成变量 x 和变量 y 值的交换,调试程序并观察运行结果。 要交换变量 x 和变量 y 的值,可以借用临时变量 z 进行交换。 一个完整的参考程序如下: #include<iostream.h> void main() { int x,y,z; //A cout<<"x,y= "; cin>>x>>y; cout<<"输入的 x="<<x<<" y="<<y <<endl; z=x; x=y; y=z; cout<<"输出的 x="<<x<<" y="<<y <<endl; } 思考: ? 在键盘上分别按如下格式输入两组数据,并观察程序运行结果: 5,3(回车) 5 3(回车) ? 将程序中的 x,y,z 命名为 auto,break,case,观察是否出错?分析原因。 ? 只将程序 A 行 x 改为大写 X,观察是否出错?分析原因。 ? 修改程序,用条件运算符输出两个数中的较大数。

( x ? 1)( y ? 1) x?z 2.编程序输入 x、y 和 z 的值,计算 的值。

( x ? 1)( y ? 1) x?z 表达式 的值不一定为整数,故程序中变量的类型应采用实型。
参考程序如下: #include<iostream.h> void main() { float x,y,z,e,f ,w; //A cout<<"x,y,z= "<<endl; cin>>x>>y>>z; e= (x+1)*(y-1); //B f=x+y; //C w=e/f; //D cout<<"w="<<w<<endl; } 思考: ? 输入 x=5.4,y=3.1,z=2.7,观察程序运行结果。

? 将程序中 A 行改为“int x,y,z,e,f,w ;”,输入 x=5.4,y=3.1,z=2.7,观察程序运行结果。 ? 将程序中 A 行改为“float x,y,z,w;”, B、C、D 行改为“w=(x+1)*(y-1)/x+y;”,观察程序运行结果。 3.编写程序,从键盘输入一个三位正整数,将其倒序输出。例如:输入 861,输出为 168。 输入的三位数为整数,变量类型按整型进行处理。可采用求余数的方法计算各位上的数,然后逆序输出。参考程序如下: #include<iostream.h> void main() { int n,i,j,k; cout<<"输入一个三位正整数 n:"; cin>>n; i=n%10; //i 存放个位数 n=(n-i)/10; //去掉个位数 j=n%10; //j 存放十位数 n=(n-j)/10; //去掉十位数 k=n; //k 存放百位数 n=i*100+j*10+k; cout<<"逆转数为:"<<n<<endl; } 思考: ? 修改程序,使其先取百位数,再取十位数,最后取个位数。 4.本例测试了不同数据类型之间的数据转换。分析下列程序的运行结果。 #include<iostream.h> void main() { int a=32,b; double c=2.7,d; char e='D',f; b=a+c; //A d=a+c; f=a+e; cout<<"b="<<b<<endl; cout<<"d="<<d<<endl; cout<<"f="<<f<<endl; cout<<b+d+f<<endl; } 思考: ? ? ? 1. 2. 3. 修改程序 A 行,对 b 的输出值四舍五入。 修改程序 B 行,按整型值输出 f。 分析 C 行数据的值的类型。 输入二整数 a、b,实现二个数的交换(不借用第三变量) 。 从键盘输入三角形的三边长,输出三角形的周长和面积(此处假设可以构成三角形) 。 编写程序输入两个整数,输出它们的商和余数。

//B //C

(二)完成实验项目

四、课后作业
1. 从键盘输入一个三位整数 n=abc,从左到右用 a、b、c 表示各位的数字,现要求依次输出从右到左的各位数字,即 输出另一个三位数 m=cba,例如:输入 123,输出 321。 (不得采用实验中已使用过的方法) 2. 撰写实验报告。

五、实验机时
2 个标准学时。

实验三
一、目的和要求
1. 2. 3.

选择结构的程序设计

掌握 Visual C++6.0 集成环境中的单步执行; 熟悉 if 与 switch 语句的格式、执行过程、使用方法及典型案例; 学会使用选择结构解决一般的实际问题,能编写简单的应用程序。

二、实验设备及分组
1. Windows2000 以上操作系统; 2. Visual C++6.0 语言环境; 3. 每人一台 PC 机。

三、内容和步骤
(一)验证分析程序
1.由键盘输入三个数,判断能否构成三角形。 分析: 判断 b+c>a 是否成立,若不成立则一定不能构成三角形;若成立则有可能构成三角形,再判断 b-c<a 是否成立。因 b-c 有 可能小于 0,用 b-c<a 时不能准确描述两边之差小于第三边,需取绝对值进行分析。 参考程序如下: #include<iostream.h> void main() { double a,b,c,t; cout<<"请输入 a 的值"<<endl; cin>>a; cout<<"请输入 b 的值"<<endl; cin>>b; cout<<"请输入 c 的值"<<endl; cin>>c; t=b-c; if(t<0) t=-t; if(b+c>a) { if(t<a) cout<<"能构成三角形"<<endl; else cout<<"不能构成三角形"<<endl; } else cout<<"不能构成三角形"<<endl; } 思考: ? 将程序改为非嵌套的 if 语句实现。 ? 在程序中增加语句,使其在能构成三角形的情况下进一步判断三角形的类型(直角、钝角、锐角三角形) 。 提示:三角形的类型由最长边所对的角决定。假定三角形最长边为 c,其所对的角为 θ。其他两边为 a、b。计算公式如下:

a 2 ? b2 ? c2 cos? ? 2ab
例如, 当 c2=a2+b2 时,为直角三角形; 当 c2>a2+b2 时,为钝角三角形; 当 c2<a2+b2 时,为锐角三角形。 2.某商店“五·一”长假期间购物打折。规则如下: 若每位顾客一次购物, ① 满 1000 元,打九折;

② 满 2000 元,打八折; ③ 满 3000 元,打七折; ④ 满 4000 元,打六折; ⑤ 5000 元,打五折; 编写程序,输入购物款,输出实收款。 解:本例使用了 if-else if 语句进行多重判断。参考程序如下: #include<iostream.h> void main() { double m,p; cout<<"输入购物款:"; cin>>m; if(m<1000) p=m; else if (m<2000)p=0.9*m; else if(m<3000) p=0.8*m; else if(m<4000) p=0.7*m; else if(m<5000) p=0.6*m; else p=0.5*m; cout<<"实收款:"<<p<<endl; } 3.有下列分段函数:

编一程序,输入 x,输出 y 的值。 解:程序如下: #include <iostream.h> void main() { float x,y; cout<<"Input x:"; cin>>x; if (x>=0) if (x>=10) y=x*x*x; else y=x*x-5; else y=x+1; cout<<"y="<<y<<endl; } 运行结果:
Input x: -3 y=-2

(二)完成实验项目
1.设计一个程序,判断从键盘输入的整数的正负性和奇偶性。 2.编写程序,实现下列函数功能:

3.已知奖金税率如下: (a 代表奖金,r 代表税率) a<500(元) r=0% 500≤a<1000 r=3% 1000≤a<2000 r=5%

2000≤a<5000 r=8% a≥5000 r=12% 输入一个奖金数,求税率、应交税款及实得奖金数。 3.输入某一年的年份和月份,计算该月的天数。 提示 (1)一年中的大月(1 月、3 月、5 月、7 月、8 月、10 月、12 月),每月的天数为 31 天; (2)一年中的小月(4 月、6 月、9 月、11 月),每月的天数为 30 天; (3)对于 2 月,则要判断该年是平年还是闰年,平年的 2 月为 28 天,闰年的 2 月为 29 天。 某年符合下面两个条件之一就是闰年: ①年份能被 400 整除; ②年份能被 4 整除,但不能被 100 整除。 4.输入平面直角坐标系中一点的坐标值(x,y) ,判断该点是在那一个象限中或那一条坐标轴上。

四、课后作业
1. 2. 设计一个计算器,可以实现简单的四则运算; 撰写实验报告。

五、实验机时
2 个标准学时。

实验四
一、目的和要求

循环结构的程序设计

1.掌握循环结构 while、do-while、for 等语句格式、执行过程、使用方法及典型案例。 2.学习循环结构的嵌套使用。 3.掌握分支与循环综合程序的编写方法; 4.学习并熟悉 break、continue 的区别与使用。 5.学会常用数值与图形的编程方法。

二、实验设备及分组
1. Windows2000 以上操作系统; 2. Visual C++6.0 语言环境; 3. 每人一台 PC 机。

三、内容和步骤
(一)验证实验程序
1.计算:S=1+2+3+4+?+n。 解: 开始 程序流程图如图 4.1 所示,程序如下:
输入 n sum=0 i=1

#include <iostream.h>
void main()

{ int i,n,sum; cout<<"Input an integer:"; 假 i≤n cin>>n; 真 sum=0; sum=sum+i i=1; i++ while (i<=n) { sum=sum+i; i++; 输出 sum } 结束 cout<<"sum="<<sum<<endl; } 图 4.1 求累加和流程图 运行结果: Input an integer:5 sum=15 2.裴波那契数列的前几个数为 1,1,2,3,5,8,??,其规律为: F1=1 (n=1) F2=1 (n=2) Fn=Fn-1+Fn-2 (n≥3) 编写程序求此数列的前面 40 个数。 分析:可设两个变量 f1 和 f2,它们的初值为 f1=1,即数列的第 1 项,f2=1,即数列的第 2 项,用一个循环结构来求数列 的前 40 项, 每次处理两项, 所以共循环 20 次, 进入循环后, 首先输出 f1、 f2, 然后令 f1=f1+f2, 即可求得第 3 项, 再令 f2=f2+f1, 注意此时的 f1 已经是第 3 项了,所以可求得第 4 项;进入下一次循环时,首先输出第 3、4 项,然后按上述方法求得第 5、6 项,以此类推即可求得前 40 项。 解: #include <iostream.h> #include <iomanip.h> void main() {

long int f1,f2; int i; f1=1;f2=1; for (i=1;i<=20;i++) { cout<<setw(12)<<f1<<setw(12)<<f2; if (i%2==0) cout<<endl; f1=f1+f2; f2=f2+f1; } } 例中“if”语句的作用是使在一行中输出 4 个数。 运行结果:
1 5 34 233 1597 10946 75025 514229 3524578 24157817 1 8 55 377 2584 17711 121393 832040 5702887 39088169 2 13 89 610 4181 28657 196418 1346269 9227465 63245986 3 21 144 987 6765 46368 317811 2178309 14930352 102334155

3.求出 100~200 之间的所有素数,输出时一行打印五个素数。 分析:判断一个数 a 是否为素数,只需将它整除以 2~ a (取整)即可,如果都不能整除,则 a 就是素数。 解: #include <iostream.h> #include <math.h> #include <iomanip.h> void main(void) { int a,k,i,n; n=0; for (a=100;a<=200;a++) { k=sqrt(a); for (i=2;i<=k;i++) if (a%i==0) break; if (i>k) { cout<<setw(12)<<a; n=n+1; if (n%5==0) cout<<endl; } } cout<<endl; } 程序运行后,输出, :
101 127 151 103 131 157 107 137 163 109 139 167 113 149 173

//若 i>k,则 i 为素数 //输出素数 //对素数统计个数

179 199

181

191

193

197

4.编写程序用公式计算 e 的近似值。直到最后一项小于给定精度。 分析:这是一个累加求和的问题,仔细分析各项,可以发现从第二项开始,各项的值为前一项除以序号 n:

Xn ?
解: #include <iostream.h> void main() { double e = 1.0,x = 1.0,y,z; int n=1; cout<< "input 精度:"; cin>>z ; y=1/x ; while(y>=z) { x*=n; y=1/x; e+=y; ++n; } cout<<e<<endl; }

X n ?1 n

思考: ? 将程序中 while 结构改写为 do-while,观察程序的运行结果。 ? 增加“continue”或“break”语句,使程序在输入数据大于 0.01 时,显示“精度要求太低,请重新输入”的提示。 5.有一对兔子,从第 3 个月起每个月生一对兔子,小兔子从第 3 个月起每个月又生一对兔子。假设所有兔子都不死,编 程序计算每个月的兔子是多少对?(求 20 个月) 。 分析:从第 3 个月开始,下个月兔子的对数为本月兔子的对数与上月兔子对数之和。这样可得出该序列的规律是:从第 3 项开始,该项的值为前两项之和。 兔子数目的规律是: 1、1、2、3、5、8、13、21、……。 解: #include <iostream.h> void main( ) { int f1,f2,f3; int i; f1=f2=1; for(i=3;i<=20;i++) { //A f3=f1+f2; cout<<i<<"月兔子对数为:"<<f3<<endl; f1=f2; f2=f3; } } 思考: ? 将程序 A 行中改写为“for(i=20;i>=3;i--)”后,观察程序运行结果; ? 画出本例的流程图。 6.编写程序打印如图 4-2 所示蝶形图形。 分析:此图形为上下对称结构,用-3~3 的整数标识行号 i,则每行字符“B”的个数可表示为 6*|i|+1。每行字符“B”前 空格的个数随着|i|的增大而减少,空格的个数要大于 0。 BBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBB 解: BBBBBBBBB # include <iostream.h> BBB void main() BBBBBBBBB BBBBBBBBBBBBBBB { BBBBBBBBBBBBBBBBBBBBB
图 4-2 蝶形

int i,j,k,d; for(i=-3;i<=3;i++) { cout<<endl; d=i; if (i<0) d=-i; for (j=1;j<=10-3*d;j++) cout<<" "; for (k=1;k<=6*d+3;k++) cout<<"B"; } cout<<endl; } 思考: ? 将程序中的“for(j=1;j<=10-3*d;j++)”用“for(j=1;j<=30-3*d;j++)”改写后,观察程序运行结果。

? 将程序中的“for(i=-3;i<=3;i++)”用“for(i=-10;i<=10;i++)”改写后,观察程序运行结果。 ? 将程序中的“for (k=1;k<=6*d+3;k++)”用“for (k=1;k<=10*d+3;k++)”改写后,观察程序运行结果。 7.将下列 do-while 结构修改为 while 结构,分别观察输出结果。 #include <iostream.h> void main() { int a=0; //A do { a++; cout<<"a="<<a<<endl; } while(a>1); } 思考: ? 将条件 while(a>1)改为 while(a),分别观察输出结果。 ? 将 A 语句改为 a=-10,while(a>1)改为 while(a),计算循环执行的次数。 8.从键盘输入任意多个整数(-999 为结束标志) ,计算其中正数之和。 分析:采用转向语句 break 和 continue 实现。break 在循环体中用于退出本层循环;continue 用于结束本次循环。 解: #include <iostream.h> void main() { int x,s=0; while(1) { cin>>x; if (x==-999) break; //A if (x<0) continue; //B s=s+x; } cout<<"s="<<s<<endl; } 思考: ? 交换 A 行和 B 行的位置,观察程序运行结果。 ? 修改程序“输入任意多个整数(-999 为结束标志) ”为“直到包含 20 个正数时” ,计算正数之和。

(二)完成实验项目
1.编程序打印一个如图 4-3 所示的数字金字塔:

图 4-3

数字金字塔

2.输入一行字符,分别统计出其中英文字母、空格、数字字符、其它字符及单词的个数。 3.设有一个数列,它的前四项为 0、0、2、5,以后每项分别是其前四项之和,编程求此数列的前 20 项。 4.求π 近似值的公式为:

2n 2n 2 2 4 4 2 1 3 3 5 2 n?1 2 n ?1 其中,n=1、2、3?设计一个程序,求出当 n=1000 时的π 的近似值。 5.求出 1~599 中能被 3 整除,且至少有一位数字为 5 的所有整数。如 15、51、513 均是满足条件的整数。

?

?

? ? ? ??

?

?

四、课后作业
1. 设用 100 元钱买 100 支笔,其中钢笔每支 3 元,圆珠笔每支 2 元,铅笔每支 0.5 元,问钢笔、圆珠笔和铅笔可以各 买多少支(每种笔至少买 1 支)? 2. 撰写实验报告。

五、实验机时
2 个标准学时。

实验五
一、目的和要求
1. 2. 3. 4.

数组

掌握一维数组、二维数组、字符数组的定义、初始化赋值、数组元素的引用方法; 掌握求最大、小值、平均值、排序的方法以及有序数组的查找、增加、删除的编程方法; 初步掌握字符串处理函数的使用方法以及字符串复制、连接、测长等程序的编写方法; 掌握数组的典型应用。

二、实验设备及分组
1. Windows2000 以上操作系统; 2. Visual C++6.0 语言环境; 3. 每人一台 PC 机。

三内容和步骤
(一)验证实验程序
1.应用一维数组,对 10 个数进行冒泡排序,使其按照从大到小的顺序输出。 分析:n 个数冒泡排序的方法是将第一个数与其后面的数逐个进行比较,发现大者进行交换,完成后最大的数就放到了第 一个的位置;第二个数与其后面的数逐个进行比较,发现大者进行交换,完成后次大的数就放到了第二个的位置;如此循环, 直到第 n-1 个数与第 n 个数进行比较,发现大者进行交换。 解: #include <iostream.h> void main() { int a[10]; //A int i,j,t; cout<<"输入数据:"<<endl; for(i=0;i<10;i++) //B { cout<<"a["<<i+1<<"]="; cin>>a[i]; } for(i=0;i<=8;i++) { for(j=i+1;j<=9;j++) { if(a[i]<a[j]) { t=a[i]; a[i]=a[j]; a[j]=t; } } } cout<<"排序结果为:"<<endl; for(i=0;i<=9;i++) cout<<"a["<<i+1<<"]="<<a[i]<<" "<<endl; } 思考: ?

将 A 行改为下列程序段: int n; cin>>n; int a[n]”

观察运行结果?分析原因。 ? 将 B 行改为“for(i=1;i<=10;i++)”,观察现象。 2.应用二维数组打印如图 5-1 所示杨辉三角形。 分析:由杨辉三角形可以看出每行数存在以下规律:每行数据的个数与行序相同;每行的第一个数和最后一个数均为 1; 中间的数为上一行同一列的数和其前一列的数之和。 解: 1 #include <iostream.h> 1 1 void main() 1 2 1 { 1 3 3 1 int y[5][5]; 1 4 6 4 1 int i,j,n=5; 图 5-1 杨辉三角形 for(i=0;i<n;i++) { y[i][i]=1; y[i][0]=1; } 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
图 5-2 杨辉三角形

for(i=2;i<n;i++) { for(j=1;j<i;j++) y[i][j]=y[i-1][j-1]+y[i-1][j]; } cout<<"杨辉三角形:"<<endl; for(i=0;i<n;i++)

{ cout<<" "; for(j=0;j<=i;j++) cout<<y[i][j]<<" "; cout<<endl; } } 思考: ? 添加语句输出如图 5-2 所示杨辉三角形。 3.从键盘输入两个字符串,将它们连接成一个字符串。 分析:建立两个变量 i、j,先使 i 指向字符数组 str1 的第一个元素,然后移动 i 使其指向 str1 的末尾,即指向 str1 的最后 一个元素‘\0’ ;再使 j 指向字符数组 str2 的第一个元素,然后将 str2 中的元素分别赋给 str1 中相应位置的元素,直到 str2 结 束为止,即 j 指向 str2 的最后一个元素‘\0’ ;最后在 str1 的末尾添加一个结束标志‘\0’ 。 程序如下: 解: #include <iostream.h> void main(void) { char str1[40],str2[20]; //定义字符数组 str1、str2 int i,j; cout<<"输入二个字符串:"; cin.getline(str1,20); //输入字符串 1 到 str1 中 cin.getline(str2,20); //输入字符串 2 到 str2 中 i=0; //使 i 指向 str1 的第一个元素 while (str1[i]!='\0') //判断 str1 是否结束 i++; //str1 没有结束,使 i 指向下一个元素 j=0; //使 j 指向 str2 的第一个元素 while (str2[j]!='\0') //判断 str2 是否结束 { str1[i]=str2[j]; //str2 没有结束,将 str2[j]赋给;str1[i] i++; //使 i 指向 str1 的下一个元素 j++; //使 j 指向 str2 的下一个元素 } str1[i]='\0'; //在 str1 末尾添加结束标志‘\0’ cout<<str1<<endl; //输出 str1 } 4.编程序将输入的字符串删去空格后输出。

分析:逐个读取每个字符,若为空格将其后面的字符和字符串结束标志前移一位,再从该位置开始,重复上述操作,直 到字符串结束。 解: #include<iostream.h> void main() { char str[]="This is a book!"; int i=0,j; while(str[i]!=NULL) { if(str[i]==' ') { j=i; while(str[j]!=NULL) { str[j]=str[j+1]; j++; } } i++; } cout<<str<<endl; } 思考: ? ? ? //C

//A

//B

将程序中 A 行的“"”用“'”改写,观察现象。 将程序中 B 行的“'”用“"”改写,观察现象。 将程序中 C 行改写为: for(j=1;str[j]!=NULL;j++,cout<<str[j]) ; cout<<endl; 观察输出结果。 编程序将输入字符串中出现的字符除空格外,按从大到小的顺序输出(每个字符只输出一次) 。

?

(二)完成实验项目
1.编程实现将一十进制整数 M 转换为 D 进制数。 2.已知一 int a[20]数组,编程将值为偶数的元素移到数组前端,值为奇数的元素移到数组后端。 (要求元素比较、移动次 数尽量最少) 3.求 S ? 1 ? 4 ? 7 ? 10 ? 13 ? ? ? n ,其中 n≥20。 4.某班有 10 个学生,进行了“数学” 、 “语文” 、 “英语” 、 “C++语言”等科目的考试,编写程序: (1) 将考试成绩输入一个二维数组; (2) 求每门课的平均成绩、每门课的不及格学生的人数及每门课的最高分与最低分; (3) 求每个学生的平均成绩、总分、不及格门数; (4) 按学生平均成绩的高低排序并输出。 5.设计一个程序,打印杨辉三角形。 (使用其它方法) 6.编写程序,实现 str=str1+str2 的操作,此处运算符“+”表示将二个字符串 str1、str2 连接成一个字符串 str。用键盘将二 个字符串输入字符数组 str1 与 str2 中,连接后的字符串存放在字符数组 str 中,并输出连接后的字符串 str。
4 7 10 13 n

四、课后作业
1. 设 A、B、C 为 m 行 n 列矩阵。设计矩阵加法程序,能完成 C=A+B 的操作。m 与 n 用 define 定义为常量,其值由用 户自定义。 2. 已有一按从小到大次序排序好的数组,现输入一数,要求用折半查找法找出该数在数组中的位置。 3. 撰写实验报告。

五、实验机时
4 个标准学时。

实验六
一、目的和要求

函数调用

1.了解函数的定义方法,理解函数的调用; 2.初步掌握函数的递归、嵌套调用; 3.了解函数调用的实参与形参的传递,以及参数默认值的设置。 4.学习并了解重载函数、内联函数的基本概念。

二、实验设备及分组
1. Windows2000 以上操作系统; 2. Visual C++6.0 语言环境; 3. 每人一台 PC 机。

三、内容和步骤
(一)验证实验程序
1.编写一个函数,用递归的方法求 1+2+3+4+?+n 的值。在主函数中进行输入输出。 解: #include <iostream.h> int fun(int n) { int z; if(n<=0) z=0; else z=n+fun(n-1); return(z); } void main(void) { int x,sum; cout<<"请输入 X 的值"<<endl; cin>>x; sum=fun(x); cout<<"求和结果为:"<<sum<<endl; } 运行结果: 请输入 X 的值 10 求和结果为:55 2.编写程序,输入 m 和 n(n>m),求 分析:已知
m cn 的值。

n! m!(n ? m)! cm 根据公式,只要自定义一个函数计算阶乘,即可通过函数调用求出 n 的值。
m cn ?

解: 阶乘函数定义如下: double fact(int k) { int p=1; if((k==0)||(k==1)) return p; else { for(int i=1;i<=k;i++)

p=p*i; return p; } } 一个完整的参考程序如下: #include <iostream.h> double fact(int); void main() { int m,n; double c; cout<<"please input"<<endl; l1: cout<<"n="; cin>>n; cout<<"m="; cin>>m; if (n<m) { cout<<"n must bigger than m!,please reinput:"<<endl; goto l1; } c= fact(n)/( fact(m)* fact(n-m)); cout<<"c="<<c<<endl; //B } double fact(int k) { int p=1; if((k==0)||(k==1)) return p; else { for(int i=1;i<=k;i++) p=p*i; return p; } } 思考: ? 分别输入 n=0,1,3,m=0,1,2 测试程序。 ? 试用静态存储变量设计阶乘函数。 3.编写程序,求两个自然数 m 和 n 的最大公约数和最小公倍数。 分析: 最大公约数就是能同时整除 m 和 n 的最大正整数,可用欧几里德算法(也称辗转相除法)求解。应用欧几里德算法计算 两个数的最大公约数的方法是:求两个数(m、n)相除的余数 r(r=m/n m>n),当余数不为零时,m 取 n 的值,n 取 r 的值, 再求两个数相除的余数,反复进行直到余数为零,除数 n 是最大公约数。 最小公倍数=m× n/最大公约数。 解: #include <iostream.h> int fun1(int c,int d) { int r; r=c%d; while(r!=0) { c=d; d=r; r=c%d;

} return d; } void main() { int m,n,e,d; cout<<"m n="; cin>>m>>n; e=fun1(m,n); d=m*n/e; cout<<" 最大公约数为:"<<e<<endl; cout<<" 最小公倍数为:"<<d<<endl; } 思考: ? 输入两个数 m=36,n=24 观察程序运行结果。 ? 用递归调用的方法实现程序编写,参考程序如下: # include <iostream.h> int fun1(int c,int d) { int r; r=c%d; if(r!=0) { c=d; d=r; fun1(c,d); } return d; } void main() { int m,n,e,d; cout<<"m n="; cin>>m>>n; e=fun1(m,n); d=m*n/e; cout<<" 最大公约数为:"<<e<<endl; cout<<" 最小公倍数为:"<<d<<endl; } ? 编写计算三个数最大公约数的程序。 4.分别输入整数半径和实数半径,使用函数重载计算圆的面积。 分析:由于参数只有一个圆的半径,所以只能对不同类型的参数实现重载。 解:程序如下 #include <iostream.h> #define PI 3.14 int area(int); float area(float); void main() { int r1; cout<<"输入一个整型半径 r=:"; cin>>r1; cout<<"area="<<area(r1)<<endl; float r2; cout<<"输入一个实型半径 r=:"; cin>>r2; cout<<"area="<<area(r2)<<endl; } int area(int x)

{ return PI*x*x; } float area(float x) { return PI*x*x; } 思考: ? 编写重载函数实现对两个整型数、三个整型数、两个实型数、三个实型数等求最小值。 5.使用内联函数计算长方形的面积。 分析:C++编译器在调用遇到内联函数的地方,会用函数体中的代码替换函数。 解: 一个完整的内联函数参考程序如下: #include <iostream.h> float s(float x,float y); void main() { float a,b; cout<<"Input two float a,b="; cin>>a>>b; cout<<"s="<<s(a,b)<<endl; } inline float s(float x,float y) { return x*y; } 思考: ? 将程序中的内联函数进行代码替换,并上机运行,观察结果。

(二)完成实验项目
1.编写函数求:

1?


1 2

?

1 3

?

1 4

?

1 5

?

1 6

?

1 7

???

1 n

2 . 用 函 数 调 用 方 法 打 印 九 九 乘 法 。 3.以下函数是用递归方法计算 x 的 n 阶勒让德多项式的值。已有调用语句“p(n,x); ” ,编写 poly 函数。递归公式如下:

4.已知

f ( x) ? cos(x) ? x x 的初始值为 3.14159/4,用牛顿法求解方程 f ( x) ? 0 的近似解,要求精确到 cos(xn ) ? xn xn?1 ? xn ? sin(xn ) ? 1

。 f ( x) 的牛顿法为:

5.已知 5 个学生 4 门课的成绩,要求主函数分调用各函数实现: (1) (1) 找出每门课成绩最高的学生序号; (2) (2) 找出课程有不及格的学生的序号及其各门课的全部成绩; (3) (3) 求每门课程的平均分数,并输出; (4) (4) 将学生按总分高低排序。 6.设计函数 Fri(int M,int n) ,功能是将 M 个人围成一圈,编号为 1—M,从第 1 号开始报数,报到 n 的倍数的人离开, 一直数下去,直到最后只剩下 1 人。求此人的编号。

四、课后作业
1. 定义子函数如下: sum(int x,int y)

{ return x+y; } 编写程序使用调用语句 sum()、sum(4)和 sum(5,7)分别对带默认参数值的函数 sum 进行调用。sum 函数声明如下:sum(int x=1,int y=2); 2. 撰写实验报告。

五、实验机时
2 个标准学时。

实验七
一、目的和要求
1. 2. 3. 掌握指针、指针变量、指针常量的基本概念; 掌握指针与数组、指针与函数的关系及应用。 初步掌握引用的概念及简单应用。

指针与引用

二、实验设备及分组
1. 2. 3. Windows2000 以上操作系统; Visual C++6.0 语言环境; 每人一台 PC 机。

三、内容和步骤
(一)验证实验程序
1.指针变量的自加、自减、加 n 和减 n 运算。假设数组 a 的首地址为 1000。 解: # include <iostream.h> void main( ) { int a[5]={0,1,2,3,4}; int *p; p=&a[0]; //p 指向 a[0],p=1000 p++ ; //p 指向下一个元素 a[1],p=1004 cout<< *p<<'\t'; //输出 a[1]的内容 1。 p=p+3; //p 指向下 3 个元素 a[4],p=1016 cout<< *p<<'\t'; //输出 a[4]的内容 4。 p――; //p 指向上一个元素 a[3],p=1012 cout<< *p<<'\t'; //输出 a[3]的内容 3。 p=p―3; //p 指向上 3 个元素 a[0],p=1000 cout<< *p<<'\t'; //输出 a[0]的内容 0。 } 运行结果:
1 4 3 0

2.指出下列程序的错误。 #include <iostream.h> void exchange(int,int); void main() { int a,b; cin>>a>>b; cout<<"Before Exchange:a="<<a<<",b="<<b<<endl; exchange(a,b); cout<<"After Exchange:a="<<a<<",b="<<b<<endl; } void exchange(int x,int y) { int t; t=x; x=y; y=t; } 分析:本例的目的是在子函数中交换的两个变量的值,在主函数中使用。但函数的数据传值调用方式是将实参的数据值 传递给形参,实参和形参在内存中占用不同的地址单元,改变形参值不改变实参值。要想通过改变形参的值而改变实参的值, 则应使用指针调用或引用调用。而且引用调用大有取代指针调用之势。

图 7.1 通过指针实现数据交换 解: 使用指针调用如下: #include <iostream.h> void exchange(int*,int*); void main() { int a,b,*p1=&a,*p2=&b; cin>>a>>b; cout<<"Before Exchange:a="<<a<<",b="<<b<<endl; exchange(p1,p2); cout<<"After Exchange:a="<<a<<",b="<<b<<endl; } void exchange(int *x,int *y) { int t; t=*x; *x=*y; *y=t; } 使用引用调用如下: #include <iostream.h> void exchange(int&,int&); void main() { int a,b; cin>>a>>b; cout<<"Before Exchange:a="<<a<<",b="<<b<<endl; exchange(a,b); cout<<"After Exchange:a="<<a<<",b="<<b<<endl; } void exchange(int &x,int &y) { int t; t=x;x=y;y=t; } 3.用指针变量输出二维数组各元素的值。 解: # include <iostream.h> void main( ) { int a[3][3]={{1,2,3},{4,5,6},{7,8,9}}; int *p=&a[0][0]; //将二维数组首地址赋给指针变量 p for (int i=0;i<9;i++) { cout<<*p<<'\t'; //输出二维数组中第 i 个元素值 p++; //指针变量 p 加 1,指向下一个元素 } }

运行结果:
1 2 3 4 5 6 7 8 9

4.用指针与数组作为函数参数,用四种方法求整型数组的最大值。 解: #include <iostream.h> int max1( int a[ ],int n) //形参为数组名 { int i,max=a[0]; for (i=1;i<n;i++) if (a[i]>max) max=a[i]; return max; } int max2( int *p,int n) //形参为指针 { int i,max=*(p+0); for (i=1;i<n;i++) if (*(p+i)>max) max=*(p+i); return max; } int max3( int a[ ],int n) //形参为数组名 { int i,max=*(a+0); for (i=1;i<n;i++) if (*(a+i)>max) max=*(a+i); return max; } int max4(int *p,int n) //形参为指针 { int i,max=p[0]; for (i=1;i<n;i++) if (p[i]>max) max=p[i]; return max; } void main( void) { int b[ ]={1,3,2,5,4,6},*pi; cout<<"max1="<<max1(b,6)<<endl; //实参为数组名,形参为数组 cout<<"max2="<<max2(b,6)<<endl; //实参为数组名,形参为指针变量 pi=b; cout<<"max3="<<max3(pi,6)<<endl; //实参为指针变量,形参为数组 pi=b; cout<<"max4="<<max4(pi,6)<<endl; //实参为指针变量,形参指针变量 } 运行结果:
max1=6 max2=6 max3=6 max4=6

5.变量和数组元素的地址都可以赋给一个指针,一个指针可以加上或减去一个整数;在两个指针指向同一数组不同元素 时,可以进行减运算,结果为其间的数组元素个数。 解: #include<iostream.h> void main() { int i,a[10]; int *p1,*p2; p1=a; //A p2=p1+5; for (i=0;i<=9;i++) { a[i]=i*i; cout<<"a["<<i<<"]="<<a[i]<<endl; } cout<<"a="<<a<<endl; //B cout<<"p1="<<p1<<",p2="<<p2<<endl;

//C } 思考: ? 将程序中 A 行改为“p1=&a[0]”观察程序运行结果。 ? 将程序中 B 行改为“cout<<"*a="<<*a<<endl;”观察程序运行结果。 ? 将程序中 C 行改为“cout<<"a[5]-a[0]="<< a[5]-a[0]<<endl;”观察程序运行结果。 6.使用函数的指针分别调用两个函数 sum1 和 sum2 分别求不大于该数的偶数或奇数之和。 分析:使用函数的指针,可以通过指针的赋值分别调用不同的函数。 解: #include <iostream.h> int sum1(int); int sum2(int); void main() { int a; int (*f)(int); cout<<"Input a data:"; cin>>a; if(a%2==0) { f=sum1; cout<<(*f)(a)<<endl; } else { f=sum2; cout<<(*f)(a)<<endl; } } int sum1(int m) { int s1=0; for(int i=2;i<=m;i=i+2) s1=s1+i; return s1; } int sum2(int n) { int s2=0; for(int i=1;i<=n;i=i+2) s2=s2+i; return s2; } 思考: ? 将 A 行改为“int (*f)(int);”,观察现象。 ? 分别输出两个函数的函数名,观察其地址值。 7.输入两个字符串,将第二个字符串拼接到第一个字符串的尾部,然后输出拼接后的字符串。 解: # include <iostream.h> # include <string.h> char *stringcat(char * p1,char *p2) { char *p=p1; //将目标串首地址赋给指针变量 p。 while(*p1++); //指针 p1 移到 s1 的串尾 p1――; while (*p1++=*p2++); // 将源串 s2 中的字符依次复制到目标串 s1 中。 //A

cout<<"p2-p1="<<p2-p1<<endl; cout<<"*p2-*p1="<<*p2-*p1<<endl;

return p; //返回指向目标串首地址的指针 p。 } void main(void) { char s1[200],s2[100]; cout<<"输入第一个字符串:"; cin.getline( s1,100); cout<<"输入第二个字符串:"; cin.getline( s2,100); cout<<"拼接后的字符串: "; cout<<stringcat(s1,s2)<<endl; //将字符串 s2 拼接到字符串 s1 后输出 s1 的内容。 } 运行结果:
输入第一个字符串:ABCD 输入第二个字符串:EFGH 拼接后的字符串:ABCDEFGH

8.自定义函数实现字符串的拷贝。 分析:字符串不允许进行赋值运算,只能使用头文件 string.h 中定义的 strcpy()库函数。本例要求自己编制一个自定义函数 实现 strcpy()库函数的功能。 解: #include<iostream.h> char *mycopy(char*,const char*); void main() { char s1[]="I am a student"; char s2[20]; mycopy(s2,s1); cout<<"s1="<<s1<<endl; cout<<"s2="<<s2<<endl; } char *mycopy(char *to,const char *from) { char *temp=to; for(;*to++=*from++;); return temp; } ? 将自定义函数改为下列程序段: char *mycopy(char *to,const char *from) { char *temp=to; for(int i=0;*(from+i)!='\0';i++) *(to+i)=*(from+i); *(to+i)='\0';

return temp; } 观察现象。 ? 将自定义函数的声明改为:“char *mycopy(const char*,const char*);” 自定义函数相应改为: char *mycopy(const char *to,const char *from) { char *temp=to; for(;*to++=*from++;); return temp; } 观察现象。 ? 在自定义函数中能否使用如下的语句“*from='a';” 9.编程,判定一个字符在一个字符串中出现的次数,如果该字符不出现则返回 0。 分析:逐个读取字符串中的字符,当所给字符与字符串中的字符相同时,计数器 count 的值加 1 后继续查找,直到字符串

尾。 解:一个完整的参考程序如下: #include <iostream.h> char_count(char *s,char letter) { int count=0; while(*s) if(*s++==letter) count++; return (count); } void main() { char str[100],c; cout<<"input a string:"; cin>>str; cout<< "input a letter:"; cin>>c; cout<<"the count is:"<<char_count(str,c)<<endl; } 思考: ? 修改程序输出每个字符和其出现的次数,不允许字符重复输出。 10.用指针实现字符串拷贝。 解: # include <iostream.h> # include <string.h> void main( ) { char *p1="I am a student" ; char s1[30],s2[30]; strcpy( s1,p1); //用命令拷贝字符串 char *p2=s2; //将数组 s2 首地址赋 p2 for (;*p2++=*p1++;); //用指针拷贝字符串 cout<<"s1="<<s1<<endl; cout<<"s2="<<s2<<endl; } 运行结果: s1= I am a student s2= I am a student 11.使用 new 和 delete 创建动态堆栈。 分析:new 和 delete 运算符可以对数组和结构体进行动态内存分配和释放。 解: #include<iostream.h> struct Stack { int stacksize; long *buffer; long *sp; } p; void ini(int size) { p.stacksize=size; p.sp=p.buffer=new long[size]; } void del() { delete p.buffer; } void push(long data) { if(p.sp>=p.buffer+p.stacksize) cerr<<"stack overflow!\n";

else { *p.sp++=data; cout<<data<<" is pushed."<<endl; } } long pop() { if(p.sp<=p.buffer) { cerr<<"stack is empty!\n"; return 0; } return *--p.sp; } void main() { ini(5); push(1234); push(5678); push(1357); push(2468); cout<<endl; cout<<pop()<<" is poped"<<endl; cout<<pop()<<" is poped"<<endl; cout<<pop()<<" is poped"<<endl; cout<<pop()<<" is poped"<<endl; cout<<pop()<<" is poped"<<endl; del(); } 思考: ? 将程序中 A 行分别改为“ini(2);”和“ini(8);”观察程序运行结果。 12.使用指向指针的指针输出计算机课程名。 分析:指向指针的指针变量即二级指针,其所指向的变量仍是一个指针。指向指针的指针多使用在二维数组,和字符数 组处理过程。 解: #include <iostream.h> char *name[]={"Visual Basic","Visual C++","Delphi","Power Build","Visual Foxpro"}; void main() { char **p =name; for(int i=0;i<5;i++) cout<<*(p+i)<<endl; //A } 思考: ? 将 A 行修改为“cout<<**(p+i)<<endl;”,观察输出结果。 ? 对下面的定义: int a[3]={1,2,3}; int *b[3]={&a[0],&a[1],&a[2]}; int **p=b; 修改程序输出 a 数组元素和 b 数组元素。

//A

(二)完成实验项目
1.下面的程序中,调用了 findmax()函数,该函数寻找数组中的最大元素,将该元素的下标通过参数返回,并返回其地址 值,编程实现 findmax()函数。 # include < iostream.h > int * findmax(int * array, int size, int * index);

void main ( ) { int a[10] = {33,91,54,67,82,37,85,63,19,68}; int * maxaddr; int idx; maxaddr = findmax(a, sizeof(a)/sizeof( * a), &idx); cout<<idx<<endl<<maxaddr << endl<<a[idx] << endl; } 2.读下列程序, (1) 将其改写为传递引用参数; (2) 将 findmax()函数改写成非递归函数(重新考虑参数个数) 。 # include < iostream.h> const size= 10; void findmax(int* a, int n, int i, int * pk); void main ( ) { int a[size]; int n = 0; cout << "请输入" << size << "个数据:"; for(int i=0; i< size; i++) cin >> a[i]; findmax(a, size,0, &n); cout <<"最大值为:" << a[n] << endl <<"其下标为:" << n << endl; } void findmax(int * a, int n, int i, int * pk) { if(i<n) { if(a[i] >a[*pk]) *pk= i; findmax(a,n,i+1,&(*pk)); } } 3. 编制程序, 将输入的一行字符加密和解密。 加密时, 每个字符依次反复加上 “4962873” 中的数字, 如果范围超过 ASCII 码的 032(空格)~122('z'),则进行模运算。解密与加密的顺序相反。编制加密和解密函数,打印各个过程的结果。 例如,加密:the result Of 3 and 2 is not 8 得到密文为:xqk"zlvyuz"wm#7>gpl's$ry"vvw$A 4.编制程序,调用传递引用的参数, 实现两个字符串变量的交换。例如开始: char* ap="hello"; char* bp="how are you"; 交换的结果使得 ap 和 bp 指向的内容分别为: ap: "how are you?" bp: "hello" 5.用指针变量编写下列字符串处理函数: (1)字符串拼接函数 Strcat; (2)字符串比较函数 Strcmp; (3)取字符串长度函数 Strlen。 6.用指针与数组作为函数参数,按下面四种情况对数组 float a[10]进行降序排序: (1)函数的实参为数组名,形参为数组。 (2)函数的实参为数组名,形参为指针变量, 。 (3)函数的实参为指针变量,形参为数组。 (4)函数的实参为指针变量,形参为指针变量。

四、课后作业
撰写实验报告。

五、实验机时
4 个标准学时。

实验八
一、目的和要求
1. 2. 3. 4.

结构体与链表

掌握结构体类型、结构体变量的基本概念; 掌握结构体指针、结构体数组的应用; 掌握链表的基本概念; 掌握链表的基本操作与应用,包括建立链表、遍历链表、插入结点、删除结点、查找结点等。

二、实验设备及分组
1. Windows2000 以上操作系统; 2. Visual C++6.0 语言环境; 3. 每人一台 PC 机。

三、内容和步骤
(一)验证实验程序
1.用三种方式定义职工、学生、日期等结构体变量。 解: # include <iostream.h> # include <string.h> struct employee //定义职工结构体数据类型 { int no ; //职工编号 char name[8]; //职工姓名 char addr[40]; //家庭地址 }; struct student //定义学生结构体数据类型 { int no; //学号 float eng,phy,math,ave; //英语、数学、物理成绩、平均成绩 } stu1,stu2; //定义结构体同时定义结构体变量 stu1、stu2 void main () { employee emp1,emp2; //定义 employ 类型的结构体变量 emp1、emp2。 struct { int year,month,day; } date1,date2; //直接定义日期结构体类型变量。 emp1.no=100; //赋职工号 strcpy ( emp1.name, "zhang sa"); //赋职工姓名 strcpy( emp1.addr, "Nanging"); //赋家庭地址 emp2=emp1; //将职工 emp1 的信息赋给 emp2 cout<<"no="<< emp2.no<<'\t' //输出职工信息 <<"name="<< emp2.name<<'\t' << "addr="<< emp2.addr<<endl; stu1.no=101; //输入学号与成绩 stu1.eng=90; //输入成绩 stu1.phy=95; stu1.math=100; cout<<"eng="<<stu1.eng<<'\t' //输出学生成绩 <<"phy="<<stu1.phy<<'\t' <<"math="<<stu1.math<<endl; date1.year=1999; //输入入学日期 date1.month=09; date1.day=01; cout<<"year="<<date1.year<<'\t' //输出入学日期 <<"month="<<date1.month<<'\t' <<"day="<<date1.day<<endl; } 2.编写程序完成一名职工的姓名、出生年月、奖惩、基本工资的初始化。从键盘输入奖金金额,输出对应职工的姓名、

工龄、奖惩、领取金额等信息。 分析:姓名、出生年月、奖惩、基本工资为不同的数据类型,组成一个有机整体,可以用结构体进行处理,其中出生年 月也用结构体来定义。 解: 一个完整的参考程序如下: #include<iostream.h> struct Date { int year; int month; }; struct Person { char name[20]; Date birth;

//A

char award[20]; float money; float salary; }p={"南苯",{1966,10},"五一劳动奖章",896,0}; void main() { float num; cout<<p.name<<","<<p.award; cout<<",基本工资:"<<p.money<<endl<<"请输入奖金金额:"; cin>>num; p.salary= p. money+num; cout<< p.name <<",年龄"<<2003- p. birth.year; cout<<",应领"<< p.salary<<"元"<<endl; } 思考: ? 删去 A 行的“;”号,运行程序,观察结果,分析原因; ? 修改程序,将结构体变量的定义放在 main()函数内,再运行程序,观察结果,分析原因; ? 修改程序,将结构体类型定义保存为头文件 Person.h,采用#include 命令实现本程序的功能。 ? 修改程序输出三名职工的姓名、工龄、奖惩、领取金额等信息。 3.设链表结点数据结构为: struct node { char name[8]; int score; node *next; }; 编写程序,实现下列链表的基本操作。 (1)建立无序链表。 (2)输出链表上各结点数据。 (3)删除整个链表 (4)删除链表中某个结点数据。 (5)将结点插入到链表指定位置。 (6)建立有序链表 解: 建立链表: node * Create(void ) { int score; //定义输入学生成绩的临时变量 score node *head,*pn,*pt; //定义链表头指针、新结点指针、尾指针 head、pn、pt。 head=0; //链表头指针赋 0,表示链表为空。 cout<<"产生链表,请输入学生成绩与姓名,以-1 为结束:"<<endl; cin>>score; //输入学生成绩 while (score!= -1) //成绩为-1 时结束输入

{ pn= new node; //动态分配新结点内存空间,并将结点地址赋给 pn。 pn->score=score; //将学生成绩输入新结点 cin>>pn->name ; //学生姓名输入新结点 if (head==0) //若链表为空 { head=pn; //则将新结点地址由 pn 赋给头指针 head 与尾指针 pt pt=pn; //使新结点加入到链首 } else //否则链表非空 { pt->next=pn; //将新结点地址由 pn 赋给链尾的 next 指针与尾指针 pt pt=pn; //使新结点加入到链尾 } cin >>score; //输入学生成绩 } pt->next=0; return (head); //链尾指针变量赋 0 //返回链表的头指针

} 输出链表: void Print(const node *head) { const node *p; p=head; cout<<”输出链表中各结点值:”<<endl; while (p!=0 ) { cout<<p->name<<’\t’<<p->score<<endl; p=p->next; } } 删除链表: void Delchain(node * head) { node * p; p=head; //链表头指针赋给 p while (head) //当链表非空时删除结点 { head=p->next; //将链表下一个结点指针赋给 head delete p; //删除链表第一个结点 p=head; //再将头指针赋给 p } } 删除链表上指定值的结点: node * Delete( node *head, char name[]) { node *pc,*pa,*headtemp; headtemp=pc=pa=head; if (head==NULL) //链表为空的情况 { cout << "链表为空,无结点可删!\t"; return NULL; } if (strcmp(pc->name,name)==0) // 第一个结点为要删除结点的情况 { head=pc->next; //将第二个结点的地址赋给 head, //使首结点从链表中分离出来 delete pc; //删除首结点 cout<<"删除了一个结点!\n"; } else //第一个结点不是要删除的结点 { while (strcmp(pc->name,name)) //查找要删除的结点 { pa=pc; //当前结点地址由 pc 赋给 pa pc=pc->next; //pc 指向下一个结点 }

if (pc==NULL) //若 pc 为空表示链表中无要删除的结点 cout << "链表中没有要删除的结点!\n"; else { pa->next=pc->next; //将下结点地址赋给上结点, //使删除结点从链表分离出来 delete pc; //删除指定结点 cout<<"删除一个结点!\n"; } head=headtemp; //返回链表头指针 } 插入结点: node * Insert(node * head, node *pn) { node *pc,*pa; //定义指向插入点前、后的指针 pc 与 pa pc=pa=head; if (head==0) //若链表为空,则新结点插入到链表首 { head=pn; pn->next=0; return head; } if (pn->score>=head->score) //若新结点成绩≥首结点成绩则新结点插在链首 { pn->next=head; head=pn; return head; } while (pc->next!=0 && pn->score<=pc->score) //若链表非空,则按成绩查找插入点 { pa=pc; // pc、pa 移到插入点前、后结点处 pc=pc->next; } if (pn->score <= pc->score) //新结点插入到链尾 { pc->next=pn; pn->next=0; } else //新结点插入到链表中间 { pn->next=pc; pa->next=pn; } return head; //返回链表头指针 } 建立一条有序链表: node *Create_sort( void) { node *pn,*head=0; //定义指向新结点的指针变量 pn 及链表头指针 head int score; //定义输入学生成绩的临时变量 score char name[8]; //定义输入学生姓名的临时变量 name[8] cout<<"产生一条有序链表,请输入数据,以-1 结束!\n"; cin>>score; //输入学生成绩 while (score!= -1) //成绩不等于-1 则循环 { pn=new node; //动态分配 node 类型结点空间,并将其地址赋给 pn cin>>name; //输入学生姓名 strcpy(pn->name,name); //学生姓名、成绩拷贝到结点 name、score 字段中 pn->score=score; head=Insert(head,pn); //调用结点插入函数,将新结点按成绩降序插入链表 cin>>score; //输入学生成绩 } return head; //返回链表头指针 } 主程序: } return head;

# include <iostream.h> # include <string.h> void main(void) //主函数 { node * head; char name[8]; head=Create(); //产生无序链表 Print(head); //输出无序链表 cout<<"输入要删除结点上学生姓名:\n"; cin >>name; //输入要删除结点的学生姓名 head=Delete(head,name); //删除指定姓名的结点 Print(head); //输出显示删除后的链表。 Delchain(head); //删除整个链表 head=Create_sort(); //产生一个有序链表 Print (head); //输出显示有序链表 Delchain(head); //删除整个链表 } 运行结果: 产生无序链表,请输入学生成绩与姓名,以-1 为结束: 90 Zhang 80 Li 70 Wang -1 输出链表中各结点值: Zhang 90 Li 80 Wang 70 输入要删除结点上学生姓名: Li 删除一个结点! 输出链表中各结点值: Zhang 90 Wang 70 产生一条有序链表,请输入数据,以-1 结束! 90 Zhang 80 Li 85 Wang 95 Zhou -1 输出链表中各结点值: Zhou 95 Zhang 90 Wang 85 Li 80

(二)完成实验项目
1.定义一个学生成绩结构体类型,包含“学号” 、 “姓名” 、 “性别” 、 “年龄” 、 “班级” 、 “英语” 、 “数学” 、 “物理” 、 “总分” 、 “名次”等信息。编写 6 个函数分别用于: (1) 使用结构体数组,输入全班 10 名学生的上述信息; (2) 计算每一个学生的总分、平均分; (3) 计算每一门课程的平均分; (4) 查找成绩有不及格的学生信息; (5) 按学生成绩总分降序排序; (6) 输出全班学生的学号、总分及名次。 2.利用上一题的结构类型,创建包含 10 个结点的无序链表。编写 5 个函数分别实现下述功能: (1) 显示链表; (2) 添加结点; (3) 删除结点; (4) 计算每位学生的总分; (5) 按英语成绩排序。

四、课后作业
撰写实验报告。

五、实验机时
2 个标准学时。

实验九
一、目的和要求
1. 2. 3. 4.

类与对象

掌握类、对象的基本概念,理解类中成员的访问权限,正确理解类与结构体的异同; 学习对象的说明和使用方法,掌握构造函数、析构函数的工作原理; 了解 I/O 流类的层次结构,掌握 C++标准输入输出流的用法,能够使用操纵算子格式化输入输出; 了解、掌握文件流的用法。

二、实验设备及分组
1. 2. 3. Windows2000 以上操作系统; Visual C++6.0 语言环境; 每人一台 PC 机。

三、内容和步骤
(一)验证实验程序
1.定义一个描述学生通讯录的类,数据成员包括:姓名、学校、电话号码和邮编;成员函数包括:输出各个数据成员的 值,分别设置和获取各个数据成员的值。 解: 由于姓名、学校和电话号码的数据长度是可变的,可使用动态的数据结构。邮编的长度是固定的,可定义一个字符数组 来存放邮编。将数据成员均定义为私有的。用一个成员函数输出所有的成员数据,用四个成员函数分别设置姓名、单位、电 话号码和邮编,再用四个成员函数分别获取姓名、单位、电话号码和邮编。主函数完成简单的测试工作。 一个完整的参考程序如下: #include <iostream.h> #include <string.h> class COMMU { char *pName; //姓名,数据成员为私有的 char *pSchool; //单位 char *pNum; //电话号码 char Box[10]; //邮编 public: void Print(void) //输出数据成员 { cout<<"姓名:"<<pName<<'\t'; cout<<"单位:"<<pSchool<<'\t'; cout<<"电话号码:"<<pNum<<'\t'; cout<<"邮编:"<<Box<<'\n'; } void Init(char *,char *,char *,char *); void FreeSpace(void); //释放数据成员占用的空间 void SetName(char *name) { if(pName ) delete [ ] pName; //释放存储空间 pName = new char[strlen(name)+1]; //申请存储空间 strcpy(pName,name); } void SetScool(char *unit) //置学校名称 { if( pSchool ) delete [] pSchool; pSchool = new char[strlen(unit)+1]; strcpy(pSchool,unit); } void SetNum(char *num) //置电话号码 { if( pNum ) delete [ ] pNum; pNum = new char[strlen(num)+1]; strcpy(pNum,num);

} void SetBox(char *mailnum) { strcpy(Box,mailnum); } char *GetName(void) { return pName; } char *GetScool(void ) { return pSchool; } char *GetNum(void) { return pNum; } char *GetBox(void) { return Box; } };

//置邮编

//取姓名

//取学校

//取电话号码

//取邮编

void COMMU::Init(char *name,char *unit,char *num,char *b) { //完成初始化 pName = new char [strlen(name)+1]; strcpy(pName,name); pSchool = new char [strlen(unit)+1]; strcpy(pSchool,unit); pNum = new char [strlen(num)+1]; strcpy(pNum,num); strcpy(Box,b); } void COMMU::FreeSpace() { if(pName) delete [] pName; if(pSchool) delete [] pSchool; if(pNum) delete [] pNum; } void main() { COMMU c1,c2; c1.Init("于元","河海大学","025-85595638","210024"); c2.Init("王海","南京理工大学","025-85432455","210015"); c1.Print(); c2.Print(); c1.SetName("王国安"); cout<<c1.GetName()<<'\n'; c1.SetScool("南京理工大学"); cout<<c1.GetScool()<<'\n'; c1.SetNum("025-88755635"); cout<<c1.GetNum()<<"\n"; c1.SetBox("210090"); cout<<c1.GetBox()<<"\n"; c1.Print(); c1.FreeSpace(); c2.FreeSpace(); } 思考: ?

用以下数据测试程序的正确性: 名字改为“李明明”,并输出; 学校改为“北京理工大学”并输出; 电话改为“010—55667878”,并输出; 邮编改为“150035”并输出。 ? 将成员函数的权限改为私有的,观察现象。 ? 将类改为结构体,重新执行程序,输出成员数据。 ? 增加数据成员:邮件地址,手机号码,并将电话号码分为住宅电话和办公电话。 2.设计一个管理图书的简单程序,描述一本书的信息包括:书号,书名,出版社和作者等。提供的基本功能包括:可连

续将新书存入文件“book.dat”中,新书信息加入到文件的尾部;也可以根据输入的书名进行查找;把文件“book.dat”中同书名的 所有书显示出来。 解: 可以把描述一本书的信息定义为一个 Book 类,它包含必要的成员函数。把加入的新书总是加入到文件尾部,所以,以增 补方式打开输出文件。从文件中查找书时,总是从文件开始位置查找,以读方式打开文件。用一个循环语句实现可连续地将 新书加入文件或从文件中查找指定的书名。由于是以一个 Book 类的实例进行文件输入输出的,所以,这文件的类型应该是二 进制文件。 简化的参考程序如下: #include <iostream.h> #include <string.h> #include <fstream.h> class Book { long int num; //书号 char bookname[40]; //书名 char publicname[40]; //出版社 char name[20]; //作者 public: Book(){ num=0; bookname[0] =0;publicname[0] =0; name[0] =0;} char * Getbookname(void) { return bookname ;} long Getnum(void ) { return num;} void Setdata(long , char *,char *,char *); void Show(void ); Book(long , char *,char *,char *); }; void Book::Setdata(long nu , char *bn,char *p,char *n) { num = nu; strcpy(bookname,bn); strcpy(publicname,p); strcpy(name,n); } void Book::Show(void ) { cout<<"书号:"<<num<<'\t'<<"书名:"<<bookname<<'\t'; cout<<"出版社:"<<publicname<<'\t'<<"作者:"<<name<<'\n'; } Book::Book(long nu, char * bp,char *p,char *n) { Setdata(nu , bp, p, n); } void main(void) { Book b1,b2; long nu; char bn[40]; //书名 char pn[40]; //出版社 char na[20]; //作者 ifstream file1; ofstream file3; char flag = 'y'; while( flag=='y' ||flag=='Y') //由 flag 控制循环 { cout<<"\t\t 1: 按书名查找一本书!\n"; cout<<"\t\t 2: 加入一本新书!\n"; cout<<"\t\t 3: 退出!\n 输入选择:"; int f; cin>>f; switch(f) { case 1: cout<<"输入要查找的书名:"; cin>>bn; file1.open("book.dat",ios::in | ios::binary);//按读方式打开文件 while(!file1.eof()) { int n; file1.read((char *)&b1,sizeof(Book)); n=file1.gcount(); if(n==sizeof(Book)) {

if(strcmp(b1.Getbookname(),bn)==0) //显示书的信息 b1.Show(); } } file1.close(); break; case 2: cout<<"输入书号:"; cin>>nu; cout<<"输入书名:"; cin>>bn; cout<<"输入出版社:"; cin>>pn; cout<<"输入作者:"; cin>>na; b1.Setdata(nu,bn,pn,na); file3.open("book.dat",ios::app|ios::binary);//增补方式打开文件 file3.write((char*)&b1,sizeof(b1)); file3.close(); break; default: flag = 'n'; } } } 思考:修改程序增加 ? 按出版社、作者从文件中查找书名; ? 输出同一出版社出版的所有书名; ? 按列表的格式输出文件中的所有书名等功能。

(二)完成实验项目
1.定义一个时间类 Time,能提供和设置由时、分、秒组成的时间,并编出应用程序,定义时间对象,设置时间,输出该 对象提供的时间。 2.编写几何图形圆的类 Circle,包括两个属性:圆心 O(另定义 Point(点)类实现)和半径 R。成员函数包括:圆心位 置获取函数 GetO、半径获取函数 GetR、半径位置设置函数 SetR、圆的位置移动函数 MoveTo 以及圆的信息打印函数 Display 等。 3.打印一张 ASCII 表保存到文件,同时输出到显示器。 4.设计一个简单的学生信息管理程序,信息包括:学号、姓名、性别、年龄、班级等。基本功能包括:可以将信息存入 文件或从文件中读出,可以添加、删除、修改学生信息,可以根据学号、姓名从文件中查找学生信息。

四、课后作业
1. 设计一个类实现简化的栈表管理,能动态地产生栈表,并输出栈表中的数据。为简化栈表的处理,假定栈表中的数据 均为实数。要求实现二个栈表对象之间的拷贝。 2. 撰写实验报告。

五、实验机时
4 个标准学时。

实验报告格式
本书的实验内容涉及五个部分,即“目的和要求” 、 “实验设备及分组” 、 “内容和步骤” 、 “课后练习”及“实验机时” 。其 中“内容和步骤”中又设立二个模块: “验证分析程序”和“完成实验项目”模块。 “验证实验程序”模块中针对该次实验的 具体要求与实验的目的, 列了一些典型的例题, 并给出了详细的解法, 同时提了一些问题, 帮助同学们理解要掌握的内容。 “完 成实验项目”模块要求同学们在读懂、验证过例题之后,独立完成题目要求,写出代码,调试通过。 “课后练习”部分的题目 留作同学们自行练习,可以作为理论课作业或课堂提问。 本实验课程的主要成果之一就是实验报告,要严格按照以下格式书写,内容详实,实验数据的采集要准确合理,实验结 果的分析及时、全面。 实验报告格式如下(以实验一为例) :

实验一 一、目的和要求: 二、实验设备:PC 机、Visual C++6.0 三、实验内容:

C++开发环境与程序设计步骤

(一)实验准备:本次实验涉及的知识介绍(如循环程序概念等) ,或操作步骤(如实验一中的上机步骤 等) 。 (二)实验项目:主要是“完成实验项目”部分的内容,要求题题过关,有题目、分析或方案、代码,并 给出测试数据、运行结果,如有异常现象,还要进行分析、总结。 四、实验小结: 每次实验必须有小结,如实验心得或体会等。要求内容充实不空洞,否则本次实验以零分计。