第 4 章 操作及其控制

37
第4第 第第第第第第 4.1 基基基基基基基基 4.2 基基基 4.3 基基 4.4 基基基基基 第第第第第第第第第第第第第第第 ; 第第 C++ 第第第第第 ; 第第第第 C++ 第第第第第第第 ; 第第 include 第第第第第第

Upload: miach

Post on 14-Jan-2016

94 views

Category:

Documents


0 download

DESCRIPTION

第 4 章 操作及其控制. 学习目的: ① 掌握基本数据类型与操作 ; ② 掌握 C++ 的主要语句 ; ③ 熟练掌握 C++ 提供的顺序控制 ; ④ 熟悉 include 等预处理指令。. 4.1 基本操作与运算符 4.2 表达式 4.3 语句 4.4 预处理指令. 4.1 基本操作与运算符. 操作又称为运算,通用程序设计语言提供多种操作,每种操作都用运算符标记,如:加( + )、减( - )、乘(*)、除( / )等算术运算,以及指针运算、移位等各种语言特有的操作。 运算符分类: 根据操作数个数:单目运算符、双目运算符及三目运算符; - PowerPoint PPT Presentation

TRANSCRIPT

第 4 章 操作及其控制

4.1基本操作与运算符4.2表达式4.3语句4.4预处理指令

学习目的:① 掌握基本数据类型与操作 ;② 掌握 C++ 的主要语句 ;③ 熟练掌握 C++ 提供的顺序控制 ;④ 熟悉 include 等预处理指令。

4.1 基本操作与运算符

4.1.1赋值操作4.1.2 算术操作4.1.3 增 1 (减 1 )操作4.1.4 关系、逻辑操作4.1.5 条件运算符

操作又称为运算,通用程序设计语言提供多种操作,每种操作都用运算符标记,如:加( + )、减( - )、乘( * )、除( / )等算术运算,以及指针运算、移位等各种语言特有的操作。运算符分类:

根据操作数个数: 单目运算符、双目运算符及三目运算符;按照功能不同: 算术运算符、关系运算符、逻辑运算符、位操作运

算符、赋值运算符等另外, 可按优先级和结合性对算符进行分类。

4.1.1 赋值操作

注意 :对于字符串的赋值采用 memset() 、 memcpy() 、 strcpy() 等函数进行。

int nVar(0);nVar=4;nVar=nVar+2;

nVar+=2;

int *pN=&nVar;*pN=8;

赋值操作用于改变数据对象的值,基本类型变量的赋值操作一般由赋值符 = 表示,其具体语义是将 = 左侧数据对象的值改变为 = 右侧表达式的值(常数为表达式的一种形式):

4.1.2 算术操作

注意 :对整型数据的除法操作,其结果为整型数据,例如: 5.0/2.0=2.5 、 2.0/4=0.5 ,但 5/2=2 、 2/4=0 ,相当于进行除法后保留商的整数部

分。

包括加、减、乘、除、取负、取余数,分别以 + 、 - 、 * 、 / 、 - 、 %等运算符代表 。

其中 % 的操作数要求为 int 型,而其它运算符要求操作数为基本数据类型或指针类型等。复杂运算的书写规则与人类的习惯相似:

3+4n*(x+4)

对于用户自定义类型或构造类型,需要由用户重新给出上述运算符所代表的具体操作 (运算符重载)。

4.1.3 增 1 (减 1 )操作1. 前缀增 1 (减 1 )运算

符 格式为: ++prefix_exp --prefix_exp

要求操作数 prefix_exp 是整型、浮点型或指针型,并且必须是一个可修改的左值表达式(即表达式没有 const 属性),例如整型变量等。前缀增 1 (减 1 )操作结果的类型与操作数类型相同,且结果是左值,运算后 prefix_exp 的值加(减) 1 ,表达式的值同此。因此 x=++Val相当于 x=Val+1 和 Val=Val+1 两个操作的复合,例如当变量 Val的值为 5 时,表达式 x=++Val 的结果是 x 的值为 6 , Val 的值也为6 。int n=0;++n;

