C++程序设计(第2版)课后习题参考答案_第1页
C++程序设计(第2版)课后习题参考答案_第2页
C++程序设计(第2版)课后习题参考答案_第3页
C++程序设计(第2版)课后习题参考答案_第4页
C++程序设计(第2版)课后习题参考答案_第5页
已阅读5页,还剩23页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C++程序设计(第2版)课后习题参考答案教材:《C++程序设计》(第2版),吴乃陵、况迎辉编著,高等教育出版社,ISBN978-7-04-018640-6。本文档范围:第1章(C++基础知识)、第2章(基本控制结构程序设计)、第3章(函数)、第4章(类与对象)四章习题的完整参考答案,含填空、简答、程序阅读与编程题的解题思路和可直接编译运行的参考代码。第5章及以后(数组与指针、模板与数据结构、动态内存分配、继承与多态、流类库、异常处理、STL)如需,可在此基础上继续整理。使用说明:编程题答案不唯一,代码给的是教材配套答案的思路,只求“能跑通、结果正确”;阅读题答案请结合自己跟踪变量值的过程对照。所有代码按ISOC++标准编写,#include<iostream>与usingnamespacestd;为标准写法。第一章C++基础知识一、基本概念与自测题1.1判断下列标识符的合法性。sinbook5arry_nameExample2.1main$1class_cppa3x*ymyname答:合法的是sin、book、_name、main、class_cpp、a3;非法的是5arry(数字开头)、Example2.1(含小数点)、$1(含非法字符$)、x*y(含运算符*)、myname(含空格)。1.2假定有下列变量:cpp

inta=3,b=5,c=0;

floatx=2.5,y=8.2,z=1.4;

charch1='a',ch2='5',ch3='0',ch4;求下列表达式的值,以及运算后各变量的值。表达式表达式的值运算后的变量x+(int)y%a4.5x、y、a均不变(2.5、8.2、3)x=z*b++,b=b*x,b++42x=7.0,b=43ch4=ch3-ch2+ch1'\\'(反斜杠)ch1、ch2、ch3不变int(y/z)+(int)y/(int)z13y、z均不变!(a<b)&&c&&(x*=y)&&b++0x、b不变(2.5、5)ch3||(b+=a*c)||c++1b=5、c=0均不变z=(a<<2)/(b>>1)6a、b不变(3、5)提示:(1)强制类型转换只影响参加运算的值,内存中y仍是8.2;只有赋值、自增、自减才改变变量本身。(2)逗号表达式依次计算,值是最后一项;x=1.4*5=7.0后b变6,再b=b*x=42,最后b++使表达式仍取42、b变43。(3)字符本质是小范围整数:48-53+97=92,即字符'\\'。(4)int(y/z)是先做实数除法再取整得5;int(y)/int(z)是先转整型再整除得8;合计13。(5)c为0即false,与运算短路,右侧的赋值、自增都不执行。(6)ch3为'0',值48,为true,或运算短路,右侧不执行。(7)a=3(二进制011)左移2位得12,b=5右移1位得2,12/2=6。1.3判断下列哪些是常量,哪些是变量。cpp

"China"constintn=10;intm=5;'a'charch='a'

