《C++语法大全.ppt》由会员分享,可在线阅读,更多相关《C++语法大全.ppt(141页珍藏版)》请在三一办公上搜索。
1、第3章 C+基本语法,主要内容,3.1 数据类型,程序中的各种加工和处理都是针对某些数据进行的,这些数据由数据类型描述。数据类型规定了数据的存储结构(在内存中占据的大小和布局)、可以进行的运算、取值范围。C+中的数据类型大致分为三类:C+预定义的一组内置的基本数据类型,表示常见的简单数据,如整数、浮点数等;复合类型,由基本数据类型组合而成的更复杂的数据类型,如数组、结构体、联合、枚举等;类类型,即用户自己定义的抽象数据类型。为了方便程序员,C+标准库中还提供的一些常用的抽象数据类型。,3.1.1 内置数据类型,字符类型字符型char,通常用来表示单个字符和小整数。整数类型整型int、短整型sh
2、ort、长整型long,分别代表不同长度的整数值char、short、int和long类型都可以用signed和unsigned修饰浮点类型浮点型float、双精度浮点型double和长双精度long double布尔类型bool类型只有两个值:true和false。-bool类型、char类型、各种整数类型通称为整值类型。整值类型和浮点类型一起被称为算术类型。,内置数据类型的空间大小,标准C+对内置数据类型的空间大小并没有做出严格规定,但为了编写可移植的代码,应该了解你所使用的编译器和机器,避免对这些特性做出某种假定。如下代码可以测试C+编译器为每种数据类型分配的空间大小:,#include
3、 using namespace std;int main()cout sizeof(char)endl;cout sizeof(int)endl;cout sizeof(float)endl;cout sizeof(double)endl;cout sizeof(bool)endl;return 0;,Visual C+6.0和DEV-C+结果:14481,3.1.2 指针类型,指针持有一个对象的地址,通过指针可以间接操作这个对象。指针的典型用法:构建链式的数据结构,如链表和树管理程序执行时动态分配的对象作为函数的参数每个指针都有相关的类型,需要在定义指针时指出。不同类型的指针的表示方法和保
4、存的地址值并没有分别,区别只是在于指针指向的对象类型不同。指针的类型指出了如何解释该内存地址保存的内容,以及该内存区域应该有多大。例如:int*pi;/指向整型的指针,如指向内存地址是1000,则跨越的地址空间是10001003 char*pc;/指向字符型的指针,如指向内存地址是1000,则只占据1000这个字节的区域,空指针,指针值为0时表示它不指向任何对象,即空指针。指针不能保存非地址值,也不能被赋值或初始化为不同类型的地址值。,int ival=100;int*pi=/编译错误,通用指针,C+提供了一种通用指针,即void*指针,它可以持有任何类型的地址值。不能操纵void指针指向的对
5、象,只能传送该地址值或和其他地址进行比较。C+也不允许void指针到其他类型指针的直接赋值。,int a=10;char ch=k;void*pv=/错误,应该使用pi=(int*)pv,通过解引用操作(*)可以间接访问指针指向的对象。,int x=100,y=20;int*pi=/x=y,指针的算术运算,指针可以进行加或减整数值的算术运算,这时地址值增加数目取决于指针的类型。指针只有在指向数组元素时,其算术运算才有意义。,int a=10;char ch=k;int*pi=/在原地址值上加1;因为char占1个字节,3.1.3 引用类型,引用又称为别名,它可以作为对象的另一个名字。通过引用我
6、们可以间接操纵对象,使用方式类似于指针,但是不需要指针的语法。在程序中,引用主要用作函数的形参。引用由类型标识符和一个取地址符(&)来定义,引用必须被初始化。,int ival=100;/OK,refVal是指向ival的引用int/Error,不能用没有内存地址的数值来初始化引用,引用的注意事项(1),引用一旦定义,就不能再指向其他的对象,对引用的所有操作都会被应用在它所指向的对象上。例如:int x=100,y=20;int/r不是y的引用,而是x=y,引用的注意事项(2),注意引用的初始化和赋值极为不同:初始化时引用“指向”一个对象,赋值时,引用被作为所指对象的别名。虽然C+标准没有规定
7、引用的实现方式,但是在很多C+编译器中,引用被实现为与所指对象占据同一地址空间,例如下面的代码:,#include using namespace std;int main()int a=10;int,在GNU C+编译环境的输出结果如下:a=10&a=0 x22ff34ra=10&ra=0 x22ff34a=20&a=0 x22ff34ra=20&ra=0 x22ff34,引用与指针的差别(1),定义与初始化指针的定义形式:类型*指针变量;指针的初始化:int x=10,y=20;int*pi;/可以不初始化pi=,引用与指针的差别(2),使用方式指针通过解引用(*)运算间接访问指向的对象;
8、引用作为对象的别名,可以直接访问对象。例如:pi=/a=40,引用与指针的差别(3),指针可以不指向任何对象,引用必须指向一个对象。pi=0;/pi是空指针,不指向任何对象ri=0;/a=0,引用与指针的差别(4),指针之间的相互赋值会改变指向关系;引用之间的相互赋值是它们指向的对象之间的赋值,引用关系本身并不改变。int x=100,y=20;int*p1=/x y,r1 仍是x 的引用,3.1.4 数组,数组是一个单一数据类型对象的集合。其中的单个对象没有命名,但可以通过它在数组中的位置进行访问,即下标访问。例如:/ia是包含10个int对象的数组 int ia10;/数组中下标为3的元素
9、被赋值为7 ia3=7;,定义数组,定义数组时需要指定类型名、数组名标识符和数组大小。数组大小是一个不小于1的常量表达式。数组元素的下标从0开始,到数组大小1。但是,C+并不提供对数组下标范围的检查,需要程序员自己保证正确性。定义数组的同时可以对数组进行初始化,初始值放在花括号中,用逗号隔开。int ia3=1,2,3;int ib=4,5,6,7;int ic10=0,1,2;,数组的注意事项,一个数组不能被另一个数组初始化,也不能被直接赋值给另一数组。C+也不允许声明一个引用数组,例如:int ia3=1,2,3;int ib=ia;/!Error int/OK,C风格字符串,C+保留了C
10、语言中用字符数组表示字符串的方式,称为C风格字符串。可以通过库函数对这样的字符串进行操作。需要包含标准库头文件,多维数组,定义多维数组,每一维的大小由一对方括号指定。例如:int ia43;访问多维数组的元素要指定每一维的下标。例如:ia12=5;多维数组也可以被初始化:int ia32=0,1,2,3,4,5;,数组与指针,数组名字代表数组第一个元素的地址,它的类型是数组元素类型的指针。例如对下面的数组定义:int ia5;ia是一个int*类型,ia和,3.1.5 结构体,结构体(struct)把一组来自不同类型的数据组合在一起构成复合类型,其中的每个数据都是结构体的成员,在内存中依次存放
11、。结构体的成员不能单独使用,必须由结构体类型的变量通过成员选择运算符“.”来选择,或者由结构体类型的指针通过“”运算符选择。定义结构体类型之后,可以创建该类型的许多实例。例如:,结构体变量内存中的大小(1),结构体变量的成员在内存中依次存放,因而,原则上,结构体变量在内存中的大小是其所有成员的大小之和。但是,为了提高访问效率,大多数编译器实际上都使用了边界对齐技术。struct Y char c;int i;Y st;上面的变量st在内存中占据几个字节呢?是5吗?,结构体变量内存中的大小(2),在GCC编译器下,sizeof(Y)的结果是8。,3.1.6 联合(共用体),union和struc
12、t的语法类似,只是数据成员的存储方式不同。union的每个成员都是从联合变量的首地址开始存储,所以每次只能使用一个成员。使用union可以节省空间,但是容易出错。union Packed char c;int i;float f;double d;/联合的大小是其中double的大小/因为double是占据空间最大的元素 Packed x;x.c=a;/其余成员现在不可使用 x.d=3.14;/覆盖了成员c的内容,联合的内存布局,3.1.7 枚举,枚举定义了一组命名的整数常量,从而提高代码的可读性。例如:enum ShapeType circle,square,rectangle;ShapeT
13、ype枚举类型定义了3个常量:0,1,2 分别和名字circle,square以及rectangle关联。ShapeType是一个枚举类型,可以用它来定义枚举变量,变量的值只能是枚举成员。也可以自己指定枚举成员的值:enum ShapeTypecircle10,square20,rectangle;未指定值的枚举成员,编译器会赋给它相邻的下一个整数值,所以rectangle成员的值是21。枚举类型在必要时,如参与算术运算,会被自动提升为算术类型。枚举的成员名字是不可打印的,输出的是它所表示的整数值。另外,不能使用枚举成员进行迭代,C+不支持枚举成员之间的前后移动。,3.1.8 类类型,除了内置
14、类型和复合类型之外,C+还允许用户自己定义类类型,并且在标准库中预定义了一些常用的类型。这里先简单介绍几种常用的标准类型。输入输出流iostream 字符串类 标准数组向量类,输入输出流iostream,输入输出操作是由iostream类提供的,使用iostream需包含标准库头文件:#include iostream库中有两个预定义的对象:cin,istream类型的对象,用于从用户终端读入数据。cin的常用方式为:cin 变量名;cin 变量名1 变量名2;cin 变量名1 变量名2 变量名n;cout,ostream类型的对象,用于向用户终端写数据。cout 的常用方式为:cout 表达
15、式;cout 表达式 endl;cout 表达式1 表达式2 表达式n;,输入输出流iostream,#include using namespace std;int main()int ival;float fval;cin ival;cin fval;cout ival fval;cout ival n fval endl;,字符串类string,除了保留C风格字符串char*之外,C+标准库还定义了字符串类string。string类支持字符串对象的各种初始化方式,支持字符串之间的拷贝、比较和连接等操作,还支持对字符串长度的查询和是否为空的判断,并且也可以访问字符串中的单个字符。使用st
16、ring类,需要包含相应的头文件:string。#include,字符串类string,#include#include using namespace std;int main()string s1,s2;/创建两个空字符串对象 string s3=Hello,World!;/初始化s3 string s4(I am);s2=“Today”;/赋值 s1=s3+s4;/字符串连接 s1+=5;/末尾追加 cout s1+s2+!endl;/输出字符串内容 cout Length of s1 is:s1.size()endl;/输出字符串长度 for(int i=0;I s1.size();+
17、i)cout s1i;/逐个输出s1中的字符,字符串类string,字符串比较使用运算符“=”获得字符串长度使用size()判断字符串是否为空使用empty()可以将一个C风格的字符串赋给string对象,但反之不可。要将string对象转换为C风格字符串,使用c_str()操作,其返回结果为const char*,即转换得到的C风格字符串首地址。例如:string s1=“This is a book.”;int x=strlen(s1);/Errorx=strlen(s1.c_str();/OK,标准数组向量类,C+标准库中的vector类为内置数组类提供了一种替代表示。为了使用vecto
18、r,我们必须包含相关的头文件:vector。vector可以像数组一样使用,还可以以STL方式使用。/数组习惯#include using namespace std;int main()vector iv(10);int ia10;for(int id=0;id10;id+)iaid=ivid;/,向量类:STL使用习惯,/STL习惯#include#include using namespace std;int main()vector iv;for(int id=0;id10;id+)iv.push_back(id);for(int id=0;idiv.size();id+)coutiv
19、id;/,3.2.1 内置数据类型的文字常量,当一个数值,例如5,出现在程序中时,它被称为文字常量(literal constant)。“文字”是因为只能以它的值的形式指代它。“常量”是因为它的值不能被改变。文字常量是不可寻址的。每个文字常量都有相应的类型,其类型由其形式、取值和后缀决定。,整数文字常量,整数文字常量可以表示为十进制、八进制或十六进制的形式。例如23可以写成:23/十进制 027/八进制 0 x17/十六进制十进制整数文字常量默认类型是int,如果数值超出int能够表示的范围,那么其类型是long。八进制和十六进制整数文字常量的类型是int、unsigned int、long、
20、unsigned long中第一个范围足够表示该数值的类型。可以在文字常量后面加“L”或“l”后缀将其指定为long类型。可以加“U”或“u”将其指定为无符号数。如:116u 120UL 2L,浮点型文字常量,浮点型文字常量可以写成普通的十进制形式或科学计数法形式。例如浮点数235.8可以表示为:235.8 2.358E2 浮点型文字常量默认为double类型,也可以加后缀改变其类型。float类型的浮点文字常量可以在后面加“F”或“f”标示,后缀“L”或“l”则为long double类型。3.14F 1.24f 2.5E3L,布尔型文字常量,bool型的文字常量只有true和false。,
21、字符型文字常量,字符型文字常量是用单引号括起来的单个字符或以斜线开头的转义字符,如a,n。一些常用的转义字符如:,字符串文字常量,在程序中经常出现的还有用双引号括起来的字符序列,即字符串文字常量,例如hello world,其默认类型是const char*。,3.2.2 变量和标识符变量,变量为我们提供了一个有名字的存储区,可以通过代码对其进行读、写处理。变量有时也被称为对象。每个变量都有特定的数据类型,这个类型决定了相关内存的大小、布局、能够存储在该存储区的值的范围以及可以应用在其上的操作。例如:int count;double salary;,3.2.2 变量和标识符标识符,引用变量要通
22、过其名字,而变量由标识符命名。标识符可以由字母、数字以及下划线组成,但必须由字母或下划线开头,并且区分大小写字母。上面代码中count和salary都是标识符。C+保留了一些词用作关键字,关键字不能作为程序的标识符使用。,C+关键字,变量的命名规则(1),变量名字要完全、准确地描述出该变量所代表的事物。变量名不能过短太短的名字无法传达足够的信息,也不能过长太长的名字很难写且不实用。研究表明,变量名的最佳长度是9到15个字符。使用i、j、k这些名字作为循环变量是约定俗成的,但不要在其他场合使用。给布尔变量赋予隐含“真/假”含义的名字,如done,error,found,success或ok等。,
23、变量的命名规则(2),常量、typedef和预处理宏全部大写;类和其他类型的名字混合大小写;变量名和函数名中第一个单词小写,后续每个单词首字母大写,如variableOrRoutineName。除了在特定前缀中,不要用下划线作为名字中的分隔符,如student_name,用studentName更好。应该避免使用这些名字:令人误解的名字或缩写,具有相似含义的名字,带有数字的名字,拼写错误的单词,仅靠大小写区分的名字,混用多种自然语言(如汉语拼音和英语),标准类型和函数的名字。避免在名字中包含易混淆的字符:例如,数字一(1)、小写字母L(l)和大写字母i(I),数字0和大小写的字母O(o),数字
24、2和字母z。,变量的右值和左值,变量和文字常量的区别在于变量是可寻址的,对于每个变量,都有两个值与之关联:它的数据值,存储在某个内存地址中。有时也被称为右值。文字常量和变量都可以被用作右值。它的地址值,即存储数据值的那块内存的地址。有时被称为变量的左值。在下面的赋值表达式中:count=count+5变量count同时出现在赋值操作的左边和右边。右边的变量被读取,读出其关联的内存中的数据值。而左边的count用作写入,原来的值会被加法操作的结果覆盖。在这个表达式的赋值号右边,count和“5”用作右值,而左边的count用作左值。,变量的定义与声明定义变量,变量的定义会引起相关内存的分配,因为
25、一个变量只能在内存中占据一个位置,所以程序中的每个变量只能定义一次。变量定义的一般格式为:类型 名字;也可以一次定义多个同类型变量,如下:类型 名字1,名字2;例如:int ival;ival=5;/定义ival后就可以使用ivalint a,b,c;/定义三个int变量a,b,c,变量的定义与声明声明变量,如果在一个文件中定义了一个变量,其他的文件还想使用这个变量,就必须声明该变量。变量声明(declaration)的作用是使程序知道该变量的类型和名字。声明不会引起内存分配,程序中可以包含对同一变量的多个声明。声明全局变量格式:extern 类型 变量名;,变量的定义与声明声明变量,/mod
26、ule0.cppint k=2;/定义变量k/module1.cpp#include/声明变量k/说明了在module1.cpp之外的某处有k的定义extern int k;int main()int t=3;/定义变量t,同时也是声明 k=t+2;/使用变量k,变量的初始化,定义变量的同时可以为变量提供初始值,否则对于全局变量,系统会自动提供初始值0,而局部变量是未初始化的。因为引用未初始化变量是程序中常见的错误,且不易被发现,因此建议为每个定义的变量提供一个初始值。C+支持两种形式的初始化:使用赋值操作符的显式语法形式(也叫赋值初始化):int value=1024;char ch=t;将
27、初始值放在括号中的隐式形式(也叫直接初始化):int value(1024);char ch(t);,3.2.3 const限定词,由const限定的对象不可改变。const在C+中用法非常多,主要有:限定一个对象(变量)限定指针限定引用类的成员函数参数&返回值,限定一个对象,程序中经常会使用某些常数值,如数组的大小。可是程序代码中如果充斥着这些数值,会降低程序的可读性和可维护性。C语言中我们使用预处理指令#define定义符号常量,但是这种常量的缺点在于它只是作简单的字符串替换,没有类型检查。C+中引入了const限定符,它将一个对象限定为常量。如:const int bufSize=102
28、4;企图修改这个值会导致编译错误。因为常量在定义后不能修改,所以必须进行初始化。,限定指针,首先回顾一下指针:,#include using namespace std;int main()int ival=1024;int*pi=,DEV-C+结果如下:sizeof(pi):4sizeof(ival):4&pi:0 x22ff70pi:0 x22ff74&ival:0 x22ff74*pi:1024ival:1024,限定指针,从程序结果可以看出:指针在内存中占4个字节,首地址是0 x22ff70,其中存放的是它所指向内容的首地址,int型变量ival在内存中占4个字节,首地址是0 x227
29、4,这块内存存放的是ival的值1024。,问题:在这个例子中,如果我们不允许修改ival的值(即1024),怎么办呢?显然可以将ival定义成常量:const int ival=1024;那么能否通过间接方式修改一个常量呢?例如:const int ival=1024;int*pi=/可以修改吗?,指向常量的指针(1),这段代码会导致编译错误,理由并不是试图通过指针间接修改const,而是“试图将一个const地址赋值给一个非const指针”。要保存ival的地址,只能将pi定义成一个指向const int 的指针,成为指向常量的指针:const int ival=1024;const in
30、t*pi=/Error,指向常量的指针(2),在上面的代码中,pi是一个指向常量的指针,它所指向的内存中的内容不可以改变。,指向常量的指针(3),指向常量的指针(4),注意:pi是一个指向常量的指针,但pi本身的值可以改变,指向另一个const int。例如:,#include using namespace std;int main(int argc,char*argv)const int ival=1024;const int*pi=,运行结果:&pi:0 x22ff70pi:0 x22ff74&ival:0 x22ff74&pi:0 x22ff70pi:0 x22ff6c&ival:0
31、x22ff6c,指向常量的指针(6),程序运行中的指针变化情况:,指向常量的指针(7),C+允许将一个非const地址赋值给const指针,例如:int ival=1024;const int*pi=,我们也可以定义指向非const 对象的指针常量,该指针所在内存的值不允许改变即该指针一旦用某个单元的地址值初始化,那么指针值就不能再改变,但它所指向单元的值可以改变,语法如下:int ival=1024;int*const pi=/!Error不能改变pi的值,指向非const对象的const指针(1),指向非const对象的const指针(2),指向const对象的const指针,const
32、int ival=5;const int*const pi=/pi是一个指向const对象的const指针在pi的定义中:第一个const限定int,表示指针指向的单元是常量;第二个const限定pi,表示指针的值也是一个常量。因此该指针所在内存的值不允许改变,它所指向内存的值也不能改变。,限定引用,const也可以限定引用,const引用可以用不可寻址的值初始化,如:int/OK/编译器生成一个值为10的临时对象,rc指向这个对象除了限定对象、引用和指针,const的另一个用途是限定函数的形式参数,由const限定的参数在函数体中不能被修改。,3.2.3 volatile限定词,const和
33、volatile一起被称为CV限定词,volatile的使用语法和const相似。当一个对象的值可能在编译器的控制或检测之外被改变时,那么该对象应该声明为volatile,例如一个被系统时钟更新的对象。编译器执行的某些例行优化行为不能应用在volatile对象上。volatile一般用在多线程或中断处理的程序设计中。,3.3 运算符和表达式,操作数和应用在这些操作数上的运算符构成了表达式。表达式指定了一个计算,会产生一个结果,即表达式的值。当一个表达式中包含两个或两个以上的运算符时,它被称为复合表达式。复合表达式的计算次序由运算符的优先级和结合性决定。C+语言提供了丰富的运算符,根据操作数的个
34、数,可以分为一元运算符、二元运算符,C+中还有一个三元运算符。也可以根据运算符的特点进行分类,例如算术运算符、位运算符、赋值运算符等。所有的运算符都会从操作数中产生一个值,大多数运算符都不会改变操作数,但是有的运算符会修改操作数的值,这称为运算符的副作用。,3.3.1 算术运算符,算术运算符包括:*、/、%、+、注意:“/”和“%”运算的右操作数不能为0。两个整数的“/”运算结果还是整数,即整除。“%”运算符只能应用于整值类型操作数,两个非负整数进行“%”运算,余数为非负值,否则余数的符号取决于实现。“+”和“”也可以作用于指针类型的变量。指针的加法一般形式是:pointer+number;指
35、针减法除了可以像上面的加法形式之外,还可以进行两个指针的减法,一般要求这两个指针指向同一数组的元素,其结果是它们指向的数组元素的下标之差。,例:韩信点兵不足百人,三人一行多一个,七人一行少两个,五人一行正好,问有多少人。,例:韩信点兵不足百人,三人一行多一个,七人一行少两个,五人一行正好,问有多少人。,3.3.2 关系和逻辑运算符,关系运算符有:,=,=,!=逻辑运算符有:!,&,|。逻辑运算和关系运算的计算结果是bool类型的,即true或false。在需要整值类型的环境中,它们的结果会被自动提升为1(true)或者0(false)。逻辑与和逻辑或运算的计算次序是从左至右,只要能够得到表达式
36、的值,运算就会结束,这种现象被称为逻辑运算的短路。即,对于表达式expr1&(|)expr2,如果expr1的计算结果为false(true),则整个逻辑与(逻辑或)表达式的值为false(true),不会再计算expr2。,判断某年是否为闰年(如果是闰年,它应能被4整除,但不能被100整除,或被100整除,也能被400整除),bool isLeapYear(int year)bool n1=(year%4=0);bool n2=(year%100=0);bool n3=(year%400=0);if(n1=true,3.3.3 赋值运算符,赋值运算符包括“=”和复合赋值运算符。赋值运算符的左
37、操作数必须是可修改的左值。右操作数的类型必须与左操作数的类型完全匹配,否则编译器会自动将右操作数的类型转换为左操作数的类型,如果不能进行转换,会引起编译错误。赋值运算是有副作用的,它改变了左操作数。赋值表达式本身的值是实际赋给左操作数的值,例如:int ival;ival=1;/结果是1ival=2.5;/结果是2,复合赋值运算符,C+还提供了一组复合赋值运算符,一般的语法格式为:a op=b等价于:a=a op(b)这里的 op=可以是下面的运算符之一:+=-=*=/=%=&=|=,赋值和初始化的不同,赋值和初始化有时会被混淆,因为都使用同一个运算符“=”。二者的不同之处在于:一个对象只能在
38、它被定义的时候初始化一次,但是可以多次被赋值。int ival=12;/初始化,等价于 int ival(12);ival=15;/赋值int ival2;/定义变量,没有初始化ival2=5;/赋值,虽然是第一次赋值,但不是初始化,“=”常被误用“=”,在编写程序时,赋值运算符“=”经常被误用为关系运算“=”,引起程序语义错误。例如,判断变量x的值如果等于1就执行某个操作的代码如果将“=”误写为“=”:/这个条件将永远为true,因为其结果是赋值表达式的值1if(x=1)doSomething;,3.3.4 自增和自减,自增(+)和自减(-)运算符为对象加1和减1提供了方便简短的表示。它们最
39、常用于对数组下标、迭代器或指针进行加1或减1操作。自增和自减是一元运算符,其操作数是可修改的左值。自增和自减都有前缀和后缀两种形式。int a=5,b=5;int ival;ival=a+;/ival的值是5,而a的值是6 ival=+b;/b的值是6,ival的值是6自增、自减运算也常用于指针,这时指针通常指向的是一个数组中的元素。,3.3.5 位运算符(1),位运算符将操作数解释为有序位的集合,每个位是0或1。位运算符允许程序员设置或测试独立的位或一组位。通常使用无符号的整值数据类型进行位操作。按位非运算:按位非运算符()对操作数的每一位取反,原来的1置为0,0置为1。移位运算:是二元运算
40、,形式:E1 E2(对无符号数或者非负的有符号数,右移一位相当于除2)如果是有符号数的负数,右移运算在左边空位或者插入符号位,或者插入0,这由具体的实现定义。,3.3.5 位运算符(2),按位,位运算表达式例子(加密解密),int main()char a1=f,a2=i,a3=r,a4=e;char secret=8;a1=(char)(a1secret);a2=(char)(a2secret);a3=(char)(a3secret);a4=(char)(a4secret);cout密文:“a1a2a3a4endl;a1=(char)(a1secret);a2=(char)(a2secret
41、);a3=(char)(a3secret);a4=(char)(a4secret);cout原文:“a1a2a3a4endl;,3.3.6 sizeof运算符,sizeof运算符的作用是计算一个对象或类型名的字节数,返回类型是size_t。size_t是一种与实现相关的typedef定义,在标准库头文件中定义。sizeof有以下三种形式:sizeof(type name)sizeof(object)sizeof object,3.3.6 sizeof应用在内置类型,在所有C+实现中:sizeof应用在char、unsigned char、signed char类型上的结果都是1;对其他内置类型
42、应用sizeof运算,其结果由实现决定。sizeof应用在枚举类型上的结果是表示枚举类型数值的低层整值类型的字节数。,3.3.6 sizeof应用在数组,sizeof运算符应用在数组上时,返回的是整个数组的字节个数,即数组长度乘以每个元素的字节数。sizeof应用在指针上时返回的是指针的字节长度,即使指针是指向数组的。例如:int ia=0,1,2;size_t arraysize=siezeof ia;/32位机器上,arraysize的值是12 int*pa=ia;size_t pointersize=siezeof(pa);/pointersize的值是4,3.3.6 sizeof应用在
43、引用类型,应用在引用类型上的sizeof运算符返回的是被引用对象的字节数。char ch=a;char/sizeof(pc)=4sizeof运算符是在编译时计算,因此被作为常量表达式。它可以用在任何需要常量表达式的地方,如数组的大小等。,3.3.7 new和delete,对象可以静态分配即编译器在处理程序源代码时分配,也可以动态分配即程序运行时调用运行时刻库函数来分配。这两种内存分配方法的主要区别是效率和灵活性。静态内存分配效率比较高,但是缺少灵活性。而存储未知类型或未知数目的元素却需要动态内存分配的灵活性。C+语言则通过new和delete两个运算符来完成动态存储空间的管理静态和动态内存分配
44、的主要区别:静态对象是有名字的变量,我们直接对其进行操作。而动态对象是没有名字的变量,我们通过指针间接地对它进行操作。静态对象的分配与释放由编译器自动处理,动态对象的分配与是否必须由程序员显式地管理。,newnew表达式的第一种形式,new运算符返回新分配的对象的指针。new表达式有三种形式。第一种用于分配特定类型的单个对象,并返回其地址。语法形式为:new 类型 或者 new 类型(初始值)例如:int*ip1=new int;*ip1=512;int*ip2=new int(100);,newnew表达式的第二种形式,new表达式的第二种形式可以在堆上分配特定类型和大小的数组,并返回数组首
45、地址,但是不能对数组进行显式的初始化。语法形式为:new 类型数组大小例如:int*ipa=new int100;注意:这里的数组大小是指数组元素的个数。用new分配的数组其大小不必是常量,可以在程序执行期间指定。比较:int*ip=new int(100);int*ip=new int100;,newnew表达式的第三种形式,new表达式的第三种形式允许程序员将对象创建在已经分配好的内存中。这种形式被称为定位new表达式,其形式如下:new(place_address)类型;place_address必须是指针。程序员可以预先分配大量的内存,以后通过定位new表达式在这段内存中创建对象。使用
46、定位new,必须包含标准库头文件。,newnew表达式的第三种形式,定位new表达式示例:#include#include using namespace std;/预分配一段空间,首地址在buf 中保存char*buf=new char 1000;int main()int*pi=new(buf)int;/在buf 中创建一个int 对象,此时不再重新从堆上分配空间,delete,堆上的空间在使用之后必须释放,否则会造成内存泄漏。new表达式分配的空间用delete运算符释放。,delete释放new分配的单个对象,释放new分配的单个对象,使用“delete 指针”表达式。例如:int*i
47、p=new int;*ip=512;/不再使用这个对象时,释放内存/释放指针指向的int对象,将空间归还给动态存储区delete ip;,空悬指针,执行delete运算后,指针ip指向的空间被释放,不能再使用ip指向的内存。delete后的ip不是空指针,而是“空悬指针”,即指向不确定的单元。在大多C+实现中,delete之后,ip中保存的仍然是delete之前的地址值,但是这个地址单元的使用权已经通过delete操作归还给动态存储区了,再继续通过ip间接使用这个单元是非法的,会引起不可预料的运行错误。int*ip=new int;*ip=512;/OKdelete ip;/释放了空间,ip成
48、为空悬指针*ip=100;/危险!不能再使用ip指向的单元int x;ip=/OK,仍然可以使用ip这个指针,delete释放new分配的数组,new表达式分配的数组使用“delete 指针”形式释放,例如:int*pa=new int100;/不再使用这个数组时,释放内存/释放指针pa指向的数组,将空间归还给动态存储区delete pa;由于定位new并不实际分配空间,所以没有对应的delete表达式。,3.3.8 条件运算符,C+中唯一的一个三元运算符。条件运算符的语法格式如下:expr1?expr2:expr3,int min(int ia,int ib)return(ia ib)?ia
49、:ib;/这段代码是如下代码的简写形式:int min(int ia,int ib)if(ia ib)return ia;elsereturn ib;,3.3.9 逗号运算符,逗号表达式是一系列由逗号分开的表达式,这些表达式从左向右计算,逗号表达式的结果是最右边表达式的值。例如:a=1,b=2,a+b 表达式的值是3,3.3.10 运算符的优先级,运算符具有优先级和结合性。优先级和结合性是指复合表达式中运算符计算的顺序。在复合表达式中,优先级高的子表达式先被计算,相同优先级的运算按照结合性从左向右或从右向左计算。大部分二元运算符都是左结合的,即从左向右计算;赋值运算符是右结合的,从右向左计算。
50、括号可以改变优先级,在计算复合表达式时先计算所有括号中的子表达式,再由计算的结果继续参与运算。,3.3.10 运算符的优先级,运算符优先级表(1),运算符优先级表(2),运算符优先级表(3),运算符优先级表(4),3.3.11 类型转换,问题:表达式中的操作数经常可能具有不同的类型,那么在计算表达式时如何处理呢?例如:int ival;ival=3.54+2;/如何计算?最终ival的结果是5。,3.3.11 类型转换,C+并不是真的将double和int值加在一起,而是提供了一组算术转换,以便在执行算术运算之前,将两个操作数转换成相同的类型。基本的转换规则是小类型被提升为大类型,以防止精度损