++(++n);

4.1.3 增 1 (减 1 )操作2. 后缀增 1 (减 1 )运算

符 格式为:

postfix_exp ++postfix_exp --

对操作数 postfix_exp 的要求与前缀增 1 (减 1 )运算符相同。运算结果类型与操作数类型相同,但不再是左值。

int n=0;n ++;

++n;(n++)=2;

4.1.4 关系、逻辑操作这两种操作经常出现在条件判断中,关系操作有六种 :

> (大于) < (小于) == (相等)>= (大于等于) <= (小于等于) != (不相等)

关系操作结果的类型为布尔型或逻辑型,例如 3==4 的值为false 、 6>2 的值为 true 。

逻辑操作有三种:&& (逻辑与) || (逻辑或) ! (逻辑非)

逻辑运算操作数类型为逻辑型,结果为逻辑型,具体操作语义如下:两操作数都为真,逻辑与运算的结果为真,否则为假。两操作数中至少一个为真,逻辑或运算结果为真,否则为假。操作数为真,逻辑非运算结果为假,否则为真。

4.1.5 条件运算符

该运算符是一个三目运算符,格式如下: exp0 ? exp1 : exp2

语义是,如果 exp0 为真,则该表达式的值为 exp1 ,否则表达式的值为 exp2 。表达式的类型与 exp1 和 exp2中类型高的( 4.2.1 )一个相同。

使用方法举例如下:

int MaxAB = (A>B) ? A : B;

4.2 表达式

4.2.1 隐含类型转换4.2.2 强制类型转换4.2.3 表达式内的顺序控制4.2.4 运算符的优先级4.2.5 运算符的结合性

运算符与操作数相结合形成的式子称为表达式。常见的简单表达式有算术表达式、逻辑表达式、关系表达式、赋值表达式等。简单表达式通常由一个运算符与一两个操作数构成,用来表述算法中最基本的简单操作。复杂的表达式由多个表达式复合而成,它们可以用来描述算法中的一个模块或者是复杂的处理。

任何表达式在运算后都会产生一个结果,这个结果具有某种类型和数值,称作表达式的类型和值。

4.2.1 隐含类型转换

int→unsigned→long→unsigned long→float→double

上述类型中 int 类型最低, double 类型最高,当低类型和高类型同时出现在一个运算符操作数中时,低类型将被转换为高类型,例如当算术运算符两个操作数中有一个的类型为 double 时,则运算前另一个操作数将被转换成 double 类型,然后进行浮点型的算术运算,运算后的结果也将为 double 型;总之,计算算术表达式的值时,如果两个操作数的类型不同,所采用的方针是用存储宽度较大的类型存放存储宽度较窄的操作数,这样做的目的是为了不丢失信息。

每个表达式的值都具有确定类型,取决于运算符的种类和操作数类型,当二目运算符的两个操作数类型不同时,不能直接进行运算,必须进行适当的类型转换。

对于基本数据类型,这种类型转换通常为语言所内建,因此称为隐含类型转换。隐含类型转换的规律是将低类型的操作数转换为高类型,对算术运算符而言,常见类型的高低顺序如下:

4.2.2 强制类型转换当操作数的类型不同,而且不属于基本数据类型时,经常需要强制类型转换,将操作数转化为所需的类型。强制类型转换具有两种形式,称为显式强制转换和隐式强制转换。

1. 显式强制类型转换格式为: type(<expression>) 或 (type)<expression>

type 为类型描述符,如 int 、 float 等。 <expression> 为表达式。经强制类型转换运算符运算后,返回一个具有 type 类型的数值,这种强制类型转换操作并不改变操作数本身,运算后操作数本身未被改变,例如:

int nVar=0xab65;char cChar=char(nVar);

