您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > 高质量C++编程学习笔记
普通程序员应该做到:(1)知错就改;(2)经常温故而知新;(3)坚持学习,天天向上。C++/C程序通常分为两个文件:1.Declaration保存程序的声明(.h)2.Implementation保存程序的实现(.c)头文件的作用:通过头文件来调用库功能;加强类型安全检查。头文件一般保存于include目录,定义文件按保存于source目录。版式:一行代码值做一件事情。尽可能在定义变量的同时初始化该变量。代码行最大长度宜控制在70至80字符以内。类的版式:以行为为中心,重点关注是类应该提供什么样的接口(服务),public类型的函数写在前面,private类型的数据写在后面。命名规则:匈牙利法:在变量和函数名中加入前缀以增进人们对程序的理解。(ppch:指向字符指针的指针)Windows应用程序的标示符通常采用大小写混排的方式,如AddChildUnix应用程序的标示符通常采用小写加下划线的方式,如add_child.表达式与基本语句(别用隐含错误的方式写代码)不可将布尔变量直接与TRUE,FALSE或者1,0进行比较,不同编译器的bool值是不同的不可将浮点变量用“==”或“!=”与任何数字比较,因为有精度限制。应当将指针变量用“==”或“!=”与NULL比较。循环语句的效率(降低循环的复杂性)多重循环中,如有可能,应当将最长的循环放在最内层。如果循环体内存在逻辑判断,并且循环次数很大,最好将逻辑判断移到循环体外面。Switch语句存在的理由:多分支选择语句,虽然可以用嵌套if语句来实现多分支选择,但那样程序冗长难读。Switch语句中每个case语句不要忘了加break。不要忘记default分支,即使不需要,也要保留default:break;常量:值在运行期间恒定不变。C语言中用#define来定义常量(称为宏常量),c++中除了#define外,还可以用const来定义常量(const常量)。Const与#define比较:const优点:1.const常量有数据类型,宏常量没有数据类型。2.有些集成化的调试工具可以对const常量进行调试,但不能对宏常量调试●在c++中只使用const常量而不使用宏常量。需要对外公开的常量放在头文件中,不需要对外公开的常量放在定义文件的头部。为便于管理,可以把同模块的常量集中存放在一个公共的头文件中。类中的常量:只能用枚举常量来实现!▲Const数据成员只在某个对象生存期内是常量,而对整个类而言却是可变的,因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。▲不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道值是什么。▲Const数据成员的初始化,只能在类构造函数的初始化表中实现。函数设计函数接口的两个要素是参数和返回值:C语言中,函数的参数和返回值的传递方式有两种;值传递和指针传递,c++多了引用传递。引用传递:性质像指针传递,而使用方式却像值传递。参数的规则:参数的书写要完整,如果函数没有参数,用void填充。参数命名要恰当,顺序要合理。(目的参数放在前面,源参数放在后面)。如果参数是指针,且仅作输入用,应在类型前加const,以防止该指针在函数体外被修改。如果输入参数以值传递的方式传递对象,宜改用“const&”,省去零时对象的构造和析构过程,提高效率。参数个数尽量控制在5个以内。尽量不要使用类型和数目不确定的参数。返回值的规则:不要省略返回值的类型。函数名字和返回者类型在语义上不可冲突。(getchar其实int类型,而不是char类型)不要将正常值和错误标志混在一起返回,正常值用输出参数获得,错误标志用return语句返回。有时候函数原本不需要返回值,但为了增加灵活性,可以附加返回值。函数内部实现的规则:(在函数体的入口处和出口处把关)在函数体的入口处,对参数的有效性进行检查,从分理解并正确使用“断言”(assert)●在函数体的出口处,对return语句的正确性和效率进行检查。1.return语句不可返回指向“栈内存”的指针或者引用,因为该内存在函数体结束时被自动销毁。2.搞清楚返回的究竟是值,指针还是引用。3.如果函数返回值是一个对象,要考虑return语句的效率。4.函数体功能要单一,不要设计多用途的函数;函数体的规模要小,尽量控制在50行代码以内;尽量避免函数带有“记忆”功能。Debug版本release版本的区别:debug版本用于内部调试,release版本发型给用户使用。断言assert是仅在debug版本起作用的宏,用于检查“不应该”发生的情况。使用断言捕捉不应该发生的非法情况;在函数的入口处,使用断言检查参数的有效性。引用与指针的比较引用是c++中的概念。1.引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。2.不能有NULL引用,引用必须与合法的存储单元关联(指针则可以使NULL)。3.一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。4.引用的主要功能是传递函数的参数和返回值。★内存管理内存是片雷区,需要细心阅读,做到真正通晓内存!发生内存错误是非常麻烦的事情,编译器不能自动发现这些错误,通常在程序运行时才能捕捉到。大多没有明显的症状,时隐时现。内存分配方式(三种)1.从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。如全局变量,static变量。2.在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但内存容量有限。3.从堆上分配,即所谓的动态内存分配。程序在运行时用malloc或new申请任意多少的内存,程序员自己动手用free或delete释放内存。动态内存的生存期由我们决定,使用灵活,但问题也最多。常见的内存错误及其对策:1.内存分配未成功,却使用了它。新手犯的。解决办法:在使用内存钱检查指针是否为NULL,如果指针P是函数的参数,那在函数入口处用assert(p!=null)进行检查。如果是用malloc或new来申请内存,用if(p==NULL)或if(p!=NULL)来进行防错处理。2.内存分配虽然成功,但没有初始化就引用它。(没有初始化的概念,或者误以为内存缺省值为0)解决办法:无论用何种方式创建数组,都别忘了赋初值,即便是赋0值也不可省略。3.内存分配成功且已经初始化,但操作越界例如在使用数组时常发生下标“多1”或“少1”,尤其是for循环中,要慎重。4.忘记了释放内存,造成内存泄漏。含有这种错误的函数每被调用一次就丢失一块内存。系统会显示“内存耗尽”解决办法:动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(new/delete)。5.释放了内存却继续使用它。ⅰ程序中的对象调用关系过于复杂。这是数据结构设计问题,要重新设计一下。ⅱreturn语句写错了,注意不要返回指向“栈内存”的指针和引用,那个东西在函数体结束时被自动销毁的!ⅲ使用free或delete释放了内存后,没有将指针设置为NULL,导致“野指针”……规则:1.用malloc或new申请内存之后,立即检查指针是否为NULL.2.为数组和动态内存赋初值。3.避免数组或指针的下标越界,特别要当心“多1”或者“少1”4.动态内存的申请和释放必须配对,防止内存泄漏(malloc/free)(new/delete)5.用free或delete释放内存之后,立即将指针设置为NULL,防止产生“野指针”指针和数组的对比:数组要么在静态存储区被创建(全局数组),要么在栈上被创建。数组名对应着一块内存(而不是指向),其地址与容量在生命期内保持不变,只有数组的内容可以改变。指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。若想把数组a的内容复制给数组b,不能用b=a,用标准库函数strcpy进行复制;比较b和a的内容是否相同,不能用b==a来判断,用标准库函数strcmp进行比较。P=a并不能把a的内容复制给指针p,而是把a的地址赋给了p。得先用malloc为p申请一块容量为strlen(a)+1个字符的内存,在用strcpy进行字符串复制。用运算符sizeof可以计算出数组的容量,字节数。但sizeof指针,只能告诉你指针类型的大小,而不是它所致的内存的容量。C++/c没有办法知道指针所致的内存容量的。Win32位系统,所有的指针都是4位的。Char是1位,int,float是4位,double是8位。注意:当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。Free和delete只是把指针所指的内存给释放掉,但并没有把指针本身干掉。指针被free以后其地址仍然不变(非NULL),只是该地址对应的内存是垃圾,成了所谓的“野指针”,如果这时候不把该指针设置为NULL,会让人误以为它是个合法的指针。对于野指针,if(p!=NULL)起不到防错作用,因为即便p不是NULL指针,它也不指向合法的内存块。“野指针”不是NULL指针,是指向“垃圾”内存的指针。If语句对它不起作用。生成野指针的原因:1.指针变量没有被初始化。如果被创建时没有初始化指针,它会乱指一气。因此在指针变量创建时要初始化,要么设置为NULL,要么让它指向合法的内存。2.指针被free或者delete之后,没有置为NULL,让人误以为它是个合法的指针。3.指针操作超越了变量的作用范围。Malloc/free和new/delete的区别。(c程序只能用malloc/free管理动态内存)Malloc与free是c++/c语言的标准库函数,new/delete是c++的运算符。他们都可以用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。因为对象在创建的同时要自动执行构造函数,消亡之前要自动执行析构函数。而malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能把执行构造函数和析构函数的任务强加于malloc/free.因此c++需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。所以,不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete.而由于内部数据类型的“多项”没有构造和析构的过程,对它们而言malloc/free和new/dekete式等价的。处理内存耗尽问题。如果申请动态内存时找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败。处理方法:1.判断指针是否为NULL,如果是则马上用return语句终止本函数。2.判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行。3.为new和malloc设置异常处理函数。Malloc/free的使用要点Malloc原型:void*malloc(size_tsize);例:int*p=(int*)malloc(sizeof(int)*length);在malloc中使用sizeof是良好的编程风格。Free原型:voidfree(void*memblock);●如果不是NULL指针,那么free对p的连续操作两次就会导致程序运行错误;如果p是NULL指针,那么无论操作多少次都不回出问题。Mew/delete的使用要点New:int*p2=newint[length];因为new内置了sizeof、类型转换和类型检查功能。对非内部数据类型的对对象,new同时完成了初始化工作。Delete:用delete释放对象数组的时候,不要随意掉了符号‘[]’,例如delete[]objects;对指针需要做的:越是怕指针,也是要使用指针。不会正确使用指针,肯定算不上合格的程序员。必须养成“使用调试器逐步跟踪程序”的习惯,只有这样才能发现问题的本质。C++函数的高级特性对比与C语言
本文标题:高质量C++编程学习笔记
链接地址:https://www.777doc.com/doc-447755 .html