一、操作符包括算数操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号表达式和下标引用、函数调用和结构成员,下面将具体介绍每一种操作符。
1、算术操作符
+ - * / %
(1)除了%操作符外,其他几个操作符都可用于整数和浮点数类型。
(2)对于 / 操作符,当操作数都为整数时,结果为整数,当有浮点数参与时,结果是浮点数。
(3)%操作符的操作对象必须是整数,这是区别于其他算数运算符的,其操作结果是整除之后的余数。
2、移位操作符
<< //左移操作符
>> //右移操作符
(1)对于左移操作符,其移位规则是左边抛弃,右边补0。
(2)对于右移操作符,分两种情况,一种是逻辑移位,一种是算术移位。算术移位:左边用原该值的符号位填充,右边丢弃;逻辑移位:左边用0填充,右边丢弃。数据在计算机里是以二进制补码形式存储的,对于无符号数,是逻辑移位,而对于有符号数,是算术移位。对于右移操作符,一定要分清是算术移位还是逻辑移位,两种结果是截然不同的。
注意:对于移位运算符,不要移动负数位,这个是标准未定义的,例如
int num=10;
num>>-1;//error
用户明显是想将num左移一位,应该写成num<<1,移动负数位是没有定义的。
3、位操作符
& //按位与
| //按位或
^ //按位异或
对于位操作符来说,操作数必须是整数。
(1)& 按位与,当操作数含有0时,其结果是0,只有当操作数都是1时,结果才为1。
(2) | 按位或,当操作数含有1时,其结果是1,只有当操作数都是0时,结果才为0。或者说,0和任何数进行按位或操作时,其结果都是它本身。
(3)^按位异或,表面意思,当操作数不同时,进行或运算,相同为0,不同为1,或者说,0和任何数进行按位异或操作时,其结果都是它本身。
4、赋值操作符
= += -= *= /= %= >>= <<= &= |= ^=
(1)对一个变量来说,首先要为它开辟空间,其次,填数值,在填数值时,有两种方法,初始化和赋值,对于一个变量来说,初始化只能初始化一次,而赋值可以进行多次。
(2)赋值有直接赋值,还有复合赋值符。赋值,可以给变量赋值,可以给表达式赋值,但切记,不能给常量赋值,例如5=3,这是错误的。赋值时,我们用符号 = 表示,是将 = 右边的值赋给 = 左边的值。
(3)复合赋值符,一定程度上是会提高效率,也让代码看起来简洁美观。用法,例如:
int a=10;
a+=3;//a=a+3;
其他复合赋值符,同上述例子。
5、单目操作符
! //逻辑反操作
- //负值
+ //正值
& //取地址
sizeof //操作数的类型长度(以字节为单位)
~ //对一个数的二进制按位取反
-- //前置--,后置--
++ //前置++,后置++
* //间接访问操作符(解引用操作符)
(类型) //强制类型转换
(1) ! 逻辑反操作,当操作数为假时,输出为真,当操作数为真时,输出为假,最后的输出结果为0或1,0代表假,1代表真。
(2) + - 这两个操作符是一对,+ 操作符,是对操作数取正值,当操作数为正值时,我们一般不写+,同算术运算, - 操作符,是对操作数取负值, - 不能省。
(3) & 取地址,对他的操作数取地址,例如:
int a=10;
int p=&a;
//p是一个变量,为其开辟空间后,里面放的是a的地址,*p放的是a的值
(4) sizeof 操作数的类型长度,例如:
/*int a=0;
sizeof(a);//sizeof(int)//测量a类型的大小*/
int arr[10]={0};
sizeof(arr)/sizeof(arr[0]);//对数组来说,sizeof(arr)是整个数组的长度,sizeof(arr[0])是数组首元素类型的长度,该语句是查看数组有多少个元素
(5) ~ 对一个数的二进制按位取反,例如:
(6) ++, - -是一对操作符,++又分为前置++,后置++,- -分为前置- -,后置- -。
前置++和前置- -是先++或- -再用,后置++和后置- - -,是先用后++ 或- -。例如:
int a=3;
int b=5;
b--;
printf("%d,%d\n",++a,b);//a=4,b=4
(7)*解引用操作符,例如:
int a=10;
int *p=a;//定义一个整形指针p
*p=19;//对p的解引用操作
(8)(类型) //强制类型转换,例如:
int a = 10;
float b =(float) a;
//b是float型,而a是整型,需要对a进行强制类型转换,转换成flaot型,再赋给b
printf("%lf\n",b);
6、关系操作符
> >= < <= != ==
对于>, >=, <, <= 这几个操作符来说,大家应该是非常熟悉的;!=,测试不相等操作符;需要注意的是 == 操作符,该操作符是判断操作数相等的,而我们还学过一个操作符 =,该操作符是赋值操作符,尽管我们知道这些,但我相信很多小伙伴在判断操作数相等时,都会将双等号误写成单等号,这是我们一直以来的一个习惯,判断相等用 = ,但是这是在算术运算中,在C中,我们用双等号来判断操作数相等。可是,在编译时,我们如果将双等号误写成单等号,编译不会报错,这是因为=也是操作符,电脑将其识别成赋值操作符,再进行其他运算,这样做有时会让系统陷入死循环。所以一般我们建议写双等号时,左边写常量,右边写变量,这样,就避免了上述情况,如果写成 =,就是错的,因为不能给常量赋值。
7、逻辑操作符
&& ||
大家看到这个操作符可能会想到&(按位与),| (按位或)这两个操作符,这两个没有任何关系,只是在判定时稍有类似,按位与和按位或是将整数转化成二进制数,对操作数的二进制数进行按位与或者按位或,其最终结果是整数。而逻辑与和逻辑或最终结果只能是0(假)或者1(真),判定条件也是0(假)或者!0(真),常用于循环条件的判定中。
(1) && ,逻辑与操作,当操作数都为真时,结果为真,当操作数含有假时,结果为假。我们知道,当操作数为假时,逻辑与连接的表达式为假,所以,在条件判定时,若&&左边操作数为假时,我们就没有必要看&&的其他操作数,只有当前面的操作数为真时,我们才判断后面的操作数是否也为真,所以&&也成为短路逻辑与。例如:
//逻辑与,短路运算符,b=0,条件为假,不需要判断后面操作数的真假,
//所以if条件为假,不打印hello world!
int a = 5;
int b = 0;
if ((b--) && (--a))
{
printf("hello world!\n");
}
printf("a=%d,b=%d\n", a, b);//a=5,b=-1
(2) || ,逻辑或操作,当操作数都为假时,结果为假,当操作数含有真时,结果为真。我们知道,当操作数为真时,逻辑或连接的表达式为真,所以,在条件判定时,若 || 左边操作数为真时,我们就没有必要看 || 的其他操作数,只有当前面的操作数为假时,我们才判断后面的操作数。例如:
//逻辑或连接的条件,前操作为真,后操作没有必要再看,
//所以只是对b进行了自减,a不变
int a = 5;
int b = 1;
if ((b--) || (--a))
{
printf("a=%d,b=%d\n", a, b);//a=5,b=0
}
8、条件操作符
条件操作符我们也成为三目运算符,例如:
int x = 3;
int y = 4;
//条件操作符,判断条件是否为真,为真输出x,否则输出y
//很明显,该题中x>y不成立,所以输出y
int res = x > y ? x : y;
printf("res=%d\n", res);//res=4
9、逗号表达式
逗号表达式是用逗号将多个表达式隔开,自左向右依次判断,最后一个表达式的值就是整个逗号表达式的值,例如:
int a = 3;
int y = 3;
//a+y=6为真,y>0为真y-a=0为假,所以整个表达式为假,if语句为假,输出hello
if (a + y, y > 0, y - a)
{
printf("hello world!\n");
}
printf("hello!\n");
10、下标引用、函数调用和结构成员
下标引用,用[]表示,操作数用一个数组名 + 一个索引值表示;函数调用操作符接受一个或多个操作数,它的第1个操作数是函数名,剩余的操作数就是传递给函数的参数;访问一个结构的成员,可以用结构体.成员名或者结构体指针->成员名
二、整形提升
我们都知道,当我们定义一个变量时,必然要为他开辟空间和初始化,该变量在计算机的内存里,当我们对该变量进行运算时,实际是将变量送给寄存器,在CPU中完成相关操作,并将变量送回内存中,而CPU中运算器的操作数的字节长度一般就是int的字节长度,同时也是CPU通用寄存器的长度,所以,在CPU中进行运算时,表达式中各种长度小于int长度的整型值,都必须转为int或unsigned int,再送到CPU中进行运算。如何进行整型提升呢?在进行整型提升时,我们要先看变量自身的类型,主要是看其是有符号数还是无符号数,有符号数补符号位,无符号数补0。
三、操作符的属性
操作符的属性有两个,优先级和结合性,在判断两个相邻的操作符先执行哪个时,先看优先级,如果优先级相同,再看结合性,优先级中,逗号操作符优先级最低,需要注意的是,前置后置++和–与*的优先级,*优先级较低,这个在以后对指针操作时用的较多。