C++Primer中文版(第4版)学习笔记(注释)

上传人:沈*** 文档编号:186967769 上传时间:2023-02-10 格式:PDF 页数:60 大小:6.70MB
收藏 版权申诉 举报 下载
C++Primer中文版(第4版)学习笔记(注释)_第1页
第1页 / 共60页
C++Primer中文版(第4版)学习笔记(注释)_第2页
第2页 / 共60页
C++Primer中文版(第4版)学习笔记(注释)_第3页
第3页 / 共60页
资源描述:

《C++Primer中文版(第4版)学习笔记(注释)》由会员分享,可在线阅读,更多相关《C++Primer中文版(第4版)学习笔记(注释)(60页珍藏版)》请在装配图网上搜索。

1、C+Primer 中文版(第 4 版)学习笔记调用调用 GNU GNU 或微软编译器或微软编译器调用 GNU 编译器的默认命令是 g+:$g+prog1.cc-o prog1微软编译器采用命令 cl 来调用:C:directory cl-GX prog1.cppacm pc2acm pc2 编译器搭配编译器搭配下面是 pc2 配置:(以 vc 为编译环境)配置环境变量:jdk 设置:path=C:Program FilesJavajdk1.6.0bin;vc 编译器设置:path=C:Program FilesMicrosoft Visual StudioVC98Bin;lib=C:Progr

2、am FilesMicrosoft Visual StudioVC98Lib;include=C:ProgramFilesMicrosoftVisualStudioVC98include环境变量配置完成之后,设置下pc2 就 ok 了!pc2 设置如下:compile line:cl.exe:mainfile Executable Filename::basename.exe program execution command line:basename.exe做到这些配置,基本上编译就不成问题了!注意,期间可以需要到 C:ProgramFilesMicrosoft Visual Studio

3、COMMONTools 路径下拷贝 mspdb60.dll 到 C:ProgramFilesMicrosoft Visual StudioVC98Bin;!这个自己调试就 Ok 了!访问 main 函数的返回值的方式和系统有关。不论 UNIX 还是 Windows 系统,执行程序后,必须发出一个适当的 echo 命令。UNIX 系统中,通过键入如下命令获取状态:$echo$?要在 Windows 系统下查看状态,键入 C:directory echo%ERRORLEVEL%再谈编译再谈编译编译器的部分工作是寻找程序代码中的错误。编译器不能查出程序的意义是否正确,但它可以查出程序形式上的错误。下