上述强制类型变换的结果是将整型值 0xab65 的高端两个字节去掉,而将低端两个字节的内容作为 char 型数值赋值给变量 cChar ,经过类型变换后 nVar 的值并没有发生改变。

4.2.2 强制类型转换2. 隐式强制类型转换

隐式类型转换发生在赋值表达式和有返回值的函数调用表达式中。在赋值表达式中,如果赋值符左右两侧的操作数类型不同,则将赋值符右侧操作数强制转换为赋值符左侧操作数类型的数值后赋值给赋值符左侧的变量。

在函数调用时,如果 return 后面表达式的类型与函数返回值类型不同,则在返回值时将 return 后表达式的数值强制转换为函数返回值类型后再将值返回。例如:

int nVar;double dVar=3.88;nVar=dVar; //执行本语句后, nVar 的值为 3 ,而 dVar仍然是 3.88

4.2.3 表达式内的顺序控制

(3+5)*83+5*8

3+(5*8)?

表达式的值与操作数类型有关,也与运算顺序有关。

应用括号直接控制表达式中子表达式的求值顺序,能够避免运算结果的不确定性。例如:按习惯 a*b/c 可以利用括号写成 (a*b)/c ,否则有可能理解为 a*(b/c) ,这两个表达式的值通常是不一样的,比如 (3*2)/3=2 ,而3*(2/3)=0 。

4.2.4 运算符的优先级制定运算符的优先级的目的是解决表达式语义的二义性,高优先级运算符所代表的操作先进行、低优先级运算符代表的操做的后进行,在一定程度上可以解决二义性问题。

+ 、 - 、 * 、 / 等 4 种基本操作的执行顺序与人们所习惯的四则运算规则相同。常用运算符的优先级如下:

++(--) 后缀增 1(减 1) nVar++ ; nVar--;++(--) 前缀增 1(减 1) ++nVar , --nVar;

& 取变量存储地址 &nVar* ( / ) 乘 (除) int a=2,b=8/a; a=b/3;

% 取余数 a=4%3;+ (- ) 加(减) int a=1,b=a+4; a=8-7;< ( > ) 小(大)于 int a=3;if(a>=6) cout<<a<<endl;

<= (>= ) 小(大)于等于== ( !=)等于(不等于) if(p != 0) break;

& ^ | 按位与、异或、或 a & b ^n a | b&& 逻辑与 (x==1) && (x==3)- 取负数 x=-nVar|| 逻辑或 b1 || b2

? : 条件表达式 (a>=b)?(a):(b)

4.2.5 运算符的结合性

只有单目运算符、条件运算符和赋值符是右结合的,其他运算符均为左结合。

结合性用于多个具有相同优先级运算符出现在一起时运算顺序的控制,具有左结合性的运算符左边优先于右边,因此将从左至右逐个运算符地进行运算,而具有右结合性的运算符的运算顺序与此相反。

a=b=c 等价于 a=(b=c)

a+b+c 等价于 (a+b)+c

3+4+5-8 等价于 ((3+4)+5)-8

3*4/5*8 等价于 ((3*4)/5)*8

3*4*8/5 等价于 ((3*4)*8)/5

4.3 语句

4.3.1 表达式语句4.3.2 语句间顺序控制4.3.3 复合语句4.3.4 选择语句4.3.5 循环语句4.3.6 直接顺序控制

语句是构成程序的基本单元,简单语句用于表示一种单一功能的操作,复合语句、选择语句、循环语句等复杂语句可能代表多个操作组成的一种复杂操作或功能。

语句由单词按照语句的语法规则组成,单词间以分隔符、运算符或若干个空格符分隔,语句通常以一个特殊的符号结束,例如 C++ 的语句以分号做为结束标志。

4.3.1 表达式语句表达式语句( Expression Statement )的形式很简单,在 C++ 中,只要在任何表达式的结尾缀以分号 ; 就构成了表达式语句。例如:

x=10*y;l=5, m=6, n=7;mb=a&(b|c);a+b;fun(x, y);y=MyFunction(3, 8);

