目录
一、运算操作符
加(+) 减( -) 乘(*) 除(/) 求余(%)
<1>加(+)减(-)乘(*)都与数学运算相同。
<2>除(/)与数学运算不同的是当两个操作数均为整数时为取整运算,当两个操作数有一个为小数时与数学运算相同。如:5/2,结果为2,5.0/2,结果为2.5
<3>求余(%)的两个操作数必须均为整数。
<4>运算的优先级:先乘除求余,再加减。同优先级的从左向右依次运算。
★算除法时,如果算的数中至少一个小数,那么结果的类型就是double类型。
二、关系操作符
大于(>) 大于等于(>=) 小于(<) 小于等于(<=) 双等(==) 不等(!=)
<1>双等(==)是用来判断两个值是否相等,相等为真,不相等为假。
<2>不等(!=)是用来判断两个值不相等的,不相等为真,相等为假。
<3>运算的优先级:先是大于(>),大于等于(>=),小于(<),小于等于(<=),再是双等(==),不等(!=)。同优先级的从左向右依次运算。
<4>不能连等,连等与数学运算不一样,极易出错。如:5>4>3,结果为假,因为5>4为真,结果为1, 1>3为假,结果为0。
<5>字符作为操作数时,以其ASCⅡ值作为操作数。如:‘a’==97为真
<6>尽量避免小数进行双等、不等的运算,因为用小数表示时存在一定的误差。
三、逻辑操作符
与(&&) 或(||) 非(!)
<1>与(&&)、或(||)都为双目运算符,非(!)为单目运算符。
<2>当与(&&)的两个操作数均为真时,结果为真,否则为假。当或(||)的两个操作数均为假时,结果为假,否则为真。
<3>运算的优先级:先与(&&)后或(||),相同优先级从左向右运算。 非(!)的优先级最高,相同优先级从右向左运算。
<4>短路特性:当运算与()时,如果左侧为假,那右侧将不再运算。当运算或()时,如果左侧为真,那右侧将不再运算。
<5>可以用来表示一个变量的取值范围,如:-4<x<4,可表示为-4<x&&x<4。
四、条件操作符(唯一的三目操作符)
格式:表达式1?表达式2:表达式3
<1>首先判断表达式1的值,如果表达式 1的结果为真,则执行表达式2,表达式2的结果即为整个表达式的结果。如果表达式1的结果为假,则执行表达式3,表达式3的结果即为整个表达式的结果。
<2>可以嵌套使用,同级的执行顺序为从右向左。
五、赋值操作符
等于(=) 加等(+=) 减等(-=) 乘等(*=) 除等(/=) 求余等(%=)
右移位等(>>=) 左移位等(<<=) 按位与等(&=) 按位或等(|=) 按位异或等(^=)
<1>赋值表达式的格式:变量 赋值运算符 表达式。 赋值运算符左边必须是变量,不能是常量或表达式。
<2>加等、减等、乘等、除等、求余等,要求必须有初值。如:a+=3,意思是a=a+3,并将表达式的值赋给a。
<3>赋值运算符都属于同一优先级,同一优先级的执行顺序为从右向左。
六、逗号表达式
格式:表达式1,表达式2,......,表达式n
求解顺序为:从左向右依次计算表达式的值,最后一个表达式的值即为整个表达式的值。
七、移位操作符
左移(<<)右移(>>)
移位操作符作用的是二进制位。
1、左移
如: int a=2,int b=a<<1 即 0000 0010向左移动一位,右边少的一位补0,得到0000 0100
2、右移
<1>算术右移
丢弃最右边,左边补原符号位。
<2>逻辑右移
丢弃最右边,左边补0。
☆要想测试算数右移和逻辑右移需要用负数来测试,正数算术右移和逻辑右移结果相同。
八、位操作符
按位与(&) 按位或(|) 按位异或(^)
知识铺垫:
整数的二进制表示形式有3种:原码、反码、补码
原码:按照数值的正负,直接写出的二进制序列就是原码。
反码:原码的符号位不变,其他位按位取反。
补码:反码的二进制+1就得到补码。
原码---->反码----->补码
取反 +1
补码---------------->原码
取反、+1
(以上转化可自行验证,结果一定是正确的)
对于正整数来说,原码、反码、补码均相同。
对于负整数来说,反码、补码都是需要计算的。
整数在内存中存储的都是补码的二进制序列。
整数在计算机中的运算都是以补码进行运算的。
1个字节是8个bit位,一般来说一个整数是4个字节,也就是32个bit位。
对于有符号的整数来说,最高位为符号位,其余位为有效位。
符号位是1表示负数。
符号位是0表示正数。
对于无符号的整数来说,没有符号位,所有位均为有效位。
1、左移(<<)
一个数的二进制位向左移动,相当于 这个数*2的移动位数次方
移动规则:左移丢弃,右边补0(正数负数都一样)
例1:int m=10,int n=m<<1;
未移动前的m:00000000 00000000 00000000 00001010
m移动后的n: 00000000 00000000 00000000 00010100
移动后,m=10,n=20; 原本的数不会变!!!
例2:int m=-7,int n=m<<1
-7的原码: 10000000 00000000 00000000 00000111
-7的反码: 11111111 11111111 11111111 11111000
-7的补码: 11111111 11111111 11111111 11111001
未前移动前的n:11111111 11111111 11111111 11111001
m移动后的n: 11111111 11111111 11111111 11110010
n的反码: 11111111 11111111 11111111 11110001
n的原码: 10000000 00000000 00000000 00001110
移动后,m=-7,n=-14;
2、右移(>>)
①逻辑右移
一个数的二进制位向右移动,一般移动之后数变成正数。
移动规则:右边直接丢弃,左边补0
②算数右移
一个数的二进制位向右移动,相当于这个数/2的移动位数次方
移动规则:右边直接丢弃,左边补原符号
★对于移位运算符,不要移动负数位,这个是标准未定义的。
九、单目操作符
①自增(++)、自减(--)
<1>自增、自减具有相同的优先级,同级执行顺序为从右向左依次执行。
<2>前置++或--:先运算后使用。如:i=2,++i,i的值为3,++i的值也为3。
后置++或--:先使用后运算。如:i=2,i++,i的值为3,i++的值为2。
<3>自增、自减都有赋值的操作,所以操作数只能是变量,不能是常量或表达式。
<4>操作的变量必须要有初值。
了解:<5>尽量不要在一个表达式中对一个变量进行多次的自增或自减,可读性差,极易出错。
<6>有时候为了避免二义性,经常使用()表明其优先结合性。
②正数(+)、负数(-)
③&取地址符
格式:& 变量名 得到变量的地址
④sizeof() 计算数据类型所占空间的大小。
☆计算变量大小的时候括号可以省略,但是计算类型大小的时候不可以省略括号。
☆计算数组类型的大小,如:int arr[10]; sizeof(int [10]);int [10]是数组的类型。
☆sizeof中放的表达式是不参与运算的。
☆sizeof算出的结果的类型是unsigned int类型的。
⑤~按位取反
二进制位按位取反。如:int a=2 ,int b=~a
a:0000 0010 2
~a:1111 1101 -3
⑥ * 间接访问操作符(解引用操作符)
⑦(类型)强制类型转换
如: int a=3.14 强制类型转换 int a=(int)3.14
⑧逻辑反操作(!)
十、下标引用、函数调用和结构成员操作符
1.下标引用操作符[ ]
此操作符的操作数有两个,一个是数组名,一个是下标。如:int arr[5]={1,2,3,4,5};
printf("%d\n",arr[3]);
2、函数调用操作符()
3、结构成员操作符 . →
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct Stu
{
char name[20];
int age;
double score;
};
int main()
{
struct Stu s = { "阿大", 20, 85.5 };
printf("%s %d %lf\n",s.name,s. age,s.score);
struct Stu* ps = &s;
printf("%s %d %lf\n",(*ps).name,(*ps).age,(*ps).score);
printf("%s %d %lf\n", ps->name, ps->age, ps->score);
return 0;
}
表达式求值
1、隐式类型转换
(1)①整型提升:表达式中的字符和短整型操作数在使用之前被转化为普通整型(表达式中各种长度小于int长度的,都必须先转化为int或unsigned int类型),这种转换称为整型提升。
如:char a,b,c;
a=b+c;
b和c的值被提升为普通整型,再参加加法运算,加法运算完成后,结果将被截断,再存储于a中。
②整型提升规则
整型提升是根据变量的数据类型的符号位来提升的
<1>有符号整数的整型提升,高位补原符号位
<2>无符号整数的整型提升,高位补0
int main()
{
char a = 3;
char b = 127;
char c = a + b;
printf("%d\n",c);
return 0;
}
%u打印的是无符号整型
char c=1;
sizeof(c);//1
sizeof(+c)//4
sizeof中的c不参与运算,但是看的是,如果参加运算,之后的类型。
(2)算数转换
当一个操作符的操作数类型不一样时,只有当一个操作数的类型向另一个操作数的类型转换之后才可以进行后续操作。
long double
double
float
unsigned long int
long int
unsigned int
int
上面的表格是,由下面的类型转换成上面的类型,原则就是向更高精度的类型转换。
十一、操作符的属性
复杂表达式的求值有三个影响因素。
1、操作符的优先级
2、操作符的结合性
3、是否控制求值顺序