C/C++学习笔记(2)——运算符和表达式、位运算、类型转换及常见运算问题

目录

运算符和表达式

运算符分类

表达式分类

求余运算

++,--运算符的使用

关系运算符与关系表达式

逻辑运算符与逻辑表达式

条件运算符与条件表达式

逗号运算符与逗号表达式

=与==的区别

位运算

按位与运算符“&”

按位或运算符“|”

按位异或运算符“^”

二进制左移运算符“<<”

二进制右移运算符“>>”

按位取反运算符“~”

类型转换及常见运算问题

类型转换问题

各类数值型数据间的混合运算

算术运算时的自动类型转换

赋值运算时的自动类型转换(隐式转换)

强制类型转换(显式转换)


运算符和表达式

运算符分类

按运算对象的数目:单目运算符、双目运算符、三目运算符

按照其功能:算术运算符、赋值运算符、关系运算符、逻辑运算符、位运算符、自增自减运算符、条件运算符、逗号运算符等。

表达式:由运算符和运算量所组成的符合C的语法的算法。

表达式分类

算术表达式、关系表达式、逻辑表达式、赋值表达式、条件表达式、逗号表达式、混合表达式等。

表达式都会返回一个结果(或值)。

C程序形式上特有的几种运算(相对于数学运算问题):

  • 算术运算符——*,/(除号),%(求余)
  • 自增自减运算符——++,--
  • 复合赋值运算符——+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=
  • 关系运算符——<=,==,>=,!=

求余运算

x%y;//x除以y取余数
/*结果符号取决于被除数*/
15%2;//结果为1
-15%2;//结果为-1
15%-2;//结果为1
-15%-2;//结果为-1

求余运算的对象必须是整型。多用于判断整除问题。

++,--运算符的使用

其优先级别高于所有的双目运算符。

有两种不同的形式:前置式、后置式

前置运算是变量先自增1或自减1后,再参与其他的运算,即先变后用。

后置运算是该变量先以原来的值参加其它运算,然后再自增1或自减1,即先用后变。

自增自减运算符只能作用于变量、字符型和指针变量,不能用于常量和表达式。

关系运算符与关系表达式

关系运算符:<,<=,>,>=,==,!=

关系运算符都是双目运算符,用来比较两个运算量之间的关系。

用关系运算符将前、后两个运算量连接起来的式子称为“关系表达式”,这两个运算量可以是任意表达式。

关系表达式的结果为整数1或整数0。

逻辑运算符与逻辑表达式

逻辑运算符:&&(逻辑与),||(逻辑或),!(逻辑非)

逻辑运算真值表

运算规则

  • 逻辑与参与运算的两个量都为真时,结果才为真,其它情况为假。
  • 逻辑或参与运算的两个量都为假时,结果才为假,其它情况为真。
  • 逻辑非参与运算量为真时,结果为假;参与运算量为假时,结果为真。

规定

  • 对于逻辑与运算,若左表达式为“假”,则无需判断右表达式即可判断逻辑表达式的值为假;只有当左表达式为“真”时,才需要继续判断右表达式。
  • 对于逻辑或运算,当左表达式为“真”,则无需判断右表达式即可判断逻辑表达式的值为真;只有当左表达式为“假”时,才需要继续判断右表达式。
a=10;
b=20;
max=b;
c=(a>b)&&(max=a);//c=0,max=20

条件运算符与条件表达式

一般形式(三目运算符)

表达式1?表达式2:表达式3

操作过程:判断表达式1的值,如果为非0值,则求解表达式2的值作为该条件表达式的值;如果为0值,则求解表达式3的值作为该条件表达式的值。

a=10;
b=-5;
c=b>0?(a+b):(a-b);//c=15

逗号运算符与逗号表达式

逗号运算符是顺序求值运算符,形式为:

表达式1,表达式2,表达式3,......,表达式n

运算过程:先求表达式1的值,再求表达式2的值,依次计算下去,最后表达式n的值为该逗号表达式的值。

a=10;
b=(a++,a%3);//a++表达式的值为10,此时a的值为11,所以a%3表达式的值为2

=与==的区别

C语言中,“=”是赋值运算符,“==”是关系运算符。

if(a=4)
    a=b;
/*实际上是将4赋值给a,然后检查表达式的值是否为0,最终的结果始终是把b值赋给了a*/

位运算

按位与运算符“&”

按位与运算是对两个操作数逐位“求与”。

作用

  • 将某些位清零。与位“0”求与。
  • 取数中的特定位。与位“1”求与。
运算真值表

按位或运算符“|”

按位或运算是对两个操作数逐位“相或”。

作用

  • 将数的某些位,置1。与位“1”相或。
  • 把一串二进制数连接到另一串二进制数(n位)后。将第一串二进制数后面加上n个0,然后与第二串二进制数相或。
运算真值表

按位异或运算符“^”

按位异或运算是对两个操作数逐位“相异或”。 

作用:某位要保持不变就异或0,某位要取反就异或1。

运算真值表

二进制左移运算符“<<”

运算规则:把数据向左移动若干位,移出左边界的所有位都将丢失,右侧新增加的位为0。

int a=4;//二进制为0000 0100
a<<2;//0000 0100<<2为0001 0000,结果为16

变量左移后未发生溢出的情况下,向左移动n位相当于乘以2^{n}