表达式语句是一个大家族,因为表达式本身的种类就很多,我们在编程中最常用到的表达式语句是变量赋值语句、增 1 语句、减 1 语句。如下述的程序段:

int n=0;while(n<10){ x=2*n; // 赋值语句 ++n; // 增 1 语句}

4.3.2 语句间的顺序控制

作为算法实现工具,通用程序设计语言通常都提供描述算法三种基本控制结构的具体方式,使用三类语句构成程序的三种基本控制结构:

顺序结构 使用顺序语句实现。顺序语句指一组语句的执行顺序与语句的物理排列顺序相同。

选择结构 使用选择语句加以实现。选择有两种形式:条件语句和开关语句。

循环结构 使用循环语句加以实现。循环语句有三种形式: do 语句、 for 语句和 while 语句

4.3.3 复合语句

复合语句是由花括号 { } ,及其内部语句组成,作为一个整体在语法上是一条语句,尽管其内部可能包含多条语句。复合语句具有明显的块特色,所以也称为块语句。

复合语句可以嵌套,即复合语句的内部可以含有其他复合语句。复合语句可以单独使用,将程序的一部分利用 { } 扩起来作为相对独立的一块形成良好的编程风格,但更常用于 if 语句、 switch 语句或循环语句中。另外,如果在复合语句中嵌入了一条或多条说明变量,则常称这种复合语句为分程序或块结构。

4.3.4 选择语句1 条件语句

if 语句( )布尔表达式if 语句

语句else

从上述语法图可得两种常用形式:格式一: if ( < 布尔表达式 > ) < 语句 >格式二: if ( < 布尔表达式 > ) < 语句 1>

else < 语句 2>

if(a==8) b=9;else { if(a==9) b=20; else { if(a==10) b=21; else b=30; } }

b=20

b=9b=30

b=21

a==8

a==9

a==10

false

false

false

true

true

true

4.3.4 选择语句2 开关语句

}

< 语句>

:

default

switch 语句 ( )switc

h< 整型表达式

>{

< 整型常量表达式>

< 语句>

case

:

例 4.1 编程统计输入流中字符 A 的数目,字符 A 与 a 的数目,输入字符总数。

#include "iostream.h"void main() { int nA(0), nAa(0), nTotal(0); for( ; ; ) { char c; cout<<"Please enter a character! "; cin>>c; switch( c ) { case '\033': //Enter ESC to terminate goto Termination; case 'A': nA++; case 'a': nAa++; default : nTotal++; } }Termination : cout<<"The total number of 'A' is "<<nA<<endl; cout<<"The total number of 'A' and 'a' is "<<nAa<<endl; cout<<"The total number of characters is "<<nTotal<<endl;}

4.3.4 选择语句2 开关语句

例 4.2 编写程序统计输入流中 -1 、 0 和 +1 的个数。

#include "iostream.h"void main(){ int nNegtive(0), nZero(0), nPositive(0); for( ; ; ) { int i; cout<<"Please enter a integer! "; cin>>i; switch( i ) { case -1: nNegtive ++; break; case 0 : nZero ++; break; case 1 : nPositive ++; break; case 100 : goto Termination; default : cout<<"Illegal integer!"<<endl; } }Termination : cout<<"The total number of -1 is " <<nNegtive<<endl; cout<<"The total number of 0 is " <<nZero<<endl; cout<<"The total number of 1 is " <<nPositive<<endl;}

4.3.5 循环语句1. for 语

句for 语句 (for < 表达式

1>; < 表达式

2>; < 表达式

3>) < 语句

>

例 4.3 用 for循环计算自然数 1 ~ 10之和。

#include <iostream.h>void main( ){ int nSum(0);

for(int i=1; i<=10; i++) nSum+=i; //1 到 10循环

cout<<"The sum is "<<nSum<<endl; //显示结果}

true

计算 < 表达式1>

执行 < 语句 >

计算 < 表达式3>

false

退出循环

计算 < 表达式2>

4.3.5 循环语句2. while 语句

while 句 (while

< 表达式>

) 语句

例 4.4 用 while循环计算自然数 1 ~ 10之和。

#include <iostream.h>void main(){ int i(0), nSum(0); while(i<=10) //1 到 10循环 { nSum+=i; i++; } cout<<"The sum is

"<<nSum<<endl;}

true执行 < 语句 >

false

退出循环

计算 < 表达式>

4.3.5 循环语句3. do 语句

do 语句(whil

e< 表达式 > )< 语句 >do

[ 例 4.6] 用 do循环计算自然数 1 ~ 10之和。

#include <iostream.h>void main(){ int i(0), nSum(0); do { nSum+=i; } while(++i<=10); //1 到 10循环

cout<<"The sum is "<<nSum<<endl; //显示结果

}