4、面是编译器能查出的最普遍的一些错误。1、语法错误。程序员犯了 C+语言中的语法错误。下面代码段说明常见的语法错误;每个注释描述下一行的错误。/error:missing)in parameter list formain int main(/error:used colon,not a semicolon afterendl std:cout Read each file.std:endl:/error:missing quotes around stringliteral std:cout Update master.std:endl;/ok:no errors on this line s

5、td:cout Write new master.std:endl;/error:missing;on return statement return 0 2、类型错误。C+中每个数据项都有其相关联的类型。例如,值 10 是一个整数。用双引号标注起来的单词“hello”是字符串字面值。类型错误的一个实例是传递了字符串字面值给应该得到整型参数的函数。3、声明错误。C+程序中使用的每个名字必须在使用之前声明。没有声明名字通常会导致错误信息。最常见的两种声明错误,是从标准库中访问名字时忘记使用“std:”,以及由于疏忽而拼错标识符名:#include int main()int v1,v2;std:

6、cin v v2;/error:uses v not v1 /cout not defined,should be std:cout cout v1+v2 std:endl;return 0;错误信息包含行号和编译器对我们所犯错误的简要描述。按错误报告的顺序改正错误是个好习惯,通常一个错误可能会产生一连串的影响,并导致编译器报告比实际多得多的错误。最好在每次修改后或最多改正了一些显而易见的错误后,就重新编译代码。这个循环就是众所周知的编辑编译调试。从键盘输入文件结束符从键盘输入文件结束符操作系统使用不同的值作为文件结束符。Windows 系统下我们通过键入controlz同时键入“ctrl”键

7、和“z”键,来输入文件结束符。Unix 系统中,包括 Mac OSX 机器,通常用 controld。标准库的头文件用尖括号 括起来,非标准库的头文件用双引号 括起来。我们能将值 20 定义成下列三种形式中的任意一种:20 /decimal 024 /octal 0 x14 /hexadecimal以 0(零)开头的字面值整数常量表示八进制,以 0 x 或 0X 开头的表示十六进制。定义长整型时,应该使用大写字母 L。小写字母 l 很容易和数值 1 混淆。类似地,可通过在数值后面加U或u定义unsigned类型。使用科学计数法时,指数用E或者e表示。默认的浮点字面值常量为double类型。在数

8、值的后面加上F或f表示单精度。同样加上L或者l表示扩展精度非打印字符的转义序列非打印字符的转义序列newline换行符vertical tab纵向制表符n horizontal tab t水平制表符v backspace退格符fbcarriage return r formfeed回车符alert(bell)报警(响铃)符进纸符a backslash反斜线question mark疑问号double quote双引号?single quote单引号我们可以将任何字符表示为以下形式的通用转义字符:ooo这里 ooo 表示三个八进制数字,这三个数字表示字符的数字值。下面的例子是用 ASCII 码字

9、符集表示字面值常量:7(bell)12(newline)40(blank)0(null)062(2)115(M)字符0通常表示“空字符(null character)”,我们将会看到它有着非常特殊的意义。同样也可以用十六进制转义字符来定义字符:xdddC+的格式非常自由。特别是有一些地方不能插入空格,其中之一是在单词中间。特别是不能在单词中间断开一行。但可以通过使用反斜线符号巧妙实现:/ok:A before a newline ignores the line break std:cou t Hi st d:endl;等价于 std:cout Hi std:endl;可以使用这个特性来编写长

10、字符串字面值:/multiline string literal std:cout a multi-line string literal using a backslash std:endl;return 0;注意反斜线符号必须是该行的尾字符不允许有注释或空格符。同样,后继行行首的任何空格和制表符都是字符串字面值的一部分。正因如此,长字符串字面值的后继行才不会有正常的缩进。C+C+关键字关键字asmautoboolbreakcasecatchcharclassconstdodoubleifinlinereturnshortsignedsizeofstatictrytypedeftypeidt

11、ypenameuniondynamic_cast intelseenumexplicitexportexternfalselongmutablenamespacenewoperatorprivateprotectedpublicregisterstatic_cast unsignedstructswitchtemplatethisthrowtrueusingvirtualvoidvolatilewchar_twhileconst_cast floatcontinuedefaultdeleteforfriendgotoreinterpret_castC+C+操作符替代名操作符替代名andbita

12、nd compl not_eq or_eq xor_eqorxorand_eq bitornotC+支持两种初始化变量的形式:复制初始化复制初始化和直接初始化直接初始化。复制初始化语法用等号(=),直接初始化则是把初始化式放在括号中:int ival(1024);/direct-initialization int ival=1024;/copy-initialization初始化置类型的对象只有一种方法:提供一个值,并且把这个值复制到新定义的对象中。对置类型来说,复制初始化和直接初始化几乎没有差别。对类类型的对象来说,有些初始化仅能用直接初始化完成。要想理解其中缘由,需要初步了解类是如何控制

13、初始化的。变量初始化规则变量初始化规则置类型变量的初始化置类型变量的初始化使用未初始化的变量是常见的程序错误,通常也是难以发现的错误。虽然许多编译器都至少会提醒不要使用未初始化变量,但是编译器并未被要求去检测未初始化变量的使用。而且,没有一个编译器能检测出所有未初始化变量的使用。有时我们很幸运,使用未初始化的变量导致程序在运行时突然崩溃。一旦跟踪到程序崩溃的位置,就可以轻易地发现没有正确地初始化变量。但有时,程序运行完毕却产生错误的结果。更糟糕的是,程序运行在一部机器上时能产生正确的结果,但在另外一部机器上却不能得到正确的结果。添加代码到程序的一些不相关的位置,会导致我们认为是正确的程序产生错

14、误的结果。建议每个置类型的对象都要初始化。虽然这样做并不总是必需的,但是会更加容易和安全,除非你确定忽略初始化式不会带来风险。类类型变量的初始化类类型变量的初始化每个类都定义了该类型的对象可以怎样初始化。类通过定义一个或多个构造函数来控制类对象的初始化。如果定义某个类的变量时没有提供初始化式,这个类也可以定义初始化时的操作。它是通过定义一个特殊的构造函数即默认构造函数默认构造函数来实现的。这个构造函数之所以被称作默认构造函数,是因为它是“默认”运行的。如果没有提供初始化式,那么就会使用默认构造函数。不管变量在哪里定义,默认构造函数都会被使用。变量的声明和定义变量的声明和定义变量的定义定义用于为

15、变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且仅有一个定义。声明声明用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用 extern 关键字声明变量名而不定义它。不定义变量的声明包括对象名、对象类型和对象类型前的关键字 extern:extern int i;/declares but does not define i int i;/declares and defines iextern 声明不是定义,也不分配存储空间。事实上,它只是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。只有当声明也是定义时,声

16、明才可以有初始化式,因为只有定义才分配存储空间。初始化式必须要有存储空间来进行初始化。如果声明有初始化式,那么它可被当作是定义,即使声明标记为 extern:extern double pi=3.1416;/definition虽然使用了 extern,但是这条语句还是定义了 pi,分配并初始化了存储空间。只有当 extern 声明位于函数外部时,才可以含有初始化式。因为已初始化的 extern 声明被当作是定义,所以该变量任何随后的定义都是错误的:extern double pi=3.1416;/definition double pi;/error:redefinition of pi同样

17、,随后的含有初始化式的 extern 声明也是错误的:extern double pi=3.1416;/definition extern double pi;/ok:declaration not definition extern double pi=3.1416;/error:redefinition of pi声明和定义之间的区别可能看起来微不足道,但事实上却是举足轻重的。在 C+语言中,变量必须且仅能定义一次,而且在使用变量之前必须定义或声明变量。任何在多个文件中使用的变量都需要有与定义分离的声明。在这种情况下,一个文件含有变量的定义,使用该变量的其他文件则包含该变量的声明(而不是定

18、义)。下列程序段将会输出什么?int i=100,sum=0;for(int i=0;i!=10;+i)sum+=i;std:cout i sum std:endl;【解答】输出为:100 45for 语句中定义的变量i,其作用域仅限于for 语句部。输出的i 值是for 语句之前所定义的变量 i 的值。constconst因为常量在定义后就不能被修改,所以定义时必须初始化:const std:string hi=hello!;/ok:initialized const int i,j=0;/error:i is uninitialized const引用引用引用必须用与该引用同类型的对象初始

19、化:int ival=1024;int&refVal=ival;/ok:refVal refers to ival int&refVal2;/error:a reference must be initialized int&refVal3=10;/error:initializer must be an object因为引用只是它绑定的对象的另一名字,作用在引用上的所有操作事实上都是作用在该引用绑定的对象上:constconst 引用引用constconst 引用引用是指向 const 对象的引用:const int ival=1024;const int&refVal=ival;/ok:b

20、oth reference and object areconst int&ref2=ival;/error:non const reference to aconst object可以读取但不能修改 refVal,因此,任何对 refVal 的赋值都是不合法的。这个限制有其意义:不能直接对 ival 赋值,因此不能通过使用 refVal 来修改ival。类定义类定义使用使用structstruct关键字关键字C+支持另一个关键字 struct,它也可以定义类类型。struct 关键字是从 C 语言中继承过来的。用 class 和 struct 关键字定义类的唯一差别在于默认访问级别:默认情况

21、下,struct 的成员为 public,而 class 的成员为 private。class Sales_item public:/operations on Sales_item objects will go here private:std:string isbn;unsigned units_sold;double revenue;struct Sales_item /no need for public label,members are public by default /operations on Sales_item objects private:std:string i

22、sbn;unsigned units_sold;double revenue;编译和多个源文件编译和多个源文件我们可以按以下方式编译这两个文件:$CC-c main.cc Sales_item.cc#by default generates a.exe#some compilers generate a.out#puts the executable in main.exe$CC-c main.cc Sales_item.cc-o main其中$是我们的系统提示符,#开始命令行注释。现在我们可以运行可执行文件,它将运行我们的 main 程序。如果我们只是修改了一个.cc 源文件,较有效的方法是

23、只重新编译修改过的文件。大多数编译器都提供了分别编译每一个文件的方法。通常这个过程产生.o文件,.o 扩展名暗示该文件含有目标代码。编译器允许我们把目标文件在一起以形成可执行文件。我们所使用的系统可以通过命令名 CC 调用编译。因此可以按以下方式编译程序:$CC-c main.cc#generates main.o$CC-c Sales_item.cc#generates Sales_item.o$CC main.o Sales_item.o#by default generates a.exe;#some compilers generate a.out#puts the executabl

24、e in main.exe$CC main.o Sales_item.o-o main头文件用于声明而不是用于定义头文件用于声明而不是用于定义因为头文件包含在多个源文件中,所以不应该含有变量或函数的定义。对于头文件不应该含有定义这一规则,有三个例外有三个例外。头文件可以定义类、值在编译时就已知道的const对象和inline函数。这些实体可在多个源文件中定义,只要每个源文件中的定义是相同的。一些一些constconst对象定义在头文件中对象定义在头文件中当该 const 变量是用常量表达式初始化时,可以保证所有的变量都有相同的值。但是在实践中,大部分的编译器在编译时都会用相应的常量表达式替换这

25、些const 变量的任何使用。所以,在实践中不会有任何存储空间用于存储用常量表达式初始化的 const 变量。可在头文件中定义。如果 const 变量不是用常量表达式初始化,那么它就不应该在头文件中定义。相反,和其他的变量一样,该 const 变量应该在一个源文件中定义并初始化。应在头文件中为它添加 extern 声明,以使其能被多个文件共享。下列声明和定义哪些应该放在头文件中?哪些应该放在源文件中?请解释原因。(a)int var;(b)const double pi=3.1416;(c)extern int total=255;(d)const double sq2=squt(2.0);【

26、解答】(a)、(c)、(d)应放在源文件中,因为(a)和(c)是变量定义,定义通常应放在源文件中。(d)中的const 变量sq2 不是用常量表达式初始化的,所以也应该放在源文件中。(b)中的 const 变量 pi 是用常量表达式初始化的,应该放在头文件中。不使用不使用命名空间命名空间#include int main()int sum=0,val=1;/keep executing the while until val is greater than 10 while(val=10)sum+=val;/assigns sum+val to sum +val;/add 1 to val s

27、td:cout Sum of 1 to 10 inclusive is sum std:endl;return 0;命名空间的命名空间的usingusing声明声明using声明可以在不需要加前缀namespace_name:的情况下访问命名空间中的名字。using声明的形式如下:using namespace:name;一旦使用了using声明,我们就可以直接引用名字,而不需要再引用该名字的命名空间。#include#include /using declarations states our intent to use these names from thenamespace std u

28、sing std:cin;using std:string;int main()string s;/ok:string is now a synonym for std:string cin s;/ok:cin is now a synonym for std:cin cout s;/error:no using declaration;we must use fullname std:cout s;/read whitespace-separated string into s cout s s;/read whitespace-separated string into s从标准输入读取s

29、tring并将读入的串存储在s中。string类型的输入操作符:读取并忽略开头所有的空白字符(如空格,换行符,制表符)。读取字符直至再次遇到空白字符,读取终止。读入未知数目的读入未知数目的stringstring对象对象和置类型的输入操作一样,string的输入操作符也会返回所读的数据流。因此,可以把输入操作作为判断条件,这与我们在1.4.4节读取整型数据的程序做法是一样的。下面的程序将从标准输入读取一组string对象,然后在标准输出上逐行输出:int main()string word;/read until end-of-file,writing each word to a new l

30、ine while(cin word)cout word endl;return 0;使用使用getlinegetline读取整行文本读取整行文本getlinegetline。这个函数接受两个参数:一个输入流对象和一个string对象。getline函数从输入流的下一行读取,并保存读取的容到不包括换行符。和输入操作符不一样的是,getline并不忽略行开头的换行符。只要getline遇到换行符,即便它是输入的第一个字符,getline也将停止读入并返回。如果第一个字符就是换行符,则string参数将被置为空string。getline函数将istream参数作为返回值,和输入操作符一样也把它用

31、作判断条件。例如,重写前面那段程序,把每行输出一个单词改为每次输出一行文本:int main()string line;/read line at time until end-of-file while(getline(cin,line)cout line endl;return 0;由于getline函数返回时丢弃换行符,换行符将不会存储在string对象中。stringstring对象的操作对象的操作.empty()s.size()sns1+s2s1=s2v1=v2如果s为空串,则返回true,否则返回false。返回s中字符的个数返回s中位置为n的字符,位置从0开始计数把s1和 s2连

32、接成一个新字符串,返回新生成的字符串把s1容替换为s2的副本比较v1与v2 的容,相等则返回true,否则返回false!=,and=保持这些操作符惯有的含义string:size_typestring:size_type类型类型从逻辑上来讲,size()成员函数似乎应该返回整形数值,或如2.2节“建议”中所述的无符号整数。但事实上,size操作返回的是string:size_type类型的值。我们需要对这种类型做一些解释。任何存储string的size操作结果的变量必须为string:size_type类型。特别重要的是,不要把size的返回值赋给一个int变量。和字符串字面值的连接和字符串

33、字面值的连接当进行string对象和字符串字面值混合连接操作时,+操作符的左右操作数必须至少有一个是string类型的:string s1=hello;/no punctuation string s2=world;string s3=s1+,;/ok:adding a string and a literal string s4=hello+,;/error:no string operand string s5=s1+,+world;/ok:each+has string operand string s6=hello+,+s2;/error:cant add string literal

34、s可用下标操作符分别取出string对象的每个字符,分行输出:string str(some string);for(string:size_type ix=0;ix!=str.size();+ix)cout strix endl;cctypecctype Functions Functionsisalnum(c)如果c是字母或数字,则为True。isalpha(c)如果c是字母,则为true。iscntrl(c)如果c是控制字符,则为trueisdigit(c)如果c是数字,则为true。isgraph(c)如果c不是空格,但可打印,则为true。islower(c)如果c是小写字母,则为t

35、rue。isprint(c)如果c是可打印的字符,则为true。ispunct(c)如果c是标点符号,则true。isspace(c)如果c是空白字符,则为true。isupper(c)如果c是大写字母,则true。isxdigit(c)如果是c十六进制数,则为true。tolower(c)如果c大写字母,返回其小写字母形式,否则直接返回c。toupper(c)如果c是小写字母,则返回其大写字母形式,否则直接返回c。建议:采用建议:采用C C标准库头文件的标准库头文件的C+C+版本版本C+标准库除了定义了一些选定于C+的设施外,还包括C标准库。C+中的头文件cctype其实就是利用了C标准库函

36、数,这些库函数就定义在C标准库的ctype.h头文件中。C标准库头文件命名形式为name而C+版本则命名为 ame,少了后缀,.h而在头文件名前加了c表示这个头文件源自C标准库。因此,cctype与ctype.h文件的容是一样的,只是采用了更适合C+程序的形式。特别地,cname头文件中定义的名字都定义在命名空间std,而.h版本中的名字却不是这样。通常,C+程序中应采用 ame这种头文件的版本,而不采用name.h版本,这样,标准库中的名字在命名空间std中保持一致。使用.h版本会给程序员带来负担,因为他们必须记得哪些标准库名字是从C继承来的,而哪些是C+所特有的。标准库标准库vectorv

37、ector类型类型vector 是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。和string 对象一样,标准库将负责管理与存储元素相关的存。我们把 vector 称为容器容器,是因为它可以包含其他对象。一个容器中的所有对象都必须是同一种类型的。vector 是一个类模板类模板(class templateclass template)。使用模板可以编写一个类定义或函数定义,而用于多个不同的数据类型。因此,我们可以定义保存 string 对象的vector,或保存 int 值的 vector,又或是保存自定义的类类型对象(如Sales_items 对象)的 vector。声明从类模

38、板产生的某种类型的对象,需要提供附加信息,信息的种类取决于模板。以 vector 为例,必须说明 vector 保存何种对象的类型,通过将类型放在类型放在类模板名称后面的尖括号中来指定类型:vector ivec;/ivec holds objects of type int vector Sales_vec;/holds Sales_itemsvector 不是一种数据类型,而只是一个类模板,可用来定义任意多种数据类型。vector 类型的每一种都指定了其保存元素的类型。因此,vector 和vector 都是数据类型。vectorvector 对象的定义和初始化对象的定义和初始化vecto

39、r v1;vector v2(v1);vector 保存类型为 T 对象。默认构造函数 v1 为空。v2 是 v1 的一个副本。vector v3(n,i);v3 包含 n 个值为 i 的元素。vector v4(n);vectorvector对象动态增长对象动态增长vector 对象(以及其他标准库容器对象)的重要属性就在于可以在运行时高效地添加元素。因为 vector 增长的效率高,在元素值已知的情况下,最好是动态地添加元素。虽然可以对给定元素个数的 vector 对象预先分配存,但更有效的方法是先初始化一个空 vector 对象,然后再动态地增加元素(我们随后将学习如何进行这样的操作)。

40、值初始化值初始化v4 含有值初始化的元素的 n 个副本。如果没有指定元素的初始化式,那么标准库将自行提供一个元素初始值进行值初值初始化(始化(value initializationdvalue initializationd)。这个由库生成的初始值将用来初始化容器中的每个元素,具体值为何,取决于存储在 vector 中元素的数据类型。如果 vector 保存置类型(如 int 类型)的元素,那么标准库将用 0 值创建元素初始化式:vector fvec(10);/10 elements,each initialized to 0如果 vector 保存的是含有构造函数的类类型(如 strin

41、g)的元素,标准库将用该类型的默认构造函数创建元素初始化式:vector svec(10);/10 elements,each an empty stringvector Operationsv.empty()v.size()v.push_back(t)vnv1=v2v1=v2!=,and=vector 对象的 size如果 v 为空,则返回 true,否则返回 false。返回 v 中元素的个数。在 v 的末尾增加一个值为 t 的元素。返回 v 中位置为 n 的元素。把 v1 的元素替换为 v2 中元素的副本。如果 v1 与 v2 相等,则返回 true。保持这些操作符惯有的含义。使用 si

42、ze_type 类型时,必须指出该类型是在哪里定义的。vector 类型总是包括总是包括 vector 的元素类型:vector:size_type /ok vector:size_type /error初学 C+的程序员可能会认为 vector 的下标操作可以添加元素,其实不然:vector ivec;/empty vector for(vector:size_type ix=0;ix!=10;+ix)ivecix=ix;/disaster:ivec has no elements上述程序试图在 ivec 中插入 10 个新元素,元素值依次为 0 到 9 的整数。但是,这里 ivec 是空的

43、 vector 对象,而且下标只能用于获取已存在的元素。这个循环的正确写法应该是:for(vector:size_type ix=0;ix!=10;+ix)ivec.push_back(ix);/ok:adds new element with value ix必须是已存在的元素才能用下标操作符进行索引。通过下标操作进行赋值时,不会添加任何元素。警告:仅能对确知已存在的元素进行下标操作迭代器简介迭代器简介除了使用下标来访问vector对象的元素外,标准库还提供了另一种访问元素的方法:使用迭代器(迭代器(iteratoriterator)。迭代器是一种检查容器元素并遍历元素的数据类型。标准库为每

44、一种标准容器(包括vector)定义了一种迭代器类型。迭代器类型提供了比下标操作更通用化的方法:所有的标准库容器都定义了相应的迭代器类型,而只有少数的容器支持下标操作。因为迭代器对所有的容器都适用,现代C+程序更倾向于使用迭代器而不是下标操作访问容器元素,即使对支持下标操作的vector类型也是这样。每种容器类型都定义了自己的迭代器类型,如vector:vector:iterator iter;begin和end操作每种容器都定义了一对命名为begin和end的函数,用于返回迭代器。如果容器中有元素的话,由begin返回的迭代器指向第一个元素:vector:iterator iter=ivec

45、.begin();由end操作返回的迭代器指向vector的“末端元素的下一个”。“超出“超出末端迭代器”(末端迭代器”(off-the-end iteratoroff-the-end iterator)。表明它指向了一个不存在的元素。如果vector为空,begin返回的迭代器与end返回的迭代器相同。由于end操作返回的迭代器不指向任何元素,因此不能对它进行解引用(*)或自增操作。for(vector:iterator iter=ivec.begin();iter!=ivec.end();+iter)*iter=0;/set element to which iter refers to

46、0const_iteratorconst_iterator每种容器类型还定义了一种名为const_iterator的类型,该类型只能用于读取容器元素,但不能改变其值。for(vector:const_iterator iter=text.begin();iter!=text.end();+iter)*iter=;/error:*iter is const使用const_iterator类型时,我们可以得到一个迭代器,它自身的值可以改变,但不能用来改变其所指向的元素的值。可以对迭代器进行自增以及使用解引用操作符来读取值,但不能对该元素赋值。不要把const_iterator对象与const的it

47、erator对象混淆起来。声明一个const迭代器时,必须初始化迭代器。一旦被初始化后,就不能改变它的值:vector nums(10);/nums is nonconst const vector:iterator cit=nums.begin();*cit=1;/ok:cit can change its underlying element +cit;/error:cant change the value of cit任何改变vector长度的操作都会使已存在的迭代器失效。例如,在调用push_back之后,就不能再信赖指向vector的迭代器的值了。标准库标准库bitsetbitse

48、t初始化初始化bitsetbitset对象的方法对象的方法bitset b;bitset b(u);bitset b(s);b有n位,每位都0b是unsigned long型u的一个副本b是string对象s中含有的位串的副本bitset b(s,pos,n);b是s中从位置pos开始的 n个位的副本。bitset bitvec;/32 bits,all zero这条语句把bitvec定义为含有32个位的bitset对象。和vector的元素一样,bitset中的位是没有命名的,程序员只能按位置来访问。位集合的位置编号从0开始,因此,bitvec的位序是从0到31。以0位开始的位串是低阶位(l

49、ow-orderlow-order),以31位结束的位串是高阶位(high-orderhigh-order)。string对象和bitsets对象之间是反向转化的:string对象的最右边字符(即下标最大的那个字符)用来初始化bitset对象的低阶位(即下标为0的位)。当用string对象初始化bitset对象时,记住这一差别很重要。bitset操作b.any()b.none()b.count()b.size()bposb中是否存在置为1的二进制位?b中不存在置为1的二进制位?b中置为1的二进制位的个数b中二进制位的个数访问b中在pos处二进制位b.test(pos)b中在pos处的二进制位置

50、是否为1b.any()b.set()b.set(pos)b.reset()b中是否存在置为1的二进制位?把b中所有二进制位都置为1把b中在pos处的二进制位置为1把b中所有二进制位都置为0b.reset(pos)把b中在pos处的二进制位置为0b.flip()把b中所有二进制位逐位取反b.flip(pos)把b中在pos处的二进制位取反b.to_ulong()用b中同样的二进制位返回一个unsigned long值os b把b中的位集输出到os流size_t类 型 定 义 在cstddef头 文 件 中,该 文 件 是C标 准 库 的 头 文件stddef.h的C+版本。它是一个与机器相关的u

51、nsigned类型,其大小足以保证存储在中对象的大小。建议:尽量避免使用指针和数组建议:尽量避免使用指针和数组指针和数组容易产生不可预料的错误。其中一部分是概念上的问题:指针用于低级操作,容易产生与繁琐细节相关的(bookkeeping)错误。其他错误则源于使用指针的语法规则,特别是声明指针的语法。许多有用的程序都可不使用数组或指针实现,现代 C+程序采用 vector 类型和迭代器取代一般的数组、采用 string 类型取代 C 风格字符串。一个有效的指针必然是以下三种状态之一:一个有效的指针必然是以下三种状态之一:保存一个特定对象的地址;指向某个对象后面的另一对象;或者是 0 值。若指针保

52、存 0 值,表明它不指向任何对象。未初始化的指针是无效的,直到给该指针赋值后,才可使用它。下列定义和赋值都是合法的:int ival=1024;int*pi=0;/pi initialized to address no object int*pi2=&ival;/pi2 initialized to address of ival int*pi3;/ok,but dangerous,pi3 is uninitialized pi=pi2;/pi and pi2 address the same object,e.g.ival pi2=0;/pi2 now addresses no objec

53、t避免使用未初始化的指针避免使用未初始化的指针很多运行时错误都源于使用了未初始化的指针。指针初始化和赋值操作的约束指针初始化和赋值操作的约束对指针进行初始化或赋值只能使用以下四种类型的值:1.0 值常量表达式,例如,在编译时可获得 0 值的整型 const 对象或字面值常量 0。2.类型匹配的对象的地址。3.另一对象末的下一地址。4.同类型的另一个有效指针。把 int 型变量赋给指针是非法的,尽管此 int 型变量的值可能为 0。但允许把数值 0 或在编译时可获得 0 值的 const 量赋给指针:int ival;int zero=0;const int c_ival=0;int*pi=iv

54、al;/error:pi initialized from int value of ival pi=zero;/error:pi assigned int value of zero pi=c_ival;/ok:c_ival is a const with compile-time valueof 0 pi=0;/ok:directly initialize to literal constant0void*void*指针指针C+提供了一种特殊的指针类型 void*void*,它可以保存任何类型对象的地址:void*表明该指针与一地址值相关,但不清楚存储在此地址上的对象的类型。void*指针

55、只支持几种有限的操作:与另一个指针进行比较;向函数传递 void*指针或从函数返回 void*指针;给另一个 void*指针赋值。不允许使用 void*指针操纵它所指向的对象。永远不要忘记字符串结束符 null如果两个操作数为正,除法(/)和求模(%)操作的结果也是正数(或零);如果两个操作数都是负数,除法操作的结果为正数(或零),而求模操作的结果则为负数(或零);如果只有一个操作数为负数,这两种操作的结果取决于机器;求模结果的符号也取决于机器,而除法操作的值则是负数(或零):21%6;/ok:result is 3 21%7;/ok:result is 0 -21%-8;/ok:result

56、 is-5 21%-5;/machine-dependent:result is 1 or-4 21/6;/ok:result is 3 21/7;/ok:result is 3 -21/-8;/ok:result is 2 21/-5;/machine-dependent:result-4 or-5当只有一个操作数为负数时,求模操作结果值的符号可依据分子(被除数)或分母(除数)的符号而定。如果求模的结果随分子的符号,则除出来的值向零一侧取整;如果求模与分母的符号匹配,则除出来的值向负无穷一侧取整。逻辑与、逻辑或操作符逻辑与、逻辑或操作符逻辑与和逻辑或操作符总是先计算其左操作数,然后再计算其右

57、操作数。只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数。我们常常称这种求值策略为“短路求值(short-circuit evaluation)”。对于位操作符,由于系统不能确保如何处理其操作数的符号位,所以强烈建议使用 unsigned 整型操作数。int*pi=new int;/pi points to an uninitialized intint*pi=new int();/pi points to an int value-initialized to0第一个语句的 int 型变量没有初始化,而第二个语句的 int 型变量则被初始化为 0。利用利用constco

58、nst引用避免复制引用避免复制编写一个比较两个 string 对象长度的函数作为例子。这个函数需要访问每个string 对象的 size,但不必修改这些对象。由于 string 对象可能相当长,所以我们希望避免复制操作。使用 const 引用就可避免复制:/compare the length of two strings bool isShorter(const string&s1,const string&s2)return s1.size()s2.size();如果使用引用形参的唯一目的是避免复制实参,则应将形参定义为 const 引用。vectorvector和其他容器类型的形参和其他

59、容器类型的形参通常,函数不应该有 vector 或其他标准库容器类型的形参。调用含有普通的非引用 vector 形参的函数将会复制 vector 的每一个元素。事实上,C+程序员倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器:/pass iterators to the first and one past the last element to print void print(vector:const_iterator beg,vector:const_iterator end)while(beg!=end)cout *beg+;if(beg!=end)cout ;/no spa

60、ce after last element cout endl;通过引用传递数组通过引用传递数组和其他类型一样,数组形参可声明为数组的引用。如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,数组大小成为形参和实参类型的一部分。编译器检查数组的实参的大小与形参的大小是否匹配:/ok:parameter is a reference to an array;size of array is fixed void printValues(int(&arr)10)/*.*/int main()int i=0,j2=0,1;int k10=0,1,2,3,4,5

61、,6,7,8,9;printValues(&i);/error:argument is not an array of 10 ints printValues(j);/error:argument is not an array of 10 ints printValues(k);/ok:argument is an array of 10 ints return 0;这个版本的 printValues 函数只严格地接受含有 10 个 int 型数值的数组,这限制了哪些数组可以传递。然而,由于形参是引用,在函数体中依赖数组的大小是安全的:/ok:parameter is a reference

62、 to an array;size of array is fixed void printValues(int(&arr)10)for(size_t i=0;i!=10;+i)cout arri endl;&arr 两边的圆括号是必需的,因为下标操作符具有更高的优先级:mainmain:处理命令行选项处理命令行选项int main(int argc,char*argv).第二个形参 argv 是一个 C 风格字符串数组。第一个形参 argc 则用于传递该数组中字符串的个数。由于第二个参数是一个数组,主函数 main 也可以这样定义:int main(int argc,char*argv).p

63、rog-d-o ofile data0当将实参传递给主函数 main 时,argv 中的第一个字符串(如果有的话)通常是程序的名字。接下来的元素将额外的可选字符串传递给主函数 main。以前面的命令行为例,argc 应设为 5,argv 会保存下面几个 C 风格字符串:argv0=prog;argv1=-d;argv2=-o;argv3=ofile;argv4=data0;静态局部对象静态局部对象一个变量如果位于函数的作用域,但生命期跨越了这个函数的多次调用,这种变量往往很有用。则应该将这样的对象定义为 static(静态的)。static 局部对象确保不迟于在程序执行流程第一次经过该对象的定

64、义语句时进行初始化。这种对象一旦被创建,在程序结束前都不会撤销。当定义静态局部对象的函数结束时,静态局部对象不会撤销。在该函数被多次调用的过程中,静态局部对象会持续存在并保持它的值。考虑下面的小例子,这个函数计算了自己被调用的次数:size_t count_calls()static size_t ctr=0;/value will persist across calls return+ctr;int main()for(size_t i=0;i!=10;+i)cout count_calls()word)/ok:read operation successful.输出缓冲区的管理输出缓冲区

65、的管理每个 IO 对象管理一个缓冲区,用于存储程序读写的数据。如有下面语句:os please enter a value:;1.程序正常结束。作为 main 返回工作的一部分,将清空所有输出缓冲区。2.在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。3.用操纵符(第 1.2.2 节)显式地刷新缓冲区,例如行结束符 endl。4.在每次输出操作执行完后,用 unitbuf 操作符设置流的部状态,从而清空缓冲区。5.可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区。输出缓冲区的刷新输出缓冲区的刷新们的程序已经使用过 e

66、ndl 操纵符,用于输出一个换行符并刷新缓冲区。除此之外,C+语言还提供了另外两个类似的操纵符。第一个经常使用的 flush,用于刷新流,但不在输出中添加任何字符。第二个则是比较少用的 ends,这个操纵符在缓冲区中插入空字符 null,然后后刷新它:cout hi!flush;/flushes the buffer;adds no data cout hi!ends;/inserts a null,then flushes thebuffer cout hi!endl;/inserts a newline,then flushes thebufferunitbufunitbuf 操纵符操纵符如果需要刷新所有输出,最好使用 unitbuf 操纵符。这个操纵符在每次执行完写操作后都刷新流:cout unitbuf first second nounitbuf;等价于:cout first flush second flush;nounitbuf 操纵符将流恢复为使用正常的、由系统管理的缓冲区刷新方式。文件的输入和输出文件的输入和输出文件流对象的使用文件流对象的使用/construct a

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

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!