• 1. 第3章 运算符和表达式
  • 2. 3.1 表达式表达式是用运算符与圆括号将操作数连接起来所构成的式子。C语言的操作数包括常量、变量、函数等。 根据表达式进行运算,得到的数值即为表达式的解。 将分号“;”加在一个表达式的后面就构成了一个简单语句。
  • 3. 3.2 算术运算符算术运算符有五种:加(+)、减(-)、乘(*)、除(/)、取模(%) 注意: 两个整数相除,结果仍为整数(结果一般向零靠拢),即整除运算。如果被除数和除数中有一个为浮点数,则结果为浮点数。 –5/ 3  – 1 取模运算实际上相当于数学中的取余数,两个操作对象都必须是整数。结果符号与%左边的操作数相同 加法和减法运算符还可以用作单目运算符,单目减运算符相当于取负数。
  • 4. 运算符的优先级和结合性 优先级是指在一个表达式中各种运算符计算的先后次序 结合性是指如果一个操作数左边和右边的两个运算符的优先级相同,应该优先运算的是左边的运算符还是右边的运算符。 自右向左 自左向右 算术运算符的优先级从高到低依次为: 单目运算符—乘、除、取模—加、减 算术运算符的结合性 单目运算符:自右向左 双目运算符:自左向右
  • 5. 3.3 赋值运算符赋值是将一个数据的值存储到一个变量中。赋值的对象只能是变量。 普通赋值运算符“=”,含义是将赋值运算符右边表达式的解送到左边变量名所代表的存储单元中。格式是 变量名=表达式 赋值表达式的解就是赋值号右边表达式的值。 赋值运算符的优先级低于算术运算,结合性自右向左
  • 6. 复合赋值运算符 += -= *= /= <<= >>= &= ^= |= 符合赋值运算符的使用规则是:Xop=Y 等价于 X=XopY 例:x+=3 表示x=x+3 a*=b-2 表示 a=a*(b-2)
  • 7. 3.4 不同类型数据间的混合运算 C语言允许双精度、单精度、整型及字符数据之间混合运算。例如: 0+'a'+1.5–8765.1234  'b' 但有一个规则:先转换成同一类型,再计算。 转换的方式有两种: 自动转换:系统根据规则自动将两个不同数据类型的运算对象转换成同一数据类型。而且对于某些数据类型,即使两个运算对象的数据类型相同,也要进行转换。 强制转换:程序员根据自己的意愿将一种数据类型转换成另一种数据类型
  • 8. double  float高低 图中“  ” 表示必定转换。如‘a’ +‘ b’,先转换为int。结果为 int。即: 既使是同一种类型也按“  ”转换。 图中“ ” : 表示低, 高型数据运算时,均先转换为高型。转换方法: longunsignedint  char, short3.4.1 自动类型转换
  • 9. 例: 10+' a'+if –d /e其中: i –– int f –– float d –– double e –– longif: 转为float, 结果为float d /e : 转为double 10+'a': 转为int, 结果为int  + :转为float -② :转为double
  • 10. 3.4.2 强制类型转换格式: (数据类型名) 操作对象 注意:强制类型转换并不改变操作对象本身的数据类型和数值。(int) f表示将f转换成整型值参与运算,但f本身的数据类型和数值都没有任何改变。 例:若x为float, 则x%3不合法。 但可用(int)x%3来解决。
  • 11. 3.4.3 赋值表达式的类型转换当赋值表达式左边变量与右边表达式的数据类型不相同时,系统负责将右边的数据类型转换成左边的数据类型。 安全的转换:转换后不会丢失数据 不安全的转换:可能丢失数据。 整型常量是long类型,浮点常量是double类型. 不同长度数据在进行赋值运算时结果可能是正确的,也可能出错,系统会出现警告: truncation from ‘const double’ to ‘float’ conversion from ‘double’ to ‘float’, possible loss of data.
  • 12. 3.5关系运算符关系运算实际上就是比较两个数值的大小。关系运算符有:大于>、大于等于>=、小于<、小于等于<=、相等==、不等于!= 关系运算的运算结果:如果关系成立,表达式的解为1(表示真);关系不成立时表达式的解为0(表示假)。注意:C语言中没有逻辑型数据。 优先级:从高到低依次为 算术运算~<、<=、>、>= ~!=、== ~赋值运算 结合性:自左向右 注意:要区别关系运算符和赋值运算符
  • 13. 例3.5(P42) #include”stdio.h” void main() { int x,y,z1,z2; x=2;y=2; z1=x=y; z2=x==y; printf(“%d,%d”,z1,z2); } 运行结果: 2,1
  • 14. 3.6 逻辑运算符逻辑与&&、逻辑或||、逻辑非! C语言系统将任何非0值都认定为真,而将0认定为假。逻辑运算的结果只有两个:1(真)和0(假)。 优先级: 逻辑非! —算术运算、关系运算—逻辑与&&—逻辑或||—赋值运算 结合性:逻辑非!自右向左,逻辑与&&和逻辑或||自左向右 注意:逻辑运算符的惰性计算(亦称按短路求值) 在C语言中,如果逻辑运算符的左操作数已经能够确定表达式的解,则系统不会再计算右操作数的值。
  • 15. AB!AA&&BA||B真真假真真真假假假真假真真假真假假真假假数学中的“10≤x≤100”如果表示成10<=x<=100 是错误的,无论x的值为什么,其结果永远是1。正确的表示方法是:x>=10&&x<=100。 惰性计算:对于逻辑与运算,只要第一个操作数结果为假,则整个表达式结果一定为假;对逻辑或运算,只要第一个操作数结果为真,则整个表达式结果一定为真。例如:x==1&&y==0 x==y||(x=0)
  • 16. 3.7 增1、减1运算符增1运算符++和减1运算符--都是单目运算符,功能分别是将变量自身的内容增1和减1。 前缀(++i,--i)先将i值增1、减1,再在表达式中使用 后缀(i++,i--) 先在表达式中使用,再将i增1、减1 优先级:高于双目算术运算符,与其它单目运算符优先级相同 结合性:自右向左
  • 17. 注意: (1)++和--运算符只能用于变量,不得用于常量和表达式。如 5++, (a+b)++均为不合法. (2)++, --的优先级与其它单目运算符相同,结合性为从右至左。如:–i++ ;因为“–”和“+ +”为同一优先级,–i++相当于–(i++)。如果 i=3, 则结果为–3, i为4. (3)在很多情况下增1减1运算都是单独使用,尽量不要出现类似i+++++i这种表达式。 (4)++, --主要用于循环变量自增或自减。 (5)增1、减1运算符与赋值运算符比较特殊,表达式的值依赖于表达式的计算顺序,运算结果可能根据编译环境有所不同。例如: a=5; c=(b=a+2)-(a=1); /*c结果可能是6或2*/ i=2;j=i*i++; /*j的值可能是4或者6*/
  • 18. 3.8 位逻辑运算符对二进制位进行控制和操作的运算符,包括:按位取反-、左移<<、右移>>、按位与&、按位或|、按位异或^ 按位取反是单目运算符,其它为双目运算符。 操作数在实现按位操作时按二进制进行计算,不能是浮点型数据,一般为无符号数。 结合性:按位取反运算符是自右向左,其它为自左向右 优先级由高到低为:按位取反及单目运算符-双目算术运算符-移位运算符-关系运算符-按位与-按位异或-按位或-逻辑运算符
  • 19. 按位与& 0&0=0 0&1=0 1&0=0 1&1=1 &运算通常用于把特定位清零(屏蔽),方法是将特定位与0进行按位与运算。 按位或| 0|0=0 0|1=1 1|0=1 1|1=1 按位异或^ 0^0=0 0^1=1 1^0=1 1^1=0 ^运算符能使特定位按位取反,方法是将这些特定位与1进行异或运算。
  • 20. 按位取反~ ~0=1 ~1=0 移位运算符 左移<<,成指数级扩大原数:右边补0,左边超出的部分删掉 例如:a=3;a=a<<2; 则a=12 由于移位运算速度远高于乘法,所以有时可以用移位运算代替乘方运算。 右移>>,成指数级缩小原数:当为正数时,最高位补 0,而为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定。Turbo C和很多系统规定为补1
  • 21. 3.9 逗号运算符逗号运算符用于将两个表达式分隔开,形成一个表达式。其格式为: 表达式1,表达式2 求解过程:先计算表达式1,再计算表达式2,并将表达式2的解作为整个逗号表达式的解。 优先级:在所有表达式中最低 结合性:从左向右
  • 22. 例: (1) a=3*5,a*4; //逗号表达式, 表达式的值60, a=15 a=3*5,a*4,a+5; //逗号表达式, 表达式的值20, a=15 (2)x=(a=3,6*3); //赋值表达式,x=18,a=3 x=a=3,6*a; //逗号表达式,表达式值18,x=3 (3)a=1;b=2;c=3; printf(“%d,%d,%d”,a,b,c); //1,2,3 printf(“%d,%d,%d”,(a,b,c),b,c); //3,2,3
  • 23. 3.10 指针类型与指针运算符指针是地址,是一个存储单元的地址,存放地址的变量就是指针变量。 程序运行时,所有程序和数据都存放在内存中,内存是以字节为单位的连续的存储空间,每个内存单元都有编号,称为内存地址。每个变量都有自己的内存地址。 指针变量定义 指针所指对象的数据类型 *指针变量名1,*指针变量名2,…… 例如: int i=2; int *p; p=&i;2000P2i2000
  • 24. 指针运算符&和*的使用 如果定义了指针变量p,p的内容应该是一个地址,通过取地址运算符&使其指向另外一个存储单元,p本身占一个存储单元。 在定义指针时,可以将其定义为指向任何一种基本类型数据的存储单元,当使用取地址运算符&为其赋值时,所指变量的数据类型应该与定义时一致。 要注意*的不同含义:作为乘号运算符使用;可以用于定义指针;可以用于采取指针所指的存储单元的内容。 指针只是概念上的地址,写程序时我们不关心它的具体数值,在C程序里不能直接将内存地址赋值给一个指针变量。 指向相同数据类型的指针变量可以相互赋值,指向不同类型对象的指针一般不要相互赋值,除非进行强制类型转换。
  • 25. 3.11 所有运算符的优先级 括号成员第一;       //括号运算符[]() 成员运算符.  -> 全体单目第二;         //所有的单目运算符比如++、 --、 // +(正)、 -(负) 、指针运算*、& 乘除余三,加减四;   //这个“余”是指取余运算即% 移位五,关系六;    //移位运算符:<< >> , //关系:> < >= <= 等 等于(与)不等排第七;    //即== 和!= 位与异或和位或;     //位运算: 位与(&)异或(^)位或(|)     “三分天下”八九十;  逻辑或跟与;            //逻辑运算符:|| 和 && 十二和十一;             //注意顺序:优先级(||)  底于 优先级(&&) 条件高于赋值,         //三目运算符优先级排到13 位 //只比赋值运算符和","高 逗号运算级最低!    //逗号运算符优先级最低