C++程序设计,c头文件有哪些

头文件 7
C++程序设计 第2章变量和类型 计算机学院黄章进zhuang@ 内容 2.1基本内置类型2.2变量 变2.3复合类型量2.4const限定符和类2.5处理类型型2.6自定义数据结构
2 数据类型 数据类型(type)是程序的基础 数据的意义能在数据上执行的操作 C++支持广泛的数据类型 基本内置类型 字符、整型、浮点数 自定义数据类型 C++标准库定义了可变长字符串和向量等
3 基本内置类型 C++定义的基本数据类型 算术类型(arithmetic
type) 字符、整型数、布尔值、浮点数 空类型void 不对应具体的值,常见于函数返回类型
4 算术类型 算术类型分为两类: 基 整型(integraltype):包括字符和布尔类型在内 本 浮点型(floating-pointtype) 内算术类型的尺寸(比特数)在不同的 置机器上有所差别 类 C++标准仅规定尺寸的最小值,但允许编 型 译器实现采用更大的尺寸
5 算术类型 基本内置类型
6 算术类型 bool类型的取值是true或false字符类型 基基本字符类型char本确保可以存放机器基本字符集中任意字符对内应的数字值,即大小和一个机器byte一样置wchar_t、char16_t和char32_t用于扩展字类符集,来支持国际化型wchar_t类型用于确保可以存放机器的最大扩 展字符集中的任一字符类型char16_t和char32_t为Unicode字符集服务
7 算术类型 其他整型: short<=int<=long<=longlong 基 longlong是C++11新定义的 本浮点型 内 单精度float以1个字(32比特)表示 置 双精度double以2个字(64比特)表示 类 扩展精度longdouble以3或4个字(96或 型 128比特)表示 float和double一般分别有7和16个有效位, longdouble常用于有特殊精度需求的硬件
8 符号类型和无符号类型 除去布尔型和扩展字符型之外,其他 基 整型都可以是带符号的(signed)和无符号的(unsigned) 本 符号类型可以表示正数、负数或
0 内 int、short、long、longlong 置 无符号类型只能表示大于等于0的值 类 unsigned或unsignedint、unsignedshort、 型 unsignedlong、unsignedlonglong
9 符号类型和无符号类型 基本字符类型有三种: char、signedchar和unsignedchar 基 char和signedchar是不一样的 本表现形式只有两种: 内 带符号的和无符号的char等价于signedchar还是unsignedchar取决 置 于编译器的实现 类无符号类型中的所有比特都用来存储值 型 8比特的unsignedchar表示[0,255]内的数 C++标准没有规定符号类型应如何表示 一般8比特的signedchar表示范围为[-128,127] 10 如何选择类型 确定数值不可能为负时,选择无符号类型使用int执行整数运算 short常常显得太小,而long一般和int有一样的尺寸 基如果数值超过了int的表示范围,选用longlong本在算术表达式中不要使用char或bool内类型char是否有符号依机器而定置如果需要使用一个不大的整数,明确指定类型为 signedchar或unsignedchar 类执行浮点数运算用double型float通常精度不够,双精度和单精度浮点数的计算代 价相差无几longdouble提供的精度一般没有必要,且计算代价高 11 类型转换 对象的类型定义了对象能包含的数据 基和能执行的操作 本当在程序中使用了一种类型而对象应 内 该取另一种类型时,程序会自动执行类型转换 置初始化 类赋值型 算术运算 12 类型转换 赋值时的类型转换规则: 把非布尔的算术值赋给一个bool对象时,0值转换为false,非0值转换为true 基把bool值赋给非布尔算术对象时,false转换为0,true 转换为
1 本把浮点数赋给整型对象时,保留小数点前的整数部分内把整数值赋给浮点对象时,小数部分为0置赋给无符号类型一个超出其表示范围的值时,结果是 该值对无符号类型表示数值总数取模后的余数 类例如,8位的unsignedchar可表示0至255区间的256个数,型那么用-1赋值后的结果是255 赋给带符号类型一个超出其表示范围的值时,结果是未定义的 13 例子 boolb=42; //bistrue inti=b; //ihasvalue1 i=3.14; //ihasvalue3 doublepi=i; //pihasvalue3.0 类unsignedcharc=-1;//assuming8-bitchars,chas value255 型signedcharc2=256;//assuming8-bitchars,thevalue 转换ofc2isundefined 14 含有无符号类型的表达式 当算术表达式中既有unsigned值又有int值时,int值会转换为unsigned类型 unsignedu=10;inti=-42; 类std::cout<=0;--u) 型std::cout<literal)包括 小数和以科学计数法表示的指数 字 科学计数法中,指数部分用E或e标识 面 3.141593.14159E00.0e0.001 值 默认的,浮点型字面值为double类型 常量 21 字符和字符串字面值 'a'//characterliteral "a"//stringliteral"HelloWorld!
"//stringliteral 字 char型字面值:由单引号括起来的一个字符 面字符串字面值:双引号括起来的零个或多 值个字符 常 编译器在每个字符串的结尾处添加一个空字符(’\0’) 量 如果两个字符串字面值位置相邻,且仅由空 格、缩进和换行符分隔,则表示一个字符串 //multilinestringliteralstd::cout<<"areally,reallylongstringliteral" "thatspanstwolines"<singlequote\' carriagereturn\rformfeed \f 23 转义序列 程序中,转义序列被当作一个字符 std::cout<<'\n';//printsanewline 字 std::cout<<"\tHi!
\n";//printsatabfollowdby"Hi!
" 面 andanewline 值也可以使用广义转义序列,其形式是\x 常 后跟1个或多个十六进制数字,或\后紧跟1到3个八进制数字 量 数字部分表示字符对应的数值 \7(bell)\12(newline)\40(blank)\0(null)\115('M')\x4d('M') 24 转义序列 可以像使用普通字符那样使用转义序列 std::cout<<"Hi\x4dO\115!
\n";//printsHiMOM!
字followedbyanewline面std::cout<<'\115'<<'\n';//printsMfollowedbya值newline常如果反斜线\后跟的八进制数字超过3个量,则只有前3个数字与\构成转义序列; 而\x要用到后面跟的所有十六进制数字 "\1234"\x1234 25 指定字面值的类型 通过添加前缀或后缀,可以改变整型、浮点型和字符型字面值的默认类型 字面值常量 使用长整型字面值时,使用大写字面L来标记,以免小写字母l和数字1混淆 26 指定字面值的类型 对整型字面值,可以分别指定是否带符号以及尺寸。
也可以将U与L或LL组合使用 以UL为后缀的字面值的类型根据具体数值取 字unsignedlong或unsignedlonglong类型面L'a'//widecharacterliteral,typeiswchar_t u8"hi!
"//utf-8stringliteral(utf-8encodesaUnicode 值characterin8bits) 42ULL//unsignedintegerliteral,typeisunsignedlong 常long量1E-3F//single-precisionfloating-pointliteral,type isfloat3.14159L//extended-precisionfloating-pointliteral,typeislongdouble 27 布尔字面值和指针字面值 true和false是布尔类型的字面值 booltest=false; 字nullptr是指针字面值面值常量 28 练习 练习2.5:指出下述字面值的类型 (a)'a',L'a',"a",L"a" 字 (b)10,10u,10L,10uL,012,0xC 面 (c)3.14,3.14f,3.14L 值 (d)10,10u,10.,10e-
2 常量练习2.6:下面两组定义是否有区别? intmonth=9,day=7;intmonth=09,day=07; 29 练习 练习2.7:给出下面字面值的含义和类 型,其中\145表示字符e 字 (a)"WhogoeswithF\145rgus?
\012" 面 (b)3.14e1L 值 (c)1024f 常 (d)3.14L 量 30 变量 变量(variable)提供了一个具名的可供程序操作的存储空间 对象(object)指具有某种数据类型的内存空间,不严格区分是内置还是类类型 也不区分是否命名或是否只读值(value)一般指只读的数据 C++中的每个变量都有其数据类型 数据类型决定着变量所占内存空间的大小和布局方式、该空间能存储值的范围,以及变量能参与的操作 31 变量定义 变量定义的基本形式是: 类型标识符变量名
1,变量名
2,…,变量名n; 定义时还可以为一个或多个变量赋初值,初始化变量的值可以是任意复杂的表达式 //ok:priceisdefinedandinitializedbeforeitisusedtoinitializediscount 变doubleprice=109.99,discount=price*0.16;量初始化和赋值是两个完全不同的操作 初始化的含义是创建变量时赋予其一个初始值 赋值的含义是把对象的当前值擦除,以一个新值来替代 32 列表初始化 C++提供了初始化的多种形式 intunits_sold=0;intunits_sold={0};intunits_sold{0};intunits_sold
(0); 变列表初始化:使用由花括号括起来的一组初始量值来进行初始化的形式定用于内置类型的变量时,如果使用列表初始化 存在丢失信息的风险,则编译器报错 义longdoubleld=3.1415926536; inta{ld},b={ld};//error:narrowingconversionrequiredintc(ld),d=ld;//ok:butvaluewillbetruncated 33 默认初始化 如果定义变量时没有指定初值,则变量被默认初始化 如果内置类型的变量未被显式初始化,其值由定义的位置决定 变定义于任何函数体之外的变量(全局变量)被初量始化为
0 函数体内部的变量(局部变量)将不被初始化 定如果类的对象没有显式初始化,其值由类确定义string类规定如果没有指定初值则生成一个空串 std::stringempty;//emptyimplicitlyinitializedtotheemptystringSales_itemitem;//default-initializedSales_itemobject 34 练习 练习2.9:解释下列定义的含义,对于非法的定义,请说明错在何处并改正 (a)std::cin>>intinput_value;(b)inti={3.14};(c)doublesalary=wage=9999.99; 变(d)inti=3.14;量练习2.10:下列变量的初值分别是什么?定std::stringglobal_str;义intglobal_int; intmain(){ intlocal_int;std::stringlocal_str;} 35 变量声明与定义 声明(declaration)使得名字为程序所知 声明规定了变量的类型和名字 定义(definition)负责创建和名字关联的 变实体 量 除了完成声明的功能外,定义还申请存储空间,也可能为变量赋一个初始值 变量能且只能被定义一次,但是可以被声明多次 36 变量声明与定义 如果想声明一个变量而非定义它,在变量名前添加关键字extern,而且不要显式地初始化变量 变externinti;//declaresbutdoesnotdefineiintj;//declaresanddefinesj 量任何包含了显式初始化的声明即成为定义 externdoublepi=3.1416;//definition 在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误 37 练习 练习2.11:指出下面语句是声明还说定 变义:量(a)externintix=1024; (b)intiy; 声明与定(c)externintiz;义 38 标识符 C++的标识符(identifier)由字母、数字和下划线组成,其中必须以字母或下划线开头 标识符的长度没有限制,但对大小写敏感 //definesfourdifferentintvariables 变intsomename,someName,SomeName,SOMENAME;量不能使用C++的关键字 C++也为标准库保留了一些名字 用户定义的标识符不能连续出现两个下划线,也不能以下划线紧接大写字母开头 定义在函数体外的标识符不能以下划线开头 39 C++关键字 标识符 C++操作符替代名: 40 变量命名规范 标识符要能体现实际含义变量名一般用小写字母,如index,不 要使用Index或INDEX 标用户自定义的类名一般以大写字母开识头,如Sales_item符如果标识符由多个单词组成,则单词 间应有明显区分,如student_loan或,studentLoan,不要使用studentloan 41 变量命名规范 unixlike风格:单词用小写字母,每个单词直接用下划线'_'分割,例如text_mutex, kernel_text_address Windows风格:大小写字母混用,单词连在
标起,每个单词首字母大写。
不过Windows风格 识 如果遇到大写专有用语时会有些别扭,例如命名一个读取RFC文本的函数,命令为 符ReadRFCText,看起来就没有unixlike的 read_rfc_text清晰了 匈牙利命名法:用这种方法命名的变量显示了 其数据类型。
匈牙利命名主要包括三个部分:基本类型、一个或更多的前缀、一个限定词 42 练习 练习2.12:请指出下面名字中哪些是非法的?
(a)intdouble=3.14; 标 (b)int_; 识 (c)intcatch-22; 符 (d)int1_or_2=1; (e)doubleDouble=3.14; 43 名字的作用域 作用域(scope)是程序的一部分,在其中名字有其特定的含义 同一名字在不同作用域中可能指向不 变同的实体量名字的有效区域开始于名字的声明语 句,以声明语句所在的作用域末端为结束尽量在第一次使用变量时再定义它 44 例子 #includeintmain(){ 名intsum=0; //sumvaluesfrom1through10inclusive 字for(intval=1;val<=10;++val)的sum+=val;//equivalenttosum=sum+val std::cout<<"Sumof1to10inclusiveis" 作< //Programforillustrationpurposesonly:Itisbadstyleforafunction //touseaglobalvariableandalsodefinealocalvariablewiththe samename 名intreused=42;//reusedhasglobalscope intmain() 字{的intunique=0;//uniquehasblockscope //output#1:usesglobalreused;prints420 作std::cout<=10;++i) 域sum+=i; std::cout< 类 个对象 型intival=1024;int&refVal=ival;//refValrefersto(isanothername for)ival int&refVal2;initialized //error:areferencemustbe 50 引用即别名 对引用的所有操作都是在与之绑定的对象上进行的 为引用赋值,实际上是把值赋给与引用绑定的对象 获取引用的值,实际上是获取与之绑定的对象的 引值用以引用作为初始值,实际上是以与引用绑定的对 象作为初始值 引用本身不是一个对象,因此不能定义引用的引用 51 引用即别名 intival=1024; int&refVal=ival;//refValrefersto(isanothernamefor)ival refVal=2;//assigns2totheobjecttowhichrefValrefers,i.e.,toival 引 intii=refVal;//sameasii=ival 用//ok:refVal3isboundtotheobjecttowhichrefValisbound,i.e.,toival int&refVal3=refVal; //initializesifromthevalueintheobjecttowhichrefValisbound inti=refVal;//ok:initializesitothesamevalueasival 52 引用的定义 允许在一条语句中定义多个引用,但每个引用标识符都必须以符号&开头 inti=1024,i2=2048;//iandi2arebothints 引int&r=i,r2=i2;anint //risareferenceboundtoi;r2is 用inti3=1024,&ri=i3;//i3isanint;riisareferenceboundtoi3 int&r3=i3,&r4=i2;//bothr3andr4arereferences 53 引用的定义 一般地,引用的类型要和与之绑定的对象严格匹配 一般地,引用只能绑定到对象,不能与字面值或表达式的计算结果绑定 引int&refVal4=10;//error:initializermustbean用object doubledval=3.14;int&refVal5=dval;//error:initializermustbeanintobject 54 练习 练习2.15:下面哪些定义是不合法的? (a)intival=1.01; (b)int&rval1=1.01; (c)int&rval2=ival; 引 (d)int&rval3; 用练习2.17:读代码写结果 inti,&ri=i; i=5;ri=10; std::cout<0,&r1=i;doubled=
0,&r2=d; 引(a)r2=3.14159;(b)r2=r1; 用 (c)i=r2; (d)r1=d; 56 指针 指针(pointer)是“指向”(pointto)另外一种类型的复合类型 指针存放所指向对象的地址 复与引用类似,指针也实现了对其他对合象的间接访问类与引用的不同点: 型 指针本身就是一个对象,允许对指针赋值 和拷贝,可以先后指向几个不同的对象 指针无须在定义时赋初值 块作用域中定义的指针未初始化时,值不定 57 指针的定义 指针类型的声明符写成*d的形式,其
中d是变量名 如果在一条语句中定义了几个指针变量,每个变量前面都必须有符号* 指int*ip1,*ip2;//bothip1andip2arepointerstoint针doubledp,*dp2;//dp2isapointertodouble;dpisa double 58 获取对象的地址 指针存放某个对象的地址 要想获取对象的地址,需要使用取地址符(操作符&) 指 引用不是对象,没有实际地址,不能定义指向引用的指针(例如:int&*p) 针 intival=42; int*p=&ival;//pholdstheaddressofival;pisapointertoival 59 获取对象的地址 一般地,指针的类型要和它指向的对象严格匹配 doubledval; 指double*pd=&dval;//ok:initializeristheaddressofadouble 针double*pd2=pd;//ok:initializerisapointertodoubleint*pi=pd;//error:typesofpiandpddifferpi=&dval;//error:assigningtheaddressofadoubletoapointertoint 60 指针值 指针的值(即地址)应属下列4中状态之一: 指向一个对象 指指空向指紧针邻,对意象味所着占指空针间没的有下指一向个任位何置对象 针 无效指针,上述三种情况之外的其他值 61 利用指针访问对象 使用解引用符(操作符*)来访问指针所指的对象 intival=42;int*p=&ival;//pholdstheaddressofival;pisapointertoival 指cout<<*p;//*yieldstheobjecttowhichppoints;prints42 针给解引用的结果赋值,实际上就是给指针 所指的对象赋值 *p=0;//*yieldstheobject;weassignanewvaluetoivalthroughpcout<<*p;//prints0 62 符号的多重含义 在声明语句中,&和*用于组成复合类型 在表达式中,又作为运算符 inti=42; int&r=i;//&followsatypeandispartofadeclaration;r 指 isareferenceint*p;//*followsatypeandispartofadeclaration;p 针isapointerp=&i;//&isusedinanexpressionastheaddress-of operator *p=i;//*isusedinanexpressionasthedereferenceoperator int&r2=*p;//&ispartofthedeclaration;*isthedereferenceoperator 63 空指针 空指针(nullpointer)不指向任何对象 int*p1=nullptr;//equivalenttoint*p1=0;int*p2=0;//directlyinitializesp2fromtheliteralconstant0//must#includecstdlibint*p3=NULL;//equivalenttoint*p3=0; 预处理变量NULL定义在头文件cstdlib,值就是
0 指nullptr是一种特殊类型的字面值,可以被转换为针任意其他的指针类型 把int变量直接赋给指针是错误的,即使值恰好等于0也不行 intzero=0;pi=zero;//error:cannotassignaninttoapointer 64 初始化所有指针 使用未经初始化的指针是引发运行时错误的一个原因 如果指针变量未被显式初始化时,全局指针被初始化为
0,局部指针未定义 指建议初始化所有的指针,尽量在定义针了对象后再定义指向它的指针 至少初始化为nullptr或者
0 不能用非0的整型字面值给指针赋值或初始化 65 赋值和指针 给指针赋值就是令它存放一个新的地址,从而指向一个新的对象 赋值永远改变的是等号左边的对象 inti=42,ival; int*pi=0;//piisinitializedbutaddressesnoobject 指int*pi2=&i;//pi2initializedtoholdtheaddressofi针int*pi3;//ifpi3isdefinedinsideablock,pi3is uninitialized pi3=pi2;//pi3andpi2addressthesameobject,e.g.,i pi2=0; //pi2nowaddressesnoobject pi=&ival;//valueinpiischanged;pinowpointstoival *pi=0;//valueinivalischanged;piisunchanged 66 其他指针操作 在条件表达式中,如果指针的值为
0,条件取false,否则取true intival=1024;int*pi=0;//piisavalid,nullpointerint*pi2=&ival;//pi2isavalidpointerthatholdstheaddressofival 指if(pi)//pihasvalue0,soconditionevaluatesasfalse //... 针if(pi2)//pi2pointstoival,soitisnot0;theconditionevaluates astrue//... 对两个类型相同的合法指针,可以使用相等(==)和不等(!
=)运算符,结果为bool类型 67 void*指针 void*是一种特殊的指针类型,可用于存放任意对象的地址 doubleobj=3.14,*pd=&obj; //ok:void*canholdtheaddressvalueofanydatapointer 指typevoid*pv=&obj;//objcanbeanobjectofanytype 针pv=pd; //pvcanholdapointertoanytype void*指针可以:拿它和别的指针比较、 作为函数的输入或输出,或者赋给另外一个void*指针 不能直接操作void*指针所指的对象 68 练习 练习2.20:请叙述下面代码的作用 inti=42;int*p1=&i;*p1=*p1**p1; 指针练习2.21:下面定义中有非法的吗? inti=0;(a)double*dp=&i;(b)int*ip=i;(c)int*p=&i; 69 练习 练习2.24:为什么p合法而lp非法? inti=42;void*p=&i;long*lp=&i; 指练法习,请2.3设2:法下将面其代修码改是正否确合法?如果非针intnull=
0,*p=null; 70 理解复合类型的声明 变量定义包括一个基本数据类型和一组声明符 一条定义语句可以定义出不同类型的变量类型修饰符是声明符的一部分 //iisanint;pisapointertoint;risareferencetointinti=1024,*p=&i,&r=i; 71 定义多个变量 理涉及指针或引用的声明,一般有两种解写法 复 把修饰符和变量标识符写在一起 int*p1,*p2;//bothp1andp2arepointerstoint 合把修饰符和类型名写在一起,每条语句只类定义一个变量型int*p1;//p1isapointertoint的声int*p2;//p2isapointertoint 明 72 指向指针的指针 理指针本身是内存中的对象,也有自己解的地址 复**表示指向指针的指针,***表示指向 合指针的指针的指针 类 intival=1024; int*pi=&ival;//pipointstoanint 型的int**ppi=π//ppipointstoapointertoanint 声 明 73 指向指针的指针 理解引用int型指针得到int型对象;解引解用指向指针的指针得到一个指针,两复次解引用才能访问所指向的对象合 cout<<"Thevalueofival\n" 类<<"directvalue:"<练习2.25:说明下列变量的类型 解 (a)int*ip,i,&r=i; (b)inti,*ip=0; 复合(c)int*ip,ip2; 类 型 的 声 明 77 const限定符 const限定的变量在运行时不能改变其值(即,运行时只读常量) const对象创建后其值就不能改变,所以必须初始化 初始值可以是任意复杂的表达式 constintbufSize=512;//inputbuffersize bufSize=512;//error:attempttowritetoconstobject constinti=get_size();//ok:initializedatruntime constintj=42; //ok:initializedpiletime constintk; //error:kisuninitializedconst 78 const const对象仅在文件内有效 默认情况下,const对象被设定为仅在文件内有效 多个文件中出现了同名的const变量时,等同于在不同文件中分别定义了独立的变量 如果想在多个文件间共享const对象,必须在变量的定义和声明前加extern 限//file_definesandinitializesaconstthatisessible定tootherfiles externconstintbufSize=(); 符//file_1.h externconstintbufSize;//samebufSizeasdefinedinfile_ 79 const 练习 练习2.26:下面哪些语句是合法的? (a)constintbuf;(b)t=0;(c)constintsz=t;(d)+t;++sz; 限定符 80 const的引用 const 可以把引用绑定到const对象上,称之为对常量的引用(referencetoconst) 不能通过对常量的引用修改它所绑定的对象 constintci=1024; 限constint&r1=ci;//ok:bothreferenceand定underlyingobjectareconst 符r1=42; //error:r1isareferencetoconst int&r2=ci;constobject //error:nonconstreferencetoa 81 const 初始化 引用的类型必须与其所引用对象的类型一致,但有两个例外 第一种例外情形:初始化常量引用时允许用任意表达式作为初始值,只要该表达式结果能被转换成引用的类型 允许常量引用绑定非常量的对象、字面值,甚至 的是个一般(右值)表达式 inti=42; 引constint&r1=i;//wecanbindaconstint&toaplainint用object constint&r2=42;//ok:r1isareferencetoconstconstint&r3=r1*2;//ok:r3isareferencetoconstint&r4=r1*2;//error:r4isaplain,nonconstreference 82 const 初始化 当一个常量引用绑定到另外一种类型时,实际上绑定到一个临时对象 临时(temporary)对象是编译器暂存表达式的求值结果时临时创建的一个未命名对象 doubledval=3.14; 的constint&ri=dval;引编译器把上述代码转换为:用constinttemp=dval;//createatemporaryconstint fromthedoubleconstint&ri=temp;//bindritothattemporary 83 const 引用非const对象 常量引用仅对引用可参与的操作做出了限定(只读),但对于引用的对象本身是不是一个常量未作限定 inti=42; int&r1=i;//r1boundtoi 的constint&r2=i;//r2alsoboundtoi;butcannotbe引usedtochangei 用r1=0; //r1isnotconst;iisnow0 r2=0; //error:r2isareferencetoconst 84 指针和const 指向常量的指针(pointertoconst)不能用于改变其所指对象的值(只读指针) 要想存放常量对象的地址,只能使用指向常量的指针 constdoublepi=3.14;//piisconst;itsvaluemaynotbechanged double*ptr=π//error:ptrisaplainpointer constdouble*cptr=π//ok:cptrmaypointtoadoublethatisconst *cptr=42; //error:cannotassignto*cptr 85 指针和const 指针的类型必须与其所指对象的类型一致,但有两个例外 第一种例外情形:允许一个指向常量的指针指向一个非常量对象 指向常量的指针(只读指针)仅仅要求不能通过该指针改变对象的值 doubledval=3.14;canbechanged //dvalisadouble;itsvalue constdouble*cptr=&dval; //ok:butcan't changedvalthroughcptrof‘constdouble*’ 86 const指针 const 常量指针(constpointer):允许把指针本身定义为常量 指 把const放在*后用以说明指针是一个常量 针常量指针必须初始化,之后其值不能 和再改变(无法再指向其他对象) interrNumb=0; int*constcurErr=&errNumb;//curErrwillalwayspointtoerrNumb constdoublepi=3.14159; constdouble*constpip=π//pipisaconstpointertoaconstobject 87 const指针 能否通过常量指针修改其所指对象的值,取决于所指对象的类型 指向常量的常量指针,不能修改其所指对象 指的值;而指向非常量的常量指针可以修改 constdoublepi=3.14159; 针constdouble*constpip=π *pip=2.72;//error:pipisapointertoconst 和//iftheobjecttowhichcurErrpoints(i.e.,errNumb)isnonzero interrNumb=
0,*constcurErr=&errNumb;if(*curErr){ errorHandler();*curErr=0;//ok:resetthevalueoftheobjecttowhichcurErrisbound} 88 const 练习 练习2.27:下面哪些初始化是合法的? (a)inti=-
1,&r=0; 指(b)int*constp2=&i2; (c)constinti=-
1,&r=0; 针(d)constint*constp3=&i2;和(e)constint*p1=&i2; (f)constint&constr2;(g)constinti2=i,&r=i; 89 const 练习 const 练习2.28:解释 如下定义,指出 指其中不合法的 针 (a)inti,*constcp; 和 (b)int*p1,*constp2; (c)constintic,&r=ic; (d)constint*constp3; (e)constint*p; 练习2.29:对上题定义的变量,哪些赋值是合法的? (a)i=ic;(b)p1=p3;(c)p1=⁣(d)p3=⁣(e)p2=p1;(f)ic=*p3; 90 顶层和底层const 顶层-levelconst)表示对象本身是const常量,对任何数据类型都适用 底层const(low-levelconst)表示指向(引用)的对象是const,与指针和引用等复合类型的基本类型部分相关 指针类型可能有独立的顶层和底层const 引用类型只可能有底层const 91 顶层和底层const inti=0;int*constp1=&i;//wecan'tchangethevalueofp1;const-levelconstintci=42;//wecannotchangeci;constlevelconstint*p2=&ci;//wecanchangep2;constislowlevelconstint*constp3=p2;//right-mostconstlevel,left-mostisnotconstint&r=ci;//constinreferencetypesisalwayslow-level 92 顶层和底层const 拷贝对象时,顶层const被忽略 拷贝对象时不会改变被拷贝对象的值 inti=0;constintci=42;i=ci;//ok:copyingthevalueofci;-levelconstinciisignoredconstint*p2=&ci;constint*constp3=p2;p2=p3;//ok:pointed-totypematches;-levelconstinp3isignored 93 顶层和底层const 拷贝对象时,底层const从不忽略 拷入和拷出的对象必须具有相同的底层const属性,或者两个对象的类型能转换 非常量可以转化为常量,反之则不行 94 顶层和底层const inti=0;constintci=42;constint*p2=&ci;constint*constp3=p2;int*p=p3;//error:p3hasalow-levelconstbutpdoesn'tp2=p3;//ok:p2hasthesamelow-levelconstqualificationasp3p2=&i;//ok:wecanconvertint*toconstint*int&r=ci;//error:can'tbindanordinaryint&toaconstintobjectconstint&r2=i;//ok:canbindconstint&toplainint 95 练习 练习2.30:下列对象是否被声明为顶层 顶或底层const constintv2=0;intv1=v2; 层int*p1=&v1,&r1=v1;和constint*p2=&v2,*constp3=&i,&r2=v2;底练习2.31:对上题中的声明,下面哪些层赋值是合法的? r1=v2;p1=p2;p2=p1;p1=p3;p2=p3; 96 const constexpr和常量表达式 常量表达式(constexpression)是指编译时就能求值且值不会改变的表达式 字面值是常量表达式 用常量表达式初始化的const对象也是 一个对象(或表达式)是不是常量表达式由其类型和初始值共同决定 constintmax_files=20;//max_filesisaconstantexpression constintlimit=max_files+1;//limitisaconstantexpression intstaff_size=27;expression //staff_sizeisnotaconstant constintsz=get_size();//szisnotaconstantexpression 97 constexpr变量 constexpr 可将变量声明为constexpr以便让编译器来验证变量是否为常量表达式 声明为constexpr的变量必须用常量表达式来初始化,该变量隐含为const 和 不能用普通函数作为constexpr变量的初值 常 constexprintmf=20;//20isaconstant 量 expression 表 constexprintlimit=mf+1;//mf+1isaconstantexpression 达 constexprintsz=size();//okonlyifsizeisa 式 constexprfunction 98 字面值类型 constexpr 常量表达式的值需要在编译时计算得到,声明constexpr的类型有限制 可被声明为constexpr的类型称为字面值 类型(literaltype) 和 算术类型、指针、引用为字面值类型 常量 自定义类型不属于字面值类型 表constexpr指针(引用)的初始值必须是 达nullptr或者
0,或者指向(引用)存储式于某个固定地址的对象 99 constexpr 指针和constexpr 在constexpr声明中定义一个指针,constexpr仅对指针有效,与指针所指对象的类型无关 constexpr把它定义的变量置为顶层const constint*p=nullptr;//pisapointertoaconstintconstexprint*q=nullptr;//qisaconstpointertoint constexpr指针可以指向常量或非常量对象 和intj=0;常constexprinti=42;//typeofiisconstint量//iandjmustbedefinedoutsideanyfunction constexprconstint*p=&i;//pisaconstantpointertotheconst 表inti达式constexprint*p1=&j;//p1isaconstantpointertotheintj 100 类型别名 类型别名(typealias)是一个名字,它是某种类型的同义词 传统的方法使用关键字typedef 处typedefdoublewages;//wagesisasynonymfor理double类typedefwagesbase,*p;//baseisasynonymfor 型 double,pfordouble* 声明符中可以包含类型修饰符 101 类型别名 新的方法使用别名声明(aliasdeclaration)来定义类型的别名: usingSI=Sales_item;//SIisasynonymforSales_item 处以关键字using开始,其后跟别名和等号,理其作用是把等号左边的名字声明为等号右类侧类型的别名型只要是类型名能出现的地方,就可以 使用类型别名 wageshourly,weekly;//sameasdoublehourly,weekly; SIitem; //sameasSales_itemitem 102 指针、常量和类型别名 把指代复合类型或常量的类型别名用到声明语句中时,常会产生意想不到的结果 typedefchar*pstring;//pstringisasynonymforchar* 类constpstringcstr=0;//cstrisaconstantpointertochar constpstring*ps; 型tochar //psisapointertoaconstantpointer 别把pstring看作基本类型,constpstring表示指名向char的常量指针,非指向constchar的指针 不能简单地直接进行变量名替换 constchar*cstr=0;//wronginterpretationofconstpstringcstr 103 auto类型说明符 auto类型说明符让编译器通过初始值来推断变量的类型 auto变量必须有初始值 //thetypeofitemisdeducedfromthetypeoftheresultof 处addingval1andval2理autoitem=val1+val2;//iteminitializedtotheresultof val1+val2 类使用auto能在一条语句中声明多个变量型所有变量的初始值必须有相容的基本类型 autoi=
0,*p=&i;//ok:iisintandpisapointertointautosz=0,pi=3.14;//error:inconsistenttypesforszandpi 104 auto 复合类型、const和auto 编译器推断出来的auto类型有时候和初始值的类型并不完全一样 编译器以引用对象的类型作为auto的类型 inti=
0,&r=i;autoa=r;//aisanint(risanaliasfori,whichhastypeint) 类auto一般会忽略顶层const,保留底层const型constintci=i,&cr=ci; autob=ci;//bisanint-levelconstinciisdropped) 说autoc=cr;//cisanint(crisanaliasforciwhoseconst明level)符autod=&i;//disanint*(&ofanintobjectisint*) autoe=&ci;//eisconstint*(&ofaconstobjectislow-levelconst) 105 auto 复合类型、const和auto 如果希望推断出来的auto类型是一个顶层const,需要显式说明: inti=0;constintci=i;constautof=ci;//deducedtypeofciisint;fhastype 类constint型声明auto类型的引用时,初始值的顶层const 属性仍然保留(在新类型中成为底层const) 说auto&g=ci;//gisaconstint&thatisboundtoci明auto&h=42;//error:wecan'tbindaplain referencetoaliteral 符constauto&j=42;//ok:wecanbindaconstreference toaliteral 106 复合类型、const和auto auto &和*只从属于某个声明符,非基本类型的一部分 初始值必须有相容的auto推断的类型 inti=0; 类constintci=i;型autok=ci,&l=i; //kisint;lisint& auto&m=ci,*p=&ci;//misaconstint&;pisa 说pointertoconstint明//error:typededucedfromiisint;typededucedfrom符&ciisconstint auto&n=i,*p2=&ci; 107 auto 练习 inti=
0,&r=i; 练习2.33:定义 autoa=r; constintci=i,&cr=ci; autob=ci; 类autoc=cr;型autod=&i;说autoe=&ci;明符auto&g=ci; 如左,判断下列赋值的运行结果 a=42;b=42;c=42;d=42;e=42;g=42; 108 auto 练习 练习2.35:由下列定义推断出的类型是什么? constinti=42;autoj=i; 类constauto&k=i;型auto*p=&i;说明constautoj2=i,&k2=i;符 109 decltype类型说明符 decltype(表达式)返回表达式的类型,但 并不对表达式求值 decltype(f())sum=x;//sumhaswhatevertypefreturns 处 若decltype使用的表达式是一个变量,则返回该变量的类型,包括顶层const和引 理用在内 类 引用都是作为其绑定对象的同义词出现,只有在decltype处是例外 型 constintci=
0,&cj=ci; decltype(ci)x=0;//xhastypeconstint decltype(cj)y=x;//yhastypeconstint&andisboundtox decltype(cj)z;//error:zisareferenceandmustbeinitialized 110 decltype decltype和引用 把decltype应用到一个不是变量的表达式时,返回表达式结果对应的类型 有些表达式向decltype返回一个引用类型 //decltypeofanexpressioncanbeareferencetypeinti=42,*p=&i,&r=i; 类decltype(r+0)b;//ok:additionyieldsanint;bisan (uninitialized)int 型decltype(*p)c;//error:cisint&andmustbe说initialized明解引用操作返回引用类型(左值),所以符decltype(*p)的类型是int&,而非int 111 decltype decltype和引用 decltype((variable))(变量名加一层或多层括号)的结果永远是引用 decltype(variable)只有当variable本身是一个引用时,结果才是引用 类//decltypeofaparenthesizedvariableisalwaysa reference 型inti=42;说decltype((i))d;//error:disint&andmustbe明initialized符decltype(i)e;//ok:eisan(uninitialized)int 112 decltype 练习 练习2.36:指出下面代码中每个变量的类型以及程序结束时各自的值 inta=3,b=4;decltype(a)c=a; 类decltype((b))d=a;型++c;说++d;明符 113 decltype 练习 练习2.37:赋值是会产生引用的又一类表达式,引用的类型就是左侧运算数(左值)的类型。
也就是说,如果i是int,则表达式i=x的类型是int&。
请指 类出下面代码中每个变量的类型和值。
型inta=3,b=4;说decltype(a)c=a;明decltype(a=b)d=a;符 114 自定义数据结构 数据结构是指把一组相关的数据元素组织起来的方法以及使用这些数据的策略 例如,Sales_item类把书本的ISBN号、销售册数及销售额等数据组织在一起,并且提供了诸如isbn函数、>>、<<、+、+=等运算在内的一系列操作 115 定义Sales_data类型 把Sales_item类的数据元素组织在一起 自定义一个简单些的类Sales_data 定 structSales_data{ 义 std::stringbookNo; 数 unsignedunits_sold=0; 据 doublerevenue=0.0; 结 };类体由花括号包围形成了一个类作用域 构 类内部定义的名字必须唯
一,但是可以与 类外部定义的名字重复 116 定义Sales_data类型 结束类体的右花括号后必须跟分号 自 可以在类体后直接定义对象 定 但最好不要把对象定义和类定义放在一起 义 struct
Sales_data{/*...*/}um,trans, 数 *salesptr; 据 //equivalent,butbetterwaytodefinethese 结objects 构 structSales_data{/*...*/};Sales_dataum,trans,*salesptr; 117 Sales_data 类数据成员 定类的数据成员(datamember)定义了类的义对象的具体内容,每个对象有自己的 一份数据成员拷贝 定义数据成员的方法和定义普通变量一样可以为数据成员提供一个类内初始值(in- classinitializer) 创建对象时,类内初识值用于初始化数据成员;没有初始值的成员将被默认初始化 类–定义Sales_data对象时,units_sold和revenue都将被型初始化为0,bookNo被初始化为空字符串 118 使用Sales_data类 0-201-78345-X320.00 0-201-78345-X225.00 自写一段程序实现打印两笔交易记录相加结定果的功能义#include #include 数#include“Sales_data.h” intmain() 据{结Sales_datadata1,data2; 构 //1.codetoreadintodata1anddata2//2.codetocheckwhetherdata1anddata2havethesameISBN //andifsoprintthesumofdata1anddata2 } 120 Sales_data对象读入数据 Sales_data string类提供了>>、<<和==等,功能分别 使是读入字符串、写出字符串和比较字符串 用 doubleprice=0;//priceperbook,usedtocalculatetotalrevenue//readthefirsttransactions:ISBN,numberofbookssold,priceper book std::cin>>data1.bookNo>>data1.units_sold>>price; //calculatetotalrevenuefrompriceandunits_sold data1.revenue=data1.units_sold*price; //readthesecondtransaction std::cin>>data2.bookNo>>data2.units_sold>>price; data2.revenue=data2.units_sold*price; 类 交易记录的是书售出的单价,而数据结构存储总销售额 121 输出两个Sales_data 对象的和 Sales_data 使用 类 检查两笔交易涉及的ISBN是否相同。
如果相同输出它们的和,否则报错 if(data1.bookNo==data2.bookNo){unsignedtotalCnt=data1.units_sold+data2.units_sold;doubletotalRevenue=data1.revenue+data2.revenue;//print:ISBN,totalsold,totalrevenue,averagepriceperbookstd::cout<=0)std::cout<常用技术是预处理器(preprocessor) 写预处理器是在编译之前执行的一段程自序,可以部分地改变我们写的程序 己 的 当预处理器看到#include标记时,会用指定的头文件的内容来代替#include 头 文 件 124 预处理器概述 C++程序使用预处理器来定义头文件保护 编符(headerguard) 写 头文件保护符依赖于预处理变量,预处理变量有两种状态 自 已定义(define)和未定义(undefined) 己#define指令把一个名字定义为预处理变量 的#ifdef指令当且仅当预处理变量已定义时 头为真 文 #ifndef指令当且仅当预处理变量未定义时为真 件一旦检查为真,则执行#ifdef或#ifndef后 的操作直到遇到#endif指令 125 头文件例子 #ifndefSALES_DATA_H#defineSALES_DATA_
H 编#include写structSales_data{ std::stringbookNo; 自unsignedunits_sold=0;己doublerevenue=0.0; 的}; 头 #endif 整个程序中预处理变量包括头文件保 文护符必须唯
件 一般把预处理变量的名字全部大写 126

标签: #内容 #程序 #工程师 #模型 #框架 #国内 #主板 #腹部