《CC 程序设计》(黄襄念)附录与习题 附录A-D_第1页
《CC 程序设计》(黄襄念)附录与习题 附录A-D_第2页
《CC 程序设计》(黄襄念)附录与习题 附录A-D_第3页
《CC 程序设计》(黄襄念)附录与习题 附录A-D_第4页
《CC 程序设计》(黄襄念)附录与习题 附录A-D_第5页
已阅读5页,还剩22页未读 继续免费阅读

下载本文档

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

文档简介

附录A 调试方法可以分为两大类,即语法错误和逻辑错误。语法错误(OJ文件(XE文件EXEdoue数据给ntdoue转换到n逻辑错误EXE程序,但运行结果不正确。造成调试是程序员最基本的技能,附录A介绍两种逻辑错误的常用调试手段——程序断点和断言,它们有助于快速定位,进而改正逻辑错误。一、调试环境VC+IDEA.1Debug”(或称开发版或DebugDebug(从DBXEeeaseXEDebu默认EXE提交给用户。二、断点调试断点eakont暂停,以便观察程序运行时的情况,诸如变量值、数组元素值等,它是最基本、最常用的调试手段。断点包括位置断点、数据断点、函数断点、消息断点等,断点可以设置多个。1.位置断点(简称断点A.1A.2F9F9取消该行断点。在该行左边灰色窄条内单击即可设置该行断点,再次单击取消该断点。A.1A.4。A-1编程实验:设置调试环境与断点。图A.1Debug环境及断点(3个) 图A.2“调试”菜单项5图A.“l5不调试A.1最后一个断点处(show函数)暂停,根据需要有两种选择:showA.show函数10”表示不进入函数而运行到下一条语句(15行。ht5。14arr各个元素值。局部变量或自动窗口A.3数据提示A.4arr出现数据提示,鼠标移开后消失。若按下最右端小图钉按钮,则为永久性提示(还可以给它写注释。图A.3局部变量窗口 图A.4数据提示显示数组arr元素以上断点无条件暂停程序的执行,称为无条件断点(简称断点。可以为断点设置一个true时触发该断点,称为条件断点false时,无视该断点。A-2编程实验:设置条件断点。A.5112个小图标,再把鼠标...A.6=4|num45(图A.7:i2i4条件;sum6sm4条件,故触发断点暂停程序。图A.第1行5A.,i为(04、sum为1(12345。图A.6编辑条件表达式2.数据断点

图A.5设置条件断点 图A.7观察条件断点结果A-3编程练习:设置数据断点。程序代码如下:7 7 cout<<test<<endl;8 }9 void func2(intb)10{testb; //testcout<<test<<endl;//test//testtest变化double test=0;void func1(inta)5 {6 test=a*10;#include<iostream>usingnamespacestd;13}14int main()15{16cout<<sizeof(int*)<<endl;//x86输出4,x64输出817cout<<sizeof(double*)<<endl;//x86输出4,x64输出818int a=1,b=15;19func1a); //1020func2b); //2521int data[100];22for(inti=0;i<100;i++)23data[i]=i;24system("pause");25}10或1不能按55,main函数(15行。A.8。图A.8新建数据断点数据断点通过监视变量的内存地址实现,故需输入变量地址且指明地址的字节数(默认4位程序(es&es,见图A.9。由于est是doue8……图A.9设置数据断点时报错double64(8字节32324doue64A.1n或8664A.10所示。图A.10设置单个项目平台64程序10或1...A.11。图A.11设置数据断点5test的地方。unc1和unc2estest>0每F5继续运行func17func2函数的12行,暂停时告诉你此处已完成修改,实现了对修改处的快速定位。3.函数断点按“lBA.12。断点条件是函数名,调用指定函数时(func2)触发函数断点,程序停留在该函数入口处。还可以结合“条件”选项,设置触发函数断点的更多条件。图A.12设置函数断点三、监视窗口A.3A.A.3。图A.13监视窗口内容 图A.14设置快速监视...ht9A-3testtest添加到监视窗口,见图A.13。dataShift+F9”或鼠标右鍵弹出菜单A.14)daa50,data50A.13是24行的情况。data[50]+test、data+10(指针)等。另外,它可以显示大数组的某个元素,而不必显示整个数组。断言(Assert)也是一种调试手段,帮助我们发现和定位程序的逻辑错误。断言可分为(言发生在程序编译时,也称编译时断言,静态断言由C++11新标准提供。一、动态断言头文件<cassert>提供动态断言的宏函数,如下:void assert(int expression);expression(非零expressionexpression值为假时断言失败abort函数非正常终止程序,输出expression、源程序名称和行号,便于找到问题所在。例A-4编程实验:使用断言。程序代码及程序输出结果(图A.15)如下:}}图A.15例A-4的输出结果system("pause");//断言失败func(c);//断言(保证)i不为空//assert,须在#include<cassert>之前//assert头文件#include<iostream>//#defineNDEBUG#include<cassert>usingnamespacestd;void func(int*i){cout<<i<<endl;assert(i!=NULL);}int main(){inta=10;int*b=NULL;int*c=NULL;b=&a;func(b);12345678910111213141516171819思考与练习:(1)不注释第2行,结果会如何?程序发行版应该怎么做?(2)不注释第2行,且交换第2行和第3行,结果会如何?断言是一种调试手段,用于发现错误而不是错误处理,不能代替错误处理代码。A-5编程实验:注意避免断言的副作用。程序代码如下:#include#include<iostream>//#defineNDEBUG#include<cassert>usingnamespacestd;int*func(double&a,int&b,intc)}}//正常输出:10*p=func(a,b,c);for(inti=0; i<b; i++){p[i]=i+10;cout<<p[i]<<endl;}delete[]p;system("pause");//断言为真//断言为真b=1;c=-2;intintintmain()double a=10;}int{131415161718192021222324252627//断言分母不能为0//断言元素个数不能为负//断言有副作用assert(c!=0);assert(b>0);//assert(b++>0);double r=a/c;int*pt=new int[b];returnpt;//断言常用于检查函数的参数6 {78910111278assertc0&&b09b++(2行思考与练习:(1)注释第8行且不注释第9行且同时注释和不注释第2行,输出有何变化?(2)分别将第17、18行改为b=-1、c=0,观察断言失败情况。(3)注释第8行且第17行改为b=-1,运行程序出现什么情况?二、静态断言C++11static_assert,不需要其他头文件。用法格式如下:static_assert(constexpr,message);constexpr是常量表达式,如果其值为真表示断言成功,不做任何事情;如果其值为假(,essaeA-6(如下:#include#include<iostream>usingnamespacestd;3 template<classT1,classT2void arrCopy(T1&dest,T2&src //函数模板4 {static_assert(sizeof(dest)>=sizeof(src),"内存dest<src"); //静态断言memcpy(&dest,&src,sizeof(src));7 };8 void func(constint&m //m可引用不同的常量9{//static_assert(m>=0m<0 //静态断言,ERROR10cout<<"m:"<<m<<endl;11}12intmain()13{int a[4]={};14int b[3]={10,20,30};15cout<<a<<endl;16cout<<&a<<endl;17func10; //m引用-1018func20; //m2019arrCopy(a,b);20const intn=4;21static_assert(n<=4,"n4 //静态断言22for(inti=0;i<n;i++) cout<<a[i]<<endl;23systempause" A.16例A-6的输出结果24}6memcpysrcdest5行用静态断言保destT2inta[4]和intb[3],故知道它们的内存大小为常量。9m(引用不同常量(要求思考与练习:(1)将第14行b[3]改为b[5],其他不变,有什么编译错误?(2)将第20行常量n值改为5,其他不变,有什么编译错误?(3)如何将第9行改为动态断言?附录B 异常处理一、必要性检测即处理只检测不处理main)还不处理,则程序停止运行。其优点在于能专心设计和实现函数功能而不处理异常,将异常上移到某一层函数去专门处理。如此分工合理、各司其职,这就是本附录的异常处理方式。二、try-catch结构下面,通过一个例子来学习try-catch结构。B-1try-catch结构处理异常。程序代码如下:try try //监测异常{ //大括号不能省略q=divide(ndiv); //div=0//constchar*类型异常并不处理#include<iostream>#include<string>usingnamespacestd;float divide(int num,int div)5 {if(div0) throw异常:被零除\n";return float(num)/div;8 }9 int main()10{int n,div; float q=0;cout输入两个数:";cin>>n>>div;}}//异常处理代码//逻辑错//语法错,try-catch之间不能有其他语句//捕捉并处理constchar*异常}//cout<<"商:"<<q<<endl;catch(constchar*exception){ //大括号不能省略coutexception;}//cout<<"商:"<<q<<endl;system("pause");//无异常时输出“商”cout<<"商:"<<q<<endl;17181920212223242526第6行:throw抛出constchar*类型异常,异常类型可以是基本类型或自定义类型。第14~18行:把可能产生异常的代码段放在try大括号中,大括号不能省略。20~23行:catch捕捉到指定类型异常时,立即跳转到该处并处理异常。19行:语法错。trycatch结构为一个整体,之间不能插入其他语句。240,则商没有意义。思考与练习:1)0正常)和等于0异常(2)第20行改为catch(intexception),分母为0时会发生什么?有何结论?三、异常传递throw抛出异常时,程序立即从throw函数跳出,沿函数调用链逐级上报,直到有函数捕获异常且不再throw为止。如果均未捕获并处理异常,则程序停止运行。例B-2编程实验:异常传递。B.1f3doubleaf3、f2、f1catchfloat、intchardouble类型而不处理,异常继续向上mainmain捕获并处理。main()……catch(double)main()……catch(double)f1()……catch(char)f2()……catch(int)f3()……throw(a)catch(float)a a a图B.1异常沿函数调用链传递程序代码及输出结果(图B.2)如下:#include#include<iostream>usingnamespacestd;void f2();445678910111213141516171819202122232425262728293031323334353637383940voidvoid{f3()throw(double);f1()//f3try{ f2();}catch(char)//f2异常{ coutf1char异常endl;cout<<"f1继续"<<endl;}}void{f2()try{f3();}catch(int)//f3异常coutf2int异常endl;cout<<"f2继续"<<endl;}void f3()throw(double){doublea=100;//float a=100;//throw(a);try{throw(a);}catch(float)//异常类型//double异常//捕捉float异常{cout<<"f3捕捉float异常\n";}cout<<"f3继续"<<endl;}int{main()try{ f1(); }catch(doubleb)//catch(float b){//监测f1()异常//double异常//捕捉float异常coutmaindouble异常endl;cout<<"异常表达式值:"<<b<<endl;}cout<<"main继续"<<endl;system("pause");图B.2例B-2的输出结果}419double)throwhow()(noecept(1)将第4、19行throw(double)改为throw()或noexcept,有何编译警告?(2)第4、19行:注释throw声明部分,有警告和错误吗?(3)注释第21行且不注释第22行,结果会如何?(4)注释第32行且不注释第33行,结果会如何?有何结论?(5)注释第24~27行且不注释第23行,结果会如何?四、专门处理将功能函数抛出的异常逐级上报到某一层去专门处理,这样层次更清楚、分工更合理。B-3B-2H1H2进行专门处理。程序代码及输出结果(图B.3)如下:B.3B-3的输出结果}catch(...){cout<<"捕获其他异常\n";}}void H2 //异常处理函数{try{H1();}catch(int*p)coutH2int*异常:*pendl}int main(){H2; //H2H1//进行某些处理//再次抛出异常(p可省略)*p+=5;throwp;voidf3(){inta=10,*b=&a,&c=a;//throwc;throwb; //int*类型异常}void H1 异常处理函数{try{f1();}//catch(...){cout<<"其他异常\n";}catch(int){cout<<"捕获int异常"<<endl;}catch(int*p){coutH1int*异常:*pendl;//调用关系:f1→f2→f3f2();f3();f1(){f2();}f2(){f3();}voidvoidvoid#include<iostream>usingnamespacestd;12345678910111213141516171819202122232425262728293031323334coutcoutmain继续endl;system("pause");37}第24行:catch(...)捕获未指定的其他各类异常。思考与练习:(1)将catch(...)提前,即注释第24行且不注释第16行,有何问题与结论?(2)注释第11行且不注释第10行,结果会如何并解释之?五、释放内存需考虑在发生异常时,如何正确释放动态分配的内存;否则,可能产生内存泄漏。B-4new(B.4)如下:}}}cout<<endl; system("pause");B.4B-4的输出结果cout<<"异常释放"<<endl;for(inti=0;i<3i++) //验证释放和不释放cout<<p[i] //的数据变化情况//New函数}int main(){try{New();}catch(int*p){//delete[]p;cout<<"\n正常释放"<<endl;delete[]p;//int*catch处//103、120、123实验//元素为0int*p=new int[3];for(inti=0;i<3;i++){cin>>p[i];if(p[i]==0){cout<<"异常"<<endl;throw p;}cout<<p[i]<<"";}5678910111213141516171819202122232425262728#include<iostream>usingnamespacestd;void Newvoid //可能抛出异常4 {12catch16delete[p得不到执行,new23catch子句中释放(本例已注释。思考与练习:1)103和12012正常2)231六、异常析构例B-5编程实验:异常时调用析构函数。程序代码及输出结果(图B.5)如下:}}cout<<"main继续"<<endl;system("pause");}{coutIDidendl}catch(intid)B-5的输出结果B.5//S1S2//异常时得不到执行S1.data();S2.data();};int main(){//Student S180非法//Student S290合法try{Student S180非法);Student S290合法}//IDint异常if(ID<90) throwID;#include<iostream>#include<string>usingnamespacestd;class Student{int ID;string name;public:Student(intn,conststring&name):ID(n),name(name){cout<<"构造: ID="<<ID<<endl;}virtual~Student(){cout<<"析构: ID="<<ID<<endl;}void data(void) throw(int){cout<<"data():"<<ID<<","<<name<<endl;cout<<"---------------\n";123456789101112131415161718192021222324252627282930313233第17行:检查ID合法性。ID<90为非法,抛出异常。第25、26行:创建对象S1和S2,生命期限于try{}花括号内。27try{}子句,此时释放(析构)S1S2;catch子句执行(30行。思考与练习:(1)注释第25、26行且不注释第22、23行,结果有什么变化?解释之。2)继续1七、抛出对象可以将异常的相关信息封装到类中,用throw抛出它的对象。例B-6编程实验:抛出无信息的异常对象。程序代码及输出结果(图B.6)如下:#include#include<iostream>usingnamespacestd;class intRange4 {int input,lower,upper;public:class tooLow{};class tooHigh{};//检查整数范围(抛出异常对象)//inputlowerupper//嵌套定义类(空类)//嵌套定义类(空类)9 intRange(intlow,inthigh):lower(low),upper(high){}101112131415161718192021222324252627282930int getInput(void){cin>>input;if(input<lower)if(input>upper)returninput;}//输入检查,抛出异常throwthrowtooLow();tooHigh();//抛出无名对象//抛出无名对象};int main(){intRange range(5,9);int cout<<"输入整数(5~9):";try{userValue=range.getInput();cout<<userValue<<"有效\n";}catch(intRange::tooLow&){cout<<"数值太小\n";}catch(intRange::tooHigh&){cout<<"数值太大\n";}cout<<"main继续...\n";B.6B-6的输出结果31 31 system("pause");32}B-7(B.7)如下:cout<<obj.value<<":cout<<obj.value<<":太小\n";cout<<obj.value<<":太大\n";//捕获同类异常B.7B-7的输出结果};int main(){intRange range(5,9);int cout<<"输入整数(5~9):";try{range.getInput();cout有效\n";}catch(intRange::OutOfRange&obj){if(obj.value<range.getlower())if(obj.value>range.getupper())}}//抛出其无名对象if(input<lower||input>upper)throw OutOfRange(input);returninput;//输入检查,抛出异常int getInput(void){cin>>input;};int getlower(void){returnlower;}int getupper(void){returnupper;}intRange(intlow,inthigh):lower(low),upper(high){}//异常数据OutOfRange(inti):value(i){}//嵌套类(抛出其对象)class OutOfRange{public:int value;//输入整数及上限、下限7891011121314151617181920212223242526272829303132333435363738//检查整数范围(抛出异常对象)#include<iostream>usingnamespacestd;class intRange4 {int input,lower,upper;public:coutmaincoutmain继续...\n";system("pause");41}附录C 命名空间。为避免命名冲突,把命名作用域naespac或称为名字空间C(全局C++补充了类作用域和命名空间作用域。不同作用域中的成员可以同名,彼此独立、互不干扰。一、声明与使用例C-1编程实验:声明命名空间、访问空间内成员的三种方式。程序代码及输出结果(图C.1)如下:////using声明空间内成员cout<<"------------\n";using ns2::m;C.1C-1的输出结果//ns1::m=1;//ns1::fun();//②命名空间域名限定m=10;fun();ns2::fun();ns2::m=20;ns2::fun();//m?void FUNC(void){cout<<"m="<<m<<endl;}int main(){//①using声明整个命名空间//ERRORmfunstd;ns1;ns2;namespacenamespacenamespace};//usingusing//usingfun(void){ cout<<"ns2::m="<<m<<endl; }void//ns2};//using namespace ns1;namespace ns2{int m;void fun(void){cout<<"ns1::m="<<m<<endl;}std; //系统命名空间ns1; //ERROR:ns1还没声明//声明命名空间ns1#include<iostream>using namespace//using namespacenamespace ns1{int m;123456789101112131415161718192021222324252627 m27 m=30; //ns2::m28 fun(); //ns1::fun();29 ns2::fun();30 cout<<"------------\n";FUNC();//using ns1::m;system("pause");34}第2、14行:using指令在全局范围(文件作用域)声明整个命名空间。第22行:用命名空间域名限定成员,一次有效。26行:using声明命名空间成员(main函数作用域。某作用域中using声明后,在该作用域中一直有效,不能重复声明。思考与练习:(1)注释第2行且不注释第13行,结果会如何?(2)不注释第3行且注释第14行,结果会如何?(3)注释第14行且不注释第8行,结果会如何?(4)不注释第15行,结果会如何?(5)不注释第32行,结果会如何?例C-2编程实验:名字相同的命名空间是同一个命名空间。程序代码如下:}}system("pause");//输出func()//输出func():10}int main(){NS::func();NS::func(10);void funcintmcoutfunc():mendl;}//重载函数//ERROER:重定义//int a;//重载函数#include<iostream>usingnamespacestd;namespaceNS{int a;void func(void){cout<<"func()"<<endl;}}namespaceNS{123456789101112131415161718二、嵌套声明与别名命名空间可以嵌套声明,还可以取别名。例C-3编程实验:命名空间嵌套与别名。程序代码及输出结果(图C.2)如下:}}C.2C-3的输出结果cout<<"ns2::m="<<ns1::ns2::m<<endl;//cout<<"ns2::m="<<n2::m<<endl;//命名空间别名//命名空间别名}void FUN(void);int main(){namespace n1=ns1;namespace n2=ns1::ns2;n1::m=10;n2::m=20;n2::fun2();FUN();system("pause");}void FUN(void){}//ns1成员//ns2void fun2(void){fun1();}{ cout<<"ns1::m="<<m<<endl; }//嵌套子空间//父空间#include<iostream>usingnamespacestd;namespacens1{int m;void fun1(void)namespace ns2{int m;12345678910111213141516171819202122232425262728声明命名空间别名,可以缩短命名空间的名字。思考与练习:(1)注释第26行且不注释第27行,结果会如何?(2)不用命名空间别名,该如何修改程序?三、内联命名空间C++11例C-4编程实验:内联子空间与程序版本控制。程序代码及输出结果如下:ParentParent;//m=20//m=10}int main(){using namespacefun();old_ns::fun();system("pause");}}void fun(void){cout<<"m="<<m<<endl;}//新值m=20;namespace new_ns //新版取代旧版(Parent成员)inline{int10111213141516171819202122fun(void){cout<<"m="<<m<<endl;}void//旧值int m=10;789 }#include<iostream>usingnamespacestd;namespace Parent4 {5 namespace old_ns //旧版6 {C-5C-4内联空间。程序代码及输出结果如下://usingnamespace//usingnamespacenew_ns;fun; //m=20voidfun(void){cout<<"m="<<m<<endl;}}int main(){//非内联空间//内联空间//namespace new_nsinline namespace new_ns{int m=20;#include<iostream>usingnamespacestd;namespaceold_ns{int m=10;voidfun(void){cout<<"m="<<m<<endl;}}123456789101112131415old_ns::old_ns::fun //m=10system("pause");20}若不用内联命名空间,则注释第9行且不注释第8行和第16行。C-6编程实验:内联命名空间应用例。1.02.0版,新类库可以自由使用,旧类库也可继续使用。实现方式:用命名空间重新封装类(原类库没用命名空间封装。程序代码及输出结果(图C.3)如下:#include#include<iostream>usingnamespacestd;namespace ver1 //v1.04 {classA{ int a1;public:891011121314151617181920212223242526272829303132A(inta1):a1(a1){}void fun(){cout<<"a1="<<a1<<endl;}};classB{ int b1;public:B(intb1):b1(b1){}void fun(){cout<<"b1="<<b1<<endl;}};}inline namespace{classA{ int a1,a2;public:A(inta1,intvoid fun()ver2//v2.0//a2a2):a1(a1),a2(a2){}{cout<<"a1="<<a1<<",a2="<<a2<<endl;}};classB{ int b1,b2;public://b2B(intb1,intb2):b1(b1),b2(b2){}voidfun(){cout<<"b1="<<b1<<",b2="<<b2<<endl;}3334333435363738394041424344454647484950515253545556};}void test1(){//1.0版cout<<"=====1.0版=====\n";ver1::Aa1(1);a1.fun();ver1::B b1(2);b1.fun();//旧版可用,需加域名限定//旧版可用,需加域名限定}void test2 //2.0版{cout<<"=====2.0版=====\n";Aa2(10,100);a2.fun();B b2(20,200);b2.fun();//A//B}int main(){test1(); //1.0test2(); //2.0system("pause");}图C.3例C-6的输出结果四、匿名命名空间匿名命名空间即没名字的命名空间,也称无名命名空间。C++提倡用它取代static全局变量和函数,限制空间中成员的所在域,即仅在本单元文件使用,其他单元文件不能用。例C-7编程实验:无名命名空间的使用。程序代码如下:1 1 //=============“1.cpp”==============#include<iostream>classA{ public:void member(){std::cout1.cppstd::endl;}6 };7 namespace //无名(匿名)8 {void test //statictest{Aa;a.member();12 }13}}}system("pause");//链接错:无法解析外部命令(extern)test();//=============“源2.cpp”==============#include<iostream>usingnamespacestd;externvoidtest();int main(){//test/*static void test(){Aa;a.member();}*/14151617181920212223242526例C-8编程实验:不同单元文件的同名命名空间属于同一个命名空间。程序代码如下:////输出:OK!system("pause");}//1.cppNS是同一个test(void); }namespace NS{ extern voidint main(){ NS::test();}//=============“源2.cpp”==============#include<iostream>//NS//无名子空间(内联或不内联)//inline namespace//{void test(void){Aa;a.member();}//}//=============“源1.cpp”==============#include<iostream>namespace NS{classA{ public:void member(){std::cout<<"OK!"<<std::endl;}};12345678910111213141516171819202122思考与练习:(1)第3行和19行:将两个命名空间改为不同的名字,结果会如何?(2)不注释第9、10、

温馨提示

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

评论

0/150

提交评论