true

false

退出循环

计算 < 表达式>

执行 < 语句 >

4.3.5 循环语句4. 复杂条件循环

循环中的初始化表达式、条件表达示等可以是一些复杂的表达式,甚至包括循环变量的声明也可能出现在循环中,下面所列为循环的一些用法,学习循环时可以借鉴:

for(int i=0; i<10; i++)

for(; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))

for(; nCount--; ++pElements)

for(; nCount--; ++pDest, ++pSrc)

for(; hWndChild != NULL; hWndChild=::GetNext(hWnd, GW_HWND))

while((dwResult = RegEnumKey(hCurrentKey, 0, szSubKeyName, 255))

while((pWndT = pWndDlg->GetNextDlgGroupItem(pWndStart)) != NULL)

4.3.5 循环语句5. 多重循环

例 4.7 已知 a 为 5×4阶矩阵, b 为 4×6阶矩阵,编程求这样两个矩阵的乘积矩阵,将结果输出在屏幕上。

#include <iostream.h>#include "string.h"void main(){ int i, j, k; int a[5][4], b[4][6], c[5][6]; memset(c, 0, sizeof(int)*5*6); // Initialize c //Followings for entering the elements of matrix a for(i=0; i<5; i++) for(j=0; j<4; j++) { cout<<"a["<<i<<", "<<j<<"]="; cin>>a[i][j]; }

a=

37691115647382563842

b=

446739856677324867785321

。 113 93 107 92 76 102

127 80 126 110 100 105

134 94 131 103 82 98

28 26 36 41 51 50

127 112 138 129 131 149

//Followings for inputing the elements of matrix b for(i=0; i<4; i++) for(j=0; j<6; j++) { cout<<"b["<<i<<", "<<j<<"]="; cin>>b[i][j]; } //Followings for calculating and outputing the elements of matrix c cout<<endl<<endl<<"The product matrix is:\t"<<endl; for(i=0; i<5; i++) { for(j=0; j<6; j++) { for(k=0; k<4; k++) c[i][j]+=a[i][k]*b[k][j]; cout<<c[i][j]<<"\t"; } cout<<endl; }}

4.3.6 直接顺序控制

1. goto 语句3. continue 语

句2. break 语

#include <iostream.h>void main(){ int nCount(0); int nCtrl(0);MyLabel: nCtrl++; nCount+=nCtrl; if( nCtrl<10 ) goto MyLabel; cout << " The sum is " << nCount <<endl;}

while(cin>>i){ if(i==8) break;}cout<<i;

int n(0);for(int i=0; i<=100; i++){ if(i%2==0) continue; n+=i;}

4.4 预处理指令

4.4.1 文件包含指令4.4.2 宏定义指令4.4.3 条件编译指令 *

预处理指令不是程序运行时刻的有效操作,而是用以指示编译器在对源代码编译之前进行必要的预处理。

C++ 的所有预处理指令都以 # 开始,除了注释外,每条预处理指令占用单独的一行,同一行不能有其它预处理指令和 C++ 语句,而且与 C++ 语句不同,预处理指令不以分号结束。

预处理指令(亦称编译指令)不是语言的一部分,但实际上几乎 C++ 、 Java 等语言的任何程序都离不开它,它为编程者提供了控制编译器行为的手段,扩展了编程环境的使用范围,在程序组织和管理上给编程者带来方便。

4.4.1 文件包含指令文件包含指令(嵌入指令或 include 指令),格

式:#include <filename>

或#include "filename"

例如:#include 〈 c:\user\WangMing\Firt\common.h 〉

#include "c:\user\WangMing\Firt\common.h "

注意: 由于预处理指令不是 C++ 指令,因此上述表示路径的反斜杠只用一个反斜杠。如果在 C++ 程序中使用字符串表示路径,则这个字符串中必须用双斜杠。例如: char FileName="c:\\user\\WangMing\\Firt\\common.h";

首先按调用编译器时行命令中所指示的路径查找,然后按语言环境所设置的默认 include 目录去查找

预处理器首先在含有该条 include 语句的文件所在目录中查找,然后在所有包含该文件的文件所在的目录中查找,再按调用编译器时行命令中所指示的路径查找,最后按语言环境所设置的默认 include 目录去查找。

4.4.2 宏定义指令宏定义是高级语言编译器提供的常用预处理指令,其目的是使用某一标识符标识某个文本字符串,分为无参数宏及有参数宏两类,格式如下:

#define <MacroName> <CharString>

或 #define <MacroName> ( <arglist> ) <CharString>

使用方法示例如下:

#define PI 3.1415926#define max(a, b) \ ((a)>(b)) ? (a):(b);

void main(){ int nRadius=3.0; int nArea=nRadius*nRadius*PI;}

4.4.2 宏定义指令宏的不安全性

#define PI 3.1415926#define max(a, b) \ ((a)>(b)) ? (a):(b);

void main(){ int nRadius=3.0; int nArea=nRadius*nRadius*PI;}

#define max(a, b) (a>b)? a : b;

int kk=2+max(1, 2);

4.4.2 宏定义指令宏定义是高级语言编译器提供的常用预处理指令,其目的是使用某一标识符标识某个文本字符串,分为无参数宏及有参数宏两类,格式如下:

#define <MacroName> <CharString>

或 #define <MacroName> ( <arglist> ) <CharString>

使用方法示例如下:

#define PI 3.1415926#define max(a, b) \ ((a)>(b)) ? (a):(b);

void main(){ int nRadius=3.0; int nArea=nRadius*nRadius*PI;}

4.4.2 宏定义指令字符串化运算符 # 将右操作数变为字符串

#define PrintString(a) #a " John" // 注意此处 John 前有一个空格 cout<<PrintString( My name is ); //参数两侧的空格将被忽略

展开后: cout<<"My name is John";

Visual C++ 为带参数宏定义提供了三个常用运算符: # 、 #@ 、##

字符化运算符 #@ 将右操作数变为字符 #define makechar(x) #@x

a = makechar(b);

展开后: a = 'b';

标识粘接运算符 ## 将两个标识( Token )粘接形成一个新标识 #define paster( n ) printf( "token" #n " = %d", token##n ) int token9 = 9; paster( 9 );

展开后: printf( "token9 = %d", token9 );

4.4.3 条件编译指令 *

#if defined(__CHINESE) cout<<" 本程序用汉字进行提示 "<<endl;#else cout<<"Prompt in English in this programm"<<endl;#endif

高级语言通常都提供控制编译器执行流程的指令—条件编译指令。 C++的编译器支持的条件编译指令为 #if 、 #else 、 #elif 、 #endif ,其语义与C++ 语言的 if 等语句相类似,使用方法也相近(注意这里多了一个#endif ),可以参见 if 语句的用法。

常与这几个指令一起应用的是一个类似于函数的运算符 defined() ,其使用方法是 defined( 标识符 ) ,如果括号内标识符目前是定义的,则该表达式的值非 0 ,否则为 0 。