intarray[5]={1,2,3,4,5};chars[]="Hello";答:"China"是文字常量;constintn=10是常变量(有名字、有类型、不可改);intm=5是变量;'a'是文字常量;charch='a'是变量;intarray[5]是数组变量;chars[]是字符数组变量。1.4将下列算式或叙述用C++表达式描述。题目C++表达式(1)π/2+arcsin(x)²+c²acos(-1.0)/2+sqrt(asin(x)*asin(x)+c*c)(2)(x+y)/((x-y)·a^y)(x+y)/((x-y)*pow(a,y))(3)圆心在原点、半径a、b的圆环内的点坐标((x*x+y*y)>=a*a)&&((x*x+y*y)<=b*b)(4)a≠b≠c(三者互不相等)(a!=b)&&(a!=c)&&(b!=c)(5)k≤20并且字符ch不为'\0'(k<=20)&&(ch!='\0')(用pow、sqrt、asin时需#include<cmath>;(4)不能写成a!=b!=c,关系运算符是左结合的,会先算(a!=b)得0或1再与c比较。)1.6设有语句:cpp

inta,b;floatx,y;charch1,ch2,ch3;

cin>>a>>b>>x>>y>>ch1;

ch2=cin.get();

cin>>ch3;从键盘输入:321.87abc(a、b、c三字符两两间有空格),执行后各变量取值如何?答:a=3,b=2,x=1.8,y=7,ch1='a',ch2=''(空格),ch3='b'。原因:>>提取字符时跳过前导空白,取出'a'后输入流中剩下一个空格,cin.get()不跳过空白,读到的就是这个空格。1.7设有语句:cpp

inta,b,c,d;

cin>>oct>>a>>b>>hex>>c>>dec>>d;从键盘输入:23232323,执行后各变量的十进制值是多少?答:a=19(八进制23=2×8+3),b=19(仍按八进制读),c=35(十六进制23=2×16+3),d=23(十进制)。1.8在1.7的基础上若执行cout<<a<<'\t'<<hex<<b<<'\t'<<oct<<c<<endl;,显示结果是什么?答:190x13043。即:a仍按十进制输出19;hex之后的b(值19)以十六进制输出为0x13;oct之后的c(值35)以八进制输出为043。注意格式标志一旦设置会一直有效,直到被新的标志改变。第二章基本控制结构程序设计一、程序阅读题(自测题)2.1.1设有说明inta=3,b=100;,下面循环执行几次?执行后a、b各为多少?cpp

while(b/a>5){

if(b-a>25)a++;

elseb/=a;

}答:循环执行14次,执行后a=17、b=100。跟踪:b始终为100,b-a从97起每次随a加1递减1,始终满足大于25,所以每次进入循环都执行a++,b不会被除小。a由3增到17时,b/a=100/17的整除结果为5,b/a>5不再成立,循环结束——共执行14次(a从3增到17需14次自增)。本题的考点是整除:后一次比较用的是a自增后的值。2.1.2下面程序段的功能是备选答案中的哪一个?当n=10、x=10时打印结果是多少?cpp

cin>>x>>n;

k=0;

do{x/=2;k++;}while(k<n);

y=1+x;

k=0;

do{y=y*y;k++;}while(k<n);

cout<<y<<endl;答:功能为B:y=(1+x2n说明:第一个循环把x连除n次2,y=1+x/2^n;第二个循环把y自乘n次,即2^n次方。x=10时整除10次2后x已为0,故y=1,输出1。2.1.3当num分别为1、2、3时,下面程序段输出什么?cpp

if(num==1)cout<<"Alpha";

elseif(num==2)cout<<"Bata";

elseif(num==3)cout<<"Gamma";

elsecout<<"Delta";答:分别为Alpha、Bata、Gamma(教材原文第二个单词写作Bata,是Beta的笔误,按原样输出)。2.1.4执行下面程序段后m和k的值各为多少?cpp

intm,k;

for(k=1,m=0;k<=50;k++){

if(m>=10)break;

if(m%2==0){m+=5;continue;}

m-=3;

}答:m=11,k=8。跟踪:m:0→5→2→7→4→9→6→11,k依次为1…7完成循环体,第8次判断时m=11≥10直接break,k++未执行,故k停在8。二、编程与综合练习题2.2分段函数:x<1时y=x;1≤x≤10时y=2x-1;x>10时y=3x-11。输入x,输出y。cpp

#include<iostream>

usingnamespacestd;

intmain(){

doublex,y;

cout<<"输入x=";

cin>>x;

if(x<1)y=x;

elseif(x<=10)y=2*x-1;

elsey=3*x-11;

cout<<"y="<<y<<endl;

return0;

}2.3百分制成绩转五分制:90分以上5分,80~89为4分,70~79为3分,60~69为2分,60分以下1分。cpp

#include<iostream>

usingnamespacestd;

intmain(){

intmark,result;

cout<<"请输入百分制成绩:"<<endl;

cin>>mark;

if(mark<0){cout<<"缺考!"<<endl;return0;}

switch(mark/10){

case10:case9:result=5;break;

case8:result=4;break;

case7:result=3;break;

case6:result=2;break;

case5:case4:case3:case2:case1:case0:

result=1;break;

default:cout<<"输入错误!"<<endl;return0;

}

cout<<"五分制成绩:"<<result<<endl;

return0;

}思路:用mark/10把百分制压缩成0~10的整数作为开关量,一个区间一个case。2.4计算个人所得税。月收入1200元起征;超过起征点500元以内部分5%,500~2000元10%,2000~5000元15%,5000~20000元20%,20000~40000元25%,40000~60000元30%,60000~80000元35%,80000~100000元40%,100000元以上45%。cpp

#include<iostream>

usingnamespacestd;

intmain(){

doubleincome,tax=0;

intk;

cout<<"请输入个人月收入:"<<endl;

cin>>income;

if(income<=1200){cout<<"免征个人所得税"<<endl;return0;}

elseincome-=1200;//应纳税所得额

if(income>20000){//两万元一档,故意不写break

k=int(income/20000);

switch(k){

default:tax+=(income-100000)*0.45;income=100000;

case4:tax+=(income-80000)*0.40;income=80000;

case3:tax+=(income-60000)*0.35;income=60000;

case2:tax+=(income-40000)*0.30;income=40000;

case1:tax+=(income-20000)*0.25;income=20000;

}

}

if(income>5000){tax+=(income-5000)*0.20;income=5000;}

if(income>2000){tax+=(income-2000)*0.15;income=2000;}

if(income>500){tax+=(income-500)*0.10;income=500;}

tax+=income*0.05;

cout<<"应征所得税:"<<tax<<endl;

return0;

}思路:从最高档往下逐段计算,每算完一段把income削到该段下限,剩下的部分再进下一段。switch不写break是有意为之(贯穿到下一个case),比逐档if更简洁;低档用不给else的独立if,效果相同。2.5打印由*组成的图形(四行正三角+三行竖条)。cpp

#include<iostream>

usingnamespacestd;

intmain(){

inti,j;

for(i=1;i<=4;i++){//四行三角

for(j=4-i;j>0;j--)cout<<'';

for(j=1;j<=2*i-1;j++)cout<<'*';

cout<<endl;

}

for(i=1;i<=3;i++)cout<<"***"<<endl;//三行竖条

return0;

}思路:难点是每行前导空格数4-i,星号数2i-1,用两个内层循环分别控制。2.6输出字母菱形(A、BBB、CCCCC、DDDDDDD、CCCCC、BBB、A),中间一行的字母由输入得到。cpp

#include<iostream>

usingnamespacestd;

intmain(){

charin;inti,j;

do{

cout<<"输入一个字母:";

cin>>in;

if(in>='a'&&in<='z')in-=32;//小写转大写

}while(in<'A'||in>'Z');

intline=in-'A';

for(i=0;i<=line;i++){//上半三角(含中间行)

for(j=line-i;j>0;j--)cout<<'';

for(j=1;j<=2*i+1;j++)cout<<char(i+'A');

cout<<endl;

}

for(i=line;i>0;i--){//下半三角(少一行)

for(j=0;j<line-i;j++)cout<<'';

for(j=1;j<=2*i-1;j++)cout<<char(i-1+'A');

cout<<endl;

}

return0;

}2.7输入n,求1!+2!+3!+…+n!cpp

#include<iostream>

#include<cstdlib>

usingnamespacestd;

intmain(){

intn,i;doublejch=1,result=0;

cout<<"请输入正整数n:"<<endl;

cin>>n;

if(n<1){cout<<"输入错误!"<<endl;return1;}

for(i=1;i<=n;i++){jch*=i;result+=jch;}//用n!=n*(n-1)!递推

cout<<result<<endl;

return0;

}思路:阶乘用递推而非每次重算,一重循环同时完成阶乘与累加;结果用double,n稍大也不溢出。2.8猴子吃桃:第一天吃一半多一个,以后每天吃前一天剩下的一半多一个,第十天吃之前只剩1个,问共摘了多少个?cpp

#include<iostream>

usingnamespacestd;

intmain(){

inti,x=1;//第十天吃前剩1个

for(i=1;i<10;i++)x=(x+1)*2;//逆推9次

cout<<"开始共有桃子"<<x<<"个。"<<endl;

return0;

}答:共1534个。逆推公式:前一天=(今天+1)×2。2.9输入一组非0整数(以0结束),求平均值,并统计正数、负数个数。cpp

#include<iostream>

usingnamespacestd;

intmain(){

intstem[256],sum=0,pnum=0,nnum=0,i=0;

cout<<"从键盘输入一组非0整数,以输入0标志结束:"<<endl;

cin>>stem[i];

while(stem[i]!=0){

sum+=stem[i];

if(stem[i]>0)pnum++;elsennum++;

i++;cin>>stem[i];

}

if(i==0)cout<<"0个数"<<endl;

else{

cout<<"平均值="<<(double)sum/(pnum+nnum)<<endl;

cout<<"正数个数="<<pnum<<endl;

cout<<"负数个数="<<nnum<<endl;

}

return0;

}2.10找出1~500中满足“除以3余2、除以5余3、除以7余2”的整数。cpp

#include<iostream>

usingnamespacestd;

intmain(){

inti;

for(i=1;i<=500;i++)

if(i%3==2&&i%5==3&&i%7==2)cout<<i<<endl;

return0;

}思路:韩信点兵问题,三个同余条件同时成立用&&连接,遍历1~500逐一检验即可。2.11求1000以内的所有完全数(一个数等于它所有因子之和,如6=1+2+3)。cpp

#include<iostream>

usingnamespacestd;

intmain(){

inti,a,sum_yz;

for(a=1;a<1000;a++){

sum_yz=0;

for(i=1;i<a;i++)if(a%i==0)sum_yz+=i;//求因子和

if(a==sum_yz)cout<<a<<endl;

}

return0;

}答:6、28、496。(注意内层循环没有改动外层控制变量a,若需要改动应另设变量。)2.12把100元换成10元、5元、1元的组合,共有多少种?cpp

#include<iostream>

usingnamespacestd;

intmain(){

inti,j,k,count=0;

for(i=0;i<=10;i++)//10元最多10张

for(j=0;j<=20;j++){//5元最多20张

k=100-10*i-5*j;//余下用1元补

if(k>=0){cout<<i<<'\t'<<j<<'\t'<<k<<endl;count++;}

}

cout<<count<<endl;

return0;

}答:共121种(i取0~10时,j的可取值个数依次为21、19、17…1,合计121)。2.13用反正切展开求π的近似值,误差小于10⁻⁵。cpp

#include<iostream>

#include<cmath>

usingnamespacestd;

constdoublee=1e-5;

intmain(){

doublex,a,sum;

inti=3;

cout<<"请输入正切值:"<<endl;

cin>>x;

a=x;sum=x;

do{

a*=x*x*(-1);//每项=前项×(-x²)

sum+=a/i;//除以项序号

i+=2;

}while(fabs(a/i)>e);

cout<<"arctg(x)="<<sum<<endl;

return0;

}思路:把分子看成一列奇数项,通式an2.14用迭代法求x²+10cosx=0的根,误差限10⁻⁵。迭代式xcpp

#include<iostream>

#include<cmath>

usingnamespacestd;

constdoublee=1e-5;

intmain(){

doublex0,x1;

intn=0;

cout<<"输入初始近似值:"<<endl;

cin>>x1;

do{

x0=x1;

x1=(x0*x0-10*(x0*sin(x0)+cos(x0)))/(2*x0-10*sin(x0));

n++;

}while(fabs(x1-x0)>e&&n<=100000);

if(n>100000)cout<<"超出迭代1e5次"<<endl;

else{

cout<<"方程x*x+10*cos(x)=0的一个根为:"<<x1<<endl;

cout<<"方程误差为:"<<x1*x1+10*cos(x1)<<endl;

}

return0;

}提示:迭代法可能收敛也可能发散,答案中加了最大迭代次数限制防止死循环;初值不同会收敛到不同根。2.15两队各5人一对一比赛,甲队A、B、C、D、E,乙队J、K、L、M、N;A不与J配,M不与D、E配。列出所有可能的配对名单。cpp

#include<iostream>

usingnamespacestd;

intmain(){

charst1[5]={'A','B','C','D','E'},st2[5]={'J','K','L','M','N'};

inti=0,j,k,l,m,n;

for(j=0;j<5;j++){

if(j==0)continue;//A不与J配

for(k=0;k<5;k++){

if(k==j)continue;

for(l=0;l<5;l++){

if(l==j||l==k)continue;

for(m=0;m<5;m++){

if(m==j||m==k||m==l)continue;

if(m==3)continue;//D不与M配

for(n=0;n<5;n++){

if(n==j||n==k||n==l||n==m)continue;

if(n==3)continue;//E不与M配

cout<<st1[0]<<'-'<<st2[j]<<'\t'<<st1[1]<<'-'<<st2[k]<<'\t';

cout<<st1[2]<<'-'<<st2[l]<<'\t'<<st1[3]<<'-'<<st2[m]<<'\t';

cout<<st1[4]<<'-'<<st2[n]<<endl;

i++;

}

}

}

}

}

cout<<i<<endl;//方案总数

return0;

}思路:五重循环穷举全排列,每层用“已占用”判断去重(相当于剔除前面层已选的选手),再剔除两条禁配条件。2.16模拟选举:候选人zhang、wang、li、zhao代号1~4,其余整数为弃权,-1结束;打印各人得票及当选者(得票过半)。cpp

#include<iostream>

#include<iomanip>

usingnamespacestd;

enumcandidate{feipiao,zhang,wang,li,zhao};

intmain(){

intvote[5]={0},i,k=0,n;

cin>>n;

while(n!=-1){

k++;//总票数

if(n>=1&&n<=4)vote[n]++;elsevote[0]++;

cin>>n;

}

for(i=0;i<5;i++){

switch((candidate)i){

casefeipiao:cout<<setw(8)<<"feipiao"<<vote[i]<<endl;break;

casezhang:cout<<setw(8)<<"zhang"<<vote[i];

if(vote[i]>k/2)cout<<"当选";cout<<endl;break;

casewang:cout<<setw(8)<<"wang"<<vote[i];

if(vote[i]>k/2)cout<<"当选";cout<<endl;break;

caseli:cout<<setw(8)<<"li"<<vote[i];

if(vote[i]>k/2)cout<<"当选";cout<<endl;break;

casezhao:cout<<setw(8)<<"zhao"<<vote[i];

if(vote[i]>k/2)cout<<"当选";cout<<endl;break;

}

}

return0;

}2.17把Fibonacci数列前20项的结果存入文件。cpp

#include<fstream>

#include<iostream>

#include<iomanip>

usingnamespacestd;

constintm=20;

intmain(){

intfib0=0,fib1=1,fib2,n;

inti,j,k,l,o;

charch;

ofstreamofile("myfile2_17.txt");//第1步:建立并打开输出文件

ofile<<setw(15)<<fib0<<setw(15)<<fib1;//第2步:按格式写数据

for(n=3;n<=m;n++){

fib2=fib0+fib1;

ofile<<setw(15)<<fib2;

if(n%5==0)ofile<<endl;//每行5个

fib0=fib1;fib1=fib2;

}

ofile.close();//第3步:关闭文件

cout<<"是否要将文件输出?Y或N"<<endl;

cin>>ch;

if(ch=='y'||ch=='Y'){

ifstreamifile("myfile2_17.txt");

while(ifile>>i>>j>>k>>l>>o){

cout<<setw(15)<<i<<setw(15)<<j<<setw(15)<<k<<setw(15)<<l<<setw(15)<<o<<endl;

}

ifile.close();

}

return0;

}思路:教材讲的“三步法”:建文件并关联→按格式写→关闭;读文件同样三步。用while(ifile>>…)作循环条件比eof()判断更稳妥(最后一个数据后可能没有换行符)。2.18把100以内的素数结果存入文件。cpp

#include<fstream>

#include<iostream>

#include<iomanip>

usingnamespacestd;

constintn=100;

intmain(){

inta[n],i,j,count=0;

charch,b[256];

for(i=0;i<n;i++)a[i]=i+1;

a[0]=0;//1不是素数

for(i=0;i<n;i++){//筛法

if(a[i]==0)continue;

for(j=i+1;j<n;j++)if(a[j]%a[i]==0)a[j]=0;

}

ofstreamofile("myfile2_18.txt");

ofile<<"1-100之间的素数:"<<endl;

for(i=0;i<n;i++)

if(a[i]!=0){

ofile<<setw(6)<<a[i];count++;

if(count%10==0)ofile<<endl;

}

ofile.close();

cout<<"是否要将文件输出?Y或N"<<endl;

cin>>ch;

if(ch=='y'||ch=='Y'){

ifstreamifile("myfile2_18.txt");

i=0;

while(ifile.get(b[i])){if(b[i]=='\n')break;i++;}//先读标题行

b[i]='\0';cout<<b<<endl;

count=0;

while(ifile>>i){cout<<setw(6)<<i;count++;

if(count%10==0)cout<<endl;}

ifile.close();cout<<endl;

}

return0;

}提示:读标题行必须用get(),不能用>>(>>会跳过空白,读不到空格与换行)。2.19统计文本文件(如源程序)的行数、单词数和字符数。cpp

#include<fstream>

#include<iostream>

usingnamespacestd;

intmain(){

charch;

intnline=0,nword=0,nch=0,isword=0;

ifstreamifile("ep2_19.cpp");

if(!ifile){cout<<"文件打开失败"<<endl;return1;}

while(ifile.get(ch)){

if(ch=='\n')nline++;

if(ch!=''&&ch!='\t'&&ch!='\n'){

if(!isword)nword++;//单词首字符

nch++;isword=1;

}

elseisword=0;

}

ifile.close();

cout<<"行数:"<<nline<<endl;

cout<<"单词数:"<<nword<<endl;

cout<<"字符数:"<<nch<<endl;

return0;

}思路:文本文件必须用成员函数get()逐字符读,若用>>会丢掉空白字符导致计数失真;用isword标志判断是否处于单词内部,避免一个单词被重复计数。第三章函数一、填空题3.1.1被定义为形参的是在函数中起(1)作用的变量,形参只能用(2)表示。实参的作用是(3),实参可以用(4)、(5)、(6)表示。答:(1)自变量;(2)变量名;(3)把实际参数的值传递给形参;(4)具有值的变量;(5)常量;(6)表达式。3.1.2局部域包括(1)、(2)和(3)。使用局部变量的意义在于(4)。答:(1)块域;(2)函数域;(3)函数原型域;(4)局部变量具有局部作用域,使程序在不同块中可以使用同名变量而互不干扰。3.1.3静态局部变量存储在(1)区,在(2)时建立,生存期为(3);若定义时未显式初始化,初值为(4)。答:(1)全局数据区;(2)编译时(程序开始运行前);(3)全局生存期(整个程序运行期);(4)全0。3.1.4局部变量存储在(1)区,在(2)时建立,生存期为(3);未显式初始化时初值为(4)。答:(1)栈;(2)函数或块开始执行时;(3)函数或块的执行期;(4)随机值(不确定)。3.1.5编译预处理的作用是(1),预处理指令的标志是(2)。多文件系统中程序由(3)管理,用户自定义头文件中通常定义(4)。答:(1)对源程序文件做文本处理、生成中间文件,再由编译器对中间文件编译生成目标代码;(2)#;(3)工程文件;(4)用户构造的数据类型(如枚举、结构、类)、外部变量、外部函数声明、常量和内联函数等。3.1.6设intf(intx,inty){returnx%y+1;},a=10、b=4、c=5,求下列语句的执行结果:cpp

(1)cout<<f(a,b)+f(a,c);(2)cout<<f(f(a+c,b),f(b,c));答:(1)4(f(10,4)=3,f(10,5)=1);(2)5(内层f(15,4)=4、f(4,5)=5,外层f(4,5)=5)。3.1.7写出下列程序的输出。(1)cpp

inta,b;

voidf(intj){

staticinti=a;//静态局部变量,只初始化一次

intm,n;

m=i+j;i++;j++;n=i*j;a++;

cout<<"i="<<i<<"\tj="<<j<<"\t";

cout<<"m="<<m<<"\tn="<<n<<endl;

}

intmain(){a=1;b=2;f(b);f(a);cout<<"a="<<a<<"\tb="<<b<<endl;}答:i=2j=3m=3n=6

i=3j=3m=4n=9

a=3b=2说明:i是静态局部变量,第一次调用时用当时的全局a=1初始化,之后跨调用保留,不再重新初始化;j是形参,每次调用重新由实参赋值。

第一次f(b):j=2,m=1+2=3,i变2、j变3,n=2×3=6,全局a加到2。

第二次f(a):此时全局a已是2,故形参j=2;i保留为2,m=2+2=4,i变3、j变3,n=3×3=9,全局a加到3。(2)cpp

floatsqr(floata){returna*a;}

floatp(floatx,intn){

cout<<"in-process:x="<<x<<"\tn="<<n<<endl;

if(n==0)return1;

elseif(n%2!=0)returnx*sqr(p(x,n/2));

elsereturnsqr(p(x,n/2));

}

intmain(){cout<<p(2.0,13)<<endl;return0;}答:in-process:x=2n=13

in-process:x=2n=6

in-process:x=2n=3

in-process:x=2n=1

in-process:x=2n=0

8192说明:递归共5层,n依次为13→6→3→1→0。递归返回时逐层回代:p(2,0)=1→p(2,1)=2×1²=2→p(2,3)=2×2²=8→p(2,6)=8²=64→p(2,13)=2×64²=8192。输出语句写在递归入口处,所以in-process各行是“由外到内”的顺序。二、简答题3.2.1实参与形参怎样对应?数目必须一致吗?什么情况下可以不同?答:实参与形参按个数和排列顺序一一对应,对应参数应类型匹配(赋值兼容)。数目一般必须一致;当函数声明中给出默认参数时,调用时可以省略尾部若干个实参,此时实参少于形参。3.2.2函数与内联函数的执行机制有何不同?定义内联函数有何意义、有何要求?答:普通函数调用要经历保护现场、参数传递、跳转、返回等过程;内联函数在编译时把函数体代码直接嵌入每个调用处,省去调用开销,本质是“以空间换时间”。inline只是对编译器的建议,编译器可以忽略;内联函数只适合功能简单、代码短小的函数,含switch、复杂if嵌套、循环或递归的函数即使写了inline也会被当作普通函数处理。3.2.3全局变量与全局静态变量有何区别?为什么提倡尽量使用局部变量?答:用static修饰的全局变量只在定义它的文件内可见,其他文件不可访问;非静态全局变量可被其他程序文件访问,但使用前需用extern说明。提倡局部变量是因为局部变量作用域局限在函数或块内,不同块可以使用同名变量而不冲突,减少了意外的相互影响,也便于调试和维护。3.2.4函数重载的作用是什么?满足什么条件才能成为重载函数?调用时怎样匹配?答:作用是用同一个函数名定义一组功能相似但参数类型或个数不同的函数,提高可读性、减少命名负担。条件是参数表必须不同(类型、个数或顺序不同),仅返回值不同不能构成重载。匹配顺序:先找严格匹配的函数;再找经内部类型转换后可匹配的函数;最后通过用户定义的转换寻求匹配(可能产生二义性)。3.2.5多文件结构的程序如何管理与运行?有什么好处?答:通过工程(项目)文件管理:头文件.h中放类型定义、外部声明、常量与内联函数,实现代码分散在若干.cpp中;各源文件分别编译生成.obj,再由连接器连接成可执行文件。好处:改一个文件只需重编译该文件,避免全量重编译;按功能划分便于设计、调试与维护;相同功能的函数成组存放,便于其他程序复用。3.2.6宏定义与const常量定义效果一样,二者完全相同吗?答:不同。宏在预处理阶段做简单的字符串替换,不为标识符分配内存、不做类型检查,替换出错也不报语法错误;const定义在编译阶段处理,要按类型分配存储单元并做类型检查,类型不兼容会报错,且const常量有作用域和类型,可参与重载解析。三、编程题3.3设计函数,把小写英文字符变为对应的大写字符。cpp

#include<iostream>

usingnamespacestd;

charcapitalize(charch){

if(ch>='a'&&ch<='z')returnch-'a'+'A';

elsereturnch;

}

intmain(){

inti=0;

charcp[30];

cout<<"请输入包含小写字母的句子:"<<endl;

cin.getline(cp,30);

while(cp[i]!='\0')cout<<capitalize(cp[i++]);

cout<<endl;

return0;

}思路:小写字母的ASCII码比对应大写字母大32,写作ch=ch-'a'+'A'比写32更清楚。3.4设计两个函数,分别求两个数的最大公约数和最小公倍数。cpp

#include<iostream>

usingnamespacestd;

intgcd(inta,intb){//辗转相除法

intr;

while(b!=0){r=a%b;a=b;b=r;}

returna;

}

intlcm(inta,intb){

returna*b/gcd(a,b);

}

intmain(){

inta,b;

cout<<"输入两个正整数:"<<endl;

cin>>a>>b;

cout<<"最大公约数="<<gcd(a,b)<<endl;

cout<<"最小公倍数="<<lcm(a,b)<<endl;

return0;

}思路:教材答案用穷举法(从大到小找第一个公约数、从小到大找第一个公倍数)也能通过;辗转相除法更快。最小公倍数用a*b/gcd(a,b),为避免a*b溢出可写成a/gcd(a,b)*b。第四章类与对象一、填空题4.1.1引入类定义的关键字是(1)。类的成员函数通常指定为(2),数据成员通常指定为(3)。指定为(4)的成员可以在类对象所在域的任何位置访问。通常用类的(5)成员表示属性,用(6)成员表示操作。答:(1)class;(2)public(公有);(3)private(私有);(4)public;(5)数据;(6)函数。4.1.2类的访问限定符包括(1)、(2)和(3)。私有数据通常由(4)函数来访问(读和写),这些函数统称为(5)。答:(1)public;(2)private;(3)protected;(4)公有的成员;(5)类的接口。4.1.3逻辑上同一类的每个对象都有(1)代码区以存放成员函数,物理上通常只有(2)代码区;只有在(3)定义并(4)的函数,以及加了关键字(5)的函数例外。答:(1)独立的;(2)共用的;(3)类内;(4)不含循环等复杂结构;(5)inline。4.1.4C++支持三种域:(1)、(2)、(3)。函数域被包括在(4)中,全局域被包括在(5)中。using指示符以using开头,后面是关键字(6),最后是(7),表示以后在该名字空间中所有成员都(8);不使用using指示符时要用::,称为(9)运算符。答:(1)局部域;(2)名字空间域;(3)类域;(4)局部域;(5)名字空间域;(6)namespace;(7)名字空间名;(8)可以直接使用;(9)域运算符(作用域解析运算符)。4.1.5引用通常用作函数的(1)和(2)。对数组只能引用(3),不能引用(4)。答:(1)参数;(2)返回值;(3)数组元素;(4)数组名本身。4.1.6构造函数的任务是(1),构造函数没有(2)。类中可以有(3)个构造函数,它们由(4)区分。若类中未给出构造函数,编译器会(5)。复制构造函数的参数是(6),未给出时系统自动提供(7),其中每个成员(8)。答:(1)初始化数据成员;(2)函数返回类型(连void也没有);(3)多;(4)不同的参数表(重载);(5)自动生成一个默认构造函数;(6)同一类对象的引用;(7)默认的复制构造函数(默认按成员语义);(8)被依次复制(浅复制)。4.1.7一个类有(1)个析构函数。(2)时系统自动调用析构函数。答:(1)一;(2)对象生存期结束(对象注销、被销毁)时。4.1.8运算符重载时,函数名由(1)构成。用成员函数重载双目运算符时,左操作数是(2),右操作数是(3)。答:(1)关键字operator加该运算符;(2)该对象本身(*this);(3)函数的参数。4.1.9面向过程的程序模型可描述为(1),面向对象的程序模型可描述为(2)。答:(1)程序=算法+数据结构,数据与数据处理相分离;(2)程序=对象+对象+…+对象+消息,对象=算法+数据结构。二、简答题4.2.1什么是面向对象程序设计的封装性?对象是一个封装体,把属性和操作封装在一起,成为独立的基本单元,实现了数据与数据处理相结合;封装还体现在可限制成员访问权限,把属性“隐藏”在对象内部,对外只呈现必要的接口。封装提高了对象的独立性和数据的可靠性,有利于调试与维护,也使类的升级扩展不影响使用者。4.2.2C++编译器怎样解析标识符?分两步:第一步查找声明中用到的标识符,特别是成员函数声明里的参数类型;第二步再解析成员函数体内的标识符。4.2.3为什么说类与对象的概念是客观世界的反映?客观事物都有属性和行为,具有相同属性和行为的事物可归为一类;类是对某一类事物共有静态特征(属性)和动态特征(行为)的抽象描述,对象是这种描述的具体实现,所以说二者是客观世界的反映。4.2.4什么叫类域?为什么说类域是抽象的?类域是类体所包括的范围,每个类定义引入一个独立的类域,其中说明的标识符只在该类域内有效。类只是说明(有数据、函数、类型定义),并非实体,不分配内存也不能运行,所以类域是抽象的。4.2.5引用作函数参数为什么能实现实参间的数据交换?为什么实参不能是引用?为什么返回引用的函数可作左值?引用是关联变量的别名,二者占同一存储单元,函数内交换两个引用参数就是交换实参。若形参是引用,调用时需取实参地址,而实参若本身是引用(已是地址)再取引用会出错,故不能再传引用(应传普通变量或指针)。函数返回引用等于返回关联变量本身,因此该函数调用可作为左值参与赋值。4.2.6什么是缺省构造函数?最多可以有多少个?类中不显式定义构造函数时编译器自动生成的、不做具体初始化的构造函数。无参的构造函数,或所有参数都有默认值的构造函数,都算缺省构造函数。缺省构造函数只能有一个。4.2.7复制构造函数用于哪三方面?(1)用一个对象初始化同类另一个对象;(2)函数形参是类对象时,调用处的形实结合;(3)函数返回值为类对象时,返回调用者的过程。4.2.8写出含对象成员的类的构造函数格式并说明。格式:类名::构造函数名(参数总表):对象成员1(参数表1),对象成员2(参数表2),…{…}。冒号后用逗号隔开的是要初始化的对象成员,括号内是传给该成员所属构造函数的实参,实参通常取自冒号前的参数总表但没有类型名;对象成员必须先于本类成员初始化,且只能这样初始化而不能在函数体内赋值。4.2.9未重载的赋值运算符“=”对类对象怎样工作?为什么可以连续赋值?对同类对象,“=”执行默认的按成员复制(浅复制)。默认赋值运算符返回对象的引用,因此可以连写a=b=c。若类中有指针成员并动态分配了资源,必须自己重载“=”做深复制,否则会出现两个对象共享同一块内存的重复释放问题。4.2.10为什么在友元函数内访问对象成员必须用“对象名.成员名”?友元函数不是类的成员函数,没有this指针,不受类域约束,访问对象成员只能像普通函数一样用对象名加点运算符。4.2.11重载复数加法时若声明为friendComplexoperator+(Complex&c1,Complex&c2),为什么不能用于“实数+复数”?怎样改进?因为引用参数只能绑定同类型对象(或可隐式转换成该类型的对象),而“实数+复数”需要先把实参转换成Complex的临时对象,非const引用不能绑定临时对象,编译失败。改为constComplex&后,转换产生的临时对象可以绑定到const引用,即可支持“实数+复数”。4.2.12类的静态数据成员与函数中的静态变量有何异同?相同之处:都存放在全局数据区,不随函数调用/对象创建销毁而重新分配,只保留一份。不同之处:类的静态成员属于类、为该类所有对象共享,可用类名访问,需在类外定义;函数中的静态变量只在函数内可见,第一次进入函数时初始化。4.2.13C++中结构、联合与类有何异同?结构(struct)与类几乎完全一样,区别仅在于默认访问权限:struct成员默认public,class默认private。联合(union)的成员共用同一段存储,各成员起始地址相同,任一时刻只能保存一个成员的值,其大小等于最长成员;而结构/类的各成员各有独立的存储空间。4.2.14由对象组成的程序怎样建立对象间的联系?面向对象程序的组织与面向过程有什么不同?通过消息传递机制:一个对象向其他对象发消息请求服务,也可响应别人发来的消息,从而协作完成功能。面向过程的程序是模块化、分层结构、层间为调用关系;面向对象程序由若干封装的对象组成,对象之间是相互请求与协作的关系。4.2.15简述Windows下应用程序的运行方式。Windows支持多任务、多窗口,运行机制是“消息传递与事件驱动”。键盘、鼠标操作、系统动作、程序自身动作都会产生事件,系统为每个事件生成对应消息放入消息队列,由应用程序的消息循环取出并分发给相应窗口函数处理;处理是分层的,处理不了的交给默认窗口函数。4.2.16类的成员函数什么情况下应定义为私有?目的是什么?除构造函数、析构函数以及对外提供的接口函数外,其余成员函数一般应设为私有。这些往往是实现细节中最复杂、最关键的部分,隐藏起来可保证接口稳定、内部可改,便于类的升级扩展(接口不变则使用者程序无需修改),也避免外部误用破坏对象状态。三、编程题4.3构造日期时间类TimeDate:数据成员为年、月、日、时、分、秒(年、月用枚举类型),成员函数完成设置与输出,并完成测试(分别用成员函数和普通函数访问)。cpp

#include<iostream>

usingnamespacestd;

enumYR{Y2000,Y2001,Y2002,Y2003,Y2004,Y2005};

enumMT{Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec};

classTimeDate{

private:

YRyear;MTmonth;

intdate,hh,mm,ss;

public:

TimeDate(){year=Y2000;month=Jan;date=1;hh=0;mm=0;ss=0;}

TimeDate(YRy,MTm,intd){year=y;month=m;date=d;hh=12;mm=30;ss=0;}

voidgetDate(YR&y,MT&m,int&d){y=year;m=month;d=date

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论