二进制右移运算符“>>”

运算规则

把数据向右移动若干位,移出右边界的所有位都将丢失,左侧的新位补充遵循下面的规则:

  • 对于无符号数,左侧的新位一律补0。称为“逻辑右移”。
  • 对于有符号数,若符号位为0,左侧新位一律补0;若符号位为1,左侧新位一律补1。称为“算术右移”。
b=-10;//b为有符号数,其二进制补码为1111 0110
b>>1;//1111 0110右移1位,结果为1111 1011,即-5

按位取反运算符“~”

按位取反运算符是将操作数进行逐位“取反”。

类型转换及常见运算问题

为了数据存储和处理的需要,C编译程序将数据划分为不同的数据类型,并为每一种数据类型规定了在内存中的存储单元字节数和对该数据类型数据所能进行的运算。 

类型转换问题

类型转换在程序设计中有两类:运算过程中的类型转换、调用函数的方式实现类型转换。

各类数值型数据间的混合运算

自动类型转换:在C语言中,字符型、整型和浮点型数据可以在同一表达式中混合使用,C语言编译系统会按照一定的准则自动进行类型转换。

发生自动类型转换的两种情况

  • 当双目运算符的两个运算量结果的类型不相同且进行算术运算时;
  • 当一个赋予一个不同类型的变量时(赋值)。 

算术运算时的自动类型转换

转换规则:值域较窄的类型向值域较宽的类型转换(“值域”就是类型所能表示的值的最大范围)。

算术转换遵循的转换方向

注意:

  • 表达式中的有符号和无符号字符以及短整型(short)一律转换为整型,如果int类型能表示原来类型的值,则转换为int类型,否则转换为unsigned类型。
  • 当一个运算量为long类型,另一个为unsigned类型时,如果long能表示unsigned的全部值,则将unsigned转换为long;否则将两个运算量都转换为unsigned long。
  • 当两个运算量中值域较宽的类型是float类型时,将float和另一运算量转成double类型。 

赋值运算时的自动类型转换(隐式转换)

赋值转换将右值表达式(赋值符号“=”的右边)结果的类型转成左值表达式的数据类型。

赋值转换具有强制性:不受算术转换规则的约束,转换结果的类型完全由左值表达式的类型决定。 

强制类型转换(显式转换)

是靠强制类型转换运算符来实现数据类型转换的,因此强制类型转换也叫做显式转换,而自动类型转换也叫做隐式转换

强制类型转换——人为

自动类型转换——自动

强制类型转换在效果上与赋值转换相同,它们的转换方向都不受算术转换规则的约束

一般形式:(类型名)表达式

作用:将表达式转换成“类型名”所指定的类型。

float x=6.5;
int y=(int)x;
/*将单精度x强制转换为int类型,并赋值为y,因此y=6,
但变量x的类型仍是单精度浮点型,x仍为6.5*/

小结:无论是自动类型转换还是强制类型转换,都只是将变量或常量的值的类型进行暂时的转换,用于参与运算和操作,而变量和常量本身的类型和数值并没有改变

调用函数实现数据类型转换

int atoi(const char *s);//将字符串转换为整数
double atof(const char *s);//将字符串转换为浮点数
long atoll(const char *s);//将字符串转换为长整型
char* itoa(int value,char *s,int radix);//将整型数转换为radix进制字符串
char* itoa(long value,char *s,int radix);//将长整型数转换为radix进制字符串
char* ecvt(double value,int ndig,int *dec,int *sign);//将浮点数转换为字符串

C语言常见运算问题分析

数据的溢出问题

数据有其固定的表示范围,因此当数据的值超出了其范围时,将出现溢出问题。

int a,b;
a=32767;//变量a在内存中的表示(按照BC31的规范)为:0111 1111 1111 1111
b=a+1;//a加上1后,变量b在内存中的表示为:1000 0000 0000 0000
printf("%d,%d\n",a,b);//所以运算结果为32767,-32768

无符号整数与有符号整数的混合运算问题

int x=1;
unsigned int y=2;
printf("%d,%d\n",x-y,(x-y)/2);//运算结果为-1,32767
/*变量x在内存中的表示为:0000 0000 0000 0001,
变量y在内存中的表示为:0000 0000 0000 0010,
根据类型自动转换原则,x-y运算结果的类型应为unsigned int,
该结果在内存中的表示为:1111 1111 1111 1111,
将结果以有符号整型数输出,即格式化输出%d,输出结果为-1;

(x-y)/2的结果在内存中的表示为:0111 1111 1111 1111,
将结果以有符号整型数输出,即格式化输出%d,输出结果为32767*/

整数相除问题

float c,f;
scanf("%f",&f);
c=5/9*(f-32);
printf("%f\n",c);
/*不管变量f输入的是41、50等,运行结果输出均为0。
因为5/9的结果为0,0乘以任何数均为0。
可修改为c=5.0/9*(f-32)或c=5/9.0*(f-32)或c=5.0/9.0*(f-32)
或将除法运算放到表达式的最后来运算,如c=5*(f-32)/9*/

除法运算“/”在使用时要特别注意数据类型。因为两个整数(或字符)相除,其结果是整型。不能整除时,只取结果的整数部分,小数部分全部舍去。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欲读万卷书,不入愚昧途

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值