c++ c语言 - 运算符和类型转换
c 语法5 - 运算符和类型转换
一、算术运算符
运算符 | 描述 | 实例 |
---|---|---|
+ | 把两个操作数相加 | A + B 将得到 30 |
- | 从第一个操作数中减去第二个操作数 | A - B 将得到 -10 |
* | 把两个操作数相乘 | A * B 将得到 200 |
/ | 分子除以分母 | B / A 将得到 2 |
% | 取模运算符,整除后的余数 | B % A 将得到 0 |
++ | 自增运算符,整数值增加 1 | A++ 将得到 11 |
-- | 自减运算符,整数值减少 1 | A-- 将得到 9 |
1、加减乘除
和一般的加减乘除无区别,注意输出格式即可,无法除以0
除法运算后得到的结果给整型变量时候,取整数部分
#include <stdio.h>
int main(void){
int a = 10;
int b = 20;
printf("a + b = %d\n",a+b);
printf("a - b = %d\n",a-b);
printf("a * b = %d\n",a*b);
printf("b / a = %d\n",b/a);
return 0;
}
2、取余
%就是取余数运算,也就是模运算(mod)。设a,b是两个整数,a%b的结果就就是a÷b得到的余数 例如5%3=2 (商1余2) 9%4=1 (商2余1) 3%7=3 (商0余3)
#include <stdio.h>
int main(void){
int a = 10;
int b = 8;
printf("a = %d\n",a);
printf("b = %d\n",b);
printf("a %s b = %d\n","%",a%b);
return 0;
}
3、(++)与(- -)
++ 与- -是一对让算数运算方便的自增属性的算术式。
++是自增,分为前缀自增与后缀自增。而- -则是自减,也分为前缀自减与后缀自减。
但是都是等效于
i ++ / ++i ==》 i = i+1
独立式子中,没有区别,但是在与其他表达式结合的时候将发挥作用。
#include <stdio.h>
int main(void){
int a = 10;
printf("a++\n");
printf("a = %d\n",a++);
printf("a = %d\n",a);
printf("++a\n");
printf("a = %d\n",++a);
printf("a = %d\n",a);
return 0;
}
明显可以看出,++a与a++的区别。
二、赋值运算符
赋值运算符代表了在运算结束之后,给予变量一个值。
这里仅展示非位运算的运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C=A+B将把A+B的值赋给C |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C+=A相当于C=C+A |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C-=A相当于C=C-A |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C* =A相当于 C= C *A |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C/=A相当于C=C/A |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %=A相当于C=C%A |
<<= | 左移且赋值运算符 | C<<=2等同于C=C<<2 |
>>= | 右移且赋值运算符 | C>>=2等同于C=C>>2 |
&= | 按位与且赋值运算符 | C&=2等同于C=C&2 |
^= | 按位异或且赋值运算符 | C^=2等同于C=C^2 |
|= | 按位或且斌值运算符 | C|=2等同于C=C|2 |
#include <stdio.h>
int pf(int a,int c){
printf("a = %d,c = %d\n\n",a,c);
return 0;
}
int main(void){
int a = 21;
int c ;
printf("Line 1 : = 运算符实例");c = a;pf(a,c);
printf("Line 2 : += 运算符实例");c += a;pf(a,c);
printf("Line 3 : -= 运算符实例");c -= a;pf(a,c);
printf("Line 4 :*= 运算符实例"); c *= a;pf(a,c);
printf("Line 5 : /= 运算符实例"); c /= a;pf(a,c);
c = 200;
printf("Line 6 : %= 运算符实例,c 的原本值 = %d\n", c );c %= a;pf(a,c);
printf("Line 7 : <<= 运算符实例,c 的原本值 = %d\n", c );c <<= 2;pf(a,c);
printf("Line 8 : >>= 运算符实例,c 的原本值 = %d\n", c ); c >>= 2;pf(a,c);
printf("Line 9 : &= 运算符实例,c 的原本值 = %d\n", c );c &= 2;pf(a,c);
printf("Line 10 : ^= 运算符实例,c 的原本值 = %d\n", c );c ^= 2;pf(a,c);
printf("Line 11 : |= 运算符实例,c 的原本值 = %d\n", c );c |= 2;pf(a,c);
}
三、比较(关系)运算符
运算符 | 含 义 | 数学中的表示 |
---|---|---|
< | 小于 | < |
<= | 小于或等于 | ≤ |
> | 大于 | > |
>= | 大于或等于 | ≥ |
== | 判等于 | = |
!= | 不等于 | ≠ |
关系运算符都是双目运算符,其结合性均为左结合。关系运算符的优先级低于算术运算符,高于赋值运算符。在六个关系运算符中,<、<=、>、>=的优先级相同,高于==和!=,==和!=的优先级相同。
#include <stdio.h>
int main(){
char c='k';
int i=1, j=2, k=3;
float x=3e+5, y=0.85;
int result_1 = 'a'+5<c, result_2 = x-5.25<=x+y;
printf( "%d, %d\n", result_1, -i-2*j>=k+1 );
printf( "%d, %d\n", 1<j<5, result_2 );
printf( "%d, %d\n", i+j+k==-2*j, k==j==i+5 );
return 0;
}
四、逻辑运算符
一般把0为假,非0为真。计算机里的话则是1一般代表计算机输出的真值
运算符 | 术语 | 实例 | 结果 |
---|---|---|---|
! | 非(非真为假,非假为真) | !a | 如果a为假,则!a为真; 如果a为真,则!a为假。 |
&& | 与(同真为真,有假为假) | a&&b | 如果a和b都为真,则结果为真,否则为假。 |
|| | 或(有真为真,同假为假) | a||b | 如果a和b有一个为真,则结果为真,二者都为假时,结果为假。 |
逻辑符非
c#include <stdio.h>
int main(void){
int a = 10;
int b = 0;
printf("a = %d !a = %d\n",a, !a);
printf("b = %d !b = %d\n",b, !b);
return 0;
}
我们可以看到,当a = 10时,!a由于取反,则变成了代表假的0
当b = 0时,则!b取反则变成了代表真的1
一般情况下,只要是非0即可代表真。
逻辑符与
#include <stdio.h>
int main(void){
int a = 10;
int b = 0;
printf("a = %d,b = %d a&&b = %d\n",a, b, a&&b);
return 0;
}
由于a=10代表真,b=0代表假,则a&&b代表假
逻辑符或
#include <stdio.h>
int main(void){
int a = 10;
int b = 0;
printf("a = %d !a = %d\n",a, !a);
printf("b = %d !b = %d\n",b, !b);
printf("a = %d,b = %d a&&b = %d\n",a, b, a&&b);
printf("a = %d,b = %d a||b = %d\n",a, b, a||b);
return 0;
}
五、位运算符
真值表
p | q | p & q | p | q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
假设变量 A 的值为 60,变量 B 的值为 13,则:
与运算符&
按位与操作,按二进制位进行"与"运算。运算规则:
0&0=0;
0&1=0;
1&0=0;
1&1=1;
(A & B) 将得到 12,即为 0000 1100
或运算符 |
按位或运算符,按二进制位进行"或"运算。运算规则:
0|0=0;
0|1=1;
1|0=1;
1|1=1;
(A | B) 将得到 61,即为 0011 1101
异或运算符^
异或运算符,按二进制位进行"异或"运算。运算规则:
0^0=0;
0^1=1;
1^0=1;
1^1=0;
(A ^ B) 将得到 49,即为 0011 0001
取反运算符 ~
取反运算符,按二进制位进行"取反"运算。运算规则:
~1=0;
~0=1;
(~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。
左移运算符 <<
二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。
A << 2 将得到 240,即为 1111 0000
右移运算符 >>
二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
A >> 2 将得到 15,即为 0000 1111
#include <stdio.h>
int main(void){
unsigned int a = 60; /* 60 = 0011 1100 */
unsigned int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a & b; /* 12 = 0000 1100 */
printf("Line 1 - c 的值是 %d\n", c );
c = a | b; /* 61 = 0011 1101 */
printf("Line 2 - c 的值是 %d\n", c );
c = a ^ b; /* 49 = 0011 0001 */
printf("Line 3 - c 的值是 %d\n", c );
c = ~a; /*-61 = 1100 0011 */
printf("Line 4 - c 的值是 %d\n", c );
c = a << 2; /* 240 = 1111 0000 */
printf("Line 5 - c 的值是 %d\n", c );
c = a >> 2; /* 15 = 0000 1111 */
printf("Line 6 - c 的值是 %d\n", c );
}
六、三目运算符和逗号运算符
三目运算符 ?:
表达式1 ? 表达式2**:** 表达式3
表达式1为一个判别表达式:若表达式1为真,则整个三目运算取值表达式2
若表达式1为假,则整个三目运算取值为表达式3
#include<stdio.h>
int main(void){
int a = 40;
int b = 50;
printf("%s",a>b ? "a>b" : "a<b" );
return 0;
}
逗号运算符 ,
一般用于连接定义或者声明变量以及连接表达式的运算符。逗号运算符可以结合形成逗号表达式,通过运算之后获取的话会获取到最后一位。
#include<stdio.h>
int main(void){
int a = 40, b = 20, c = 10; //同时定义三个整型变量
int x = (a = 4, b = 2, c = 1); //逗号运算符表达式,x获得表达式最后一个值的结果,同时值被改写
printf("X = %d\n", x);
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
return 0;
}
七、运算符优先级
单目运算符:代表运算过程只有一个变量
双目运算符:代表运算过程存在两个变量
以此类推
同一优先级的运算符,运算次序由结合方向所决定。
简单记就是:!> 算术运算符 > 关系运算符 > && > || > 赋值运算符
优先级1
运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|
[] | 数组下标 | 数组名[常量表达式] | 左到右 | |
() | 圆括号 | (表达式)/函数名(形参表) | 左到右 | |
. | 成员选择(对象) | 对象.成员名 | 左到右 | |
-> | 成员选择(指针) | 对象指针->成员名 | 左到右 | |
-- | 后置自减运算符 | --变量名 | 左到右 | 单目运算符 |
++ | 后置自增运算符 | ++变量名 | 左到右 | 单目运算符 |
优先级2
运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|
- | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
(类型) | 强制类型转换 | (数据类型)表达式 | 右到左 | |
++ | 前置自增运算符 | 变量名++ | 右到左 | 单目运算符 |
-- | 前置自减运算符 | 变量名-- | 右到左 | 单目运算符 |
* | 取值运算符 | *指针变量 | 右到左 | 单目运算符 |
& | 取地址运算符 | &变量名 | 右到左 | 单目运算符 |
! | 逻辑非运算符 | !表达式 | 右到左 | 单目运算符 |
~ | 按位取反运算符 | ~表达式 | 右到左 | 单目运算符 |
sizeof | 长度运算符 | sizeof(表达式) | 右到左 |
优先级3
运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|
/ | 除 | 表达式/表达式 | 左到右 | 双目运算符 |
* | 乘 | 表达式*表达式 | 左到右 | 双目运算符 |
% | 余数(取模) | 整型表达式/整型表达式 | 左到右 | 双目运算符 |
优先级4
运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|
+ | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
- | 减 | 表达式-表达式 | 左到右 | 双目运算符 |
优先级5
运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|
<< | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
>> | 右移 | 变量>>表达式 | 左到右 | 双目运算符 |
优先级6
运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|
> | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
>= | 大于等于 | 表达式>=表达式 | 左到右 | 双目运算符 |
< | 小于 | 表达式<表达式 | 左到右 | 双目运算符 |
<= | 小于等于 | 表达式<=表达式 | 左到右 | 双目运算符 |
优先级7
运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|
== | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
!= | 不等于 | 表达式!= 表达式 | 左到右 | 双目运算符 |
优先级8~13
优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|---|
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
13 | ? : | 条件运算符 | 表达式1? 表达式2: 表达式3 | 右到左 | 三目运算符 |
优先级14
运算符 | 名称或含义 | 使用形式 | 结合方向 |
---|---|---|---|
= | 赋值运算符 | 变量=表达式 | 右到左 |
/= | 除后赋值 | 变量/=表达式 | 右到左 |
*= | 乘后赋值 | 变量*=表达式 | 右到左 |
%= | 取模后赋值 | 变量%=表达式 | 右到左 |
+= | 加后赋值 | 变量+=表达式 | 右到左 |
-= | 减后赋值 | 变量-=表达式 | 右到左 |
<<= | 左移后赋值 | 变量<<=表达式 | 右到左 |
>>= | 右移后赋值 | 变量>>=表达式 | 右到左 |
&= | 按位与后赋值 | 变量&=表达式 | 右到左 |
^= | 按位异或后赋值 | 变量^=表达式 | 右到左 |
|= | 按位或后赋值 | 变量|=表达式 | 右到左 |
优先级15
运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
---|---|---|---|---|
, | 逗号运算符 | 表达式,表达式,… | 左到右 | 从左向右顺序运算 |
类型转换
数据拥有不同的数据类型,不同数据类型之间进行混合运算必然涉及类型的转换问题。
转换的方法有两种: 自动转换(隐式转换):遵循一定的规则,由编译系统自动完成。 强制类型转换:把表达式的运算结果强制转换成所需的数据类型。
**类型转换的原则:**占用内存字节数少(值域小)的类型,向占用内存字节数多(值域大)的类型转换,以保证精度不降低。
大 ==》 小有可能存在问题;小 ==》 大没问题;
隐式转换
**特点:**由编译器自动完成的类型转换
算术运算式中,低类型转换为高类型 赋值表达式中,表达式的值转换为左边变量的类型 函数调用时,实参转换为形参的类型 函数返回值,return表达式转换为返回值类型
#include <stdio.h>
int main(void){
int i = -2;
unsigned int j = 1;
if( (i + j) >= 0 ){
printf("i+j>=0\n");
}
else{
printf("i+j<0\n");
}
printf("i+j=%d\n", i + j);
return 0;
}
在计算时,转换为高类型,即unsigned int,判断>0,这里感觉没有错。那为什么输出-1,跟我们正常算-2+1的结果一样呢。
我们都知道计算机是补码存储,-2+1的unsigned int结果是0xffffffff,对于输出的%d其实是int类型,所以自然打印就是-1了。
强制类型转换
虽然自动类型转换不需要人工干预,使用方便,但有利也有弊,尤其当自动类型转换是从较高类型转换为较低类型时,将会降低精度或截断数据,可能得不到预期的结果。
为了给程序设计人员提供更多的类型转换控制权限,使程序设计更加灵活,转换的目的更加清晰,C 语言提供了可显式指定类型转换的语法支持,通常称之为强制类型转换。
强制类型转换的格式为:
(目标类型) 表达式
(目标类型) 变量
#include <stdio.h>
int main(void){
float p = 3.6;
int w = 4;
double sum = (int)p*w;
printf("输出浮点数:%lf",sum);
return 0;
}
我们将p直接转成int类型,则p取整数部分进行运算
往期文章
2020-8-21
往期文章
2020-8-21
图 | 郭嘉
文 | 郭嘉
扫码关注桔梗与少年
新浪微博:桔梗与少年