C语言的运算符
学习编程语言,应该遵循“字-->词-->句-->段--->章”,对于一条有意义的语句而言,是离不开标点符号的
运算符指明要进行的运算和操作,操作数是指运算符的操作对象,根据运算符操作数的数目不同,C语言标准把运算符分为三种:单目运算符(一元运算符)、双目运算符(二元运算符)、三目运算符(三元运算符)
C语言运算符优先级详细列表
(1)算术运算符
C语言中提供了7种算术运算符,分别是
+ | - | * | / | % | ++ | -- |
++和--都属于单目运算符,使用的时候比较特殊,其他五种都属于双目运算符
加法运算符+和减法运算符-一般没有特别需要注意的,作为双目运算符,需要两个操作对象,但是有时候 - 也会作为负号使用就变为单目运算符,使用规则发生变化
*和/是作为乘法运算符和除法运算符,属于双目运算符,但是除法运算符的使用规则有些不同
当除法运算符两端的操作数都是整数的时候,得到的结果也是整数,当两个操作数无法被整数,会舍弃小数,只保留整数
- Question1:求以下程序执行的结果
#include <stdio.h>int main()
{int x = 'f';printf("%c\n",'a'+(x-'a'+1));
}A.g B.h C.i D.j
- Answer1:
首先,int x = 'f'; 中,字符 'f' 的 ASCII 码值为 102。接着分析表达式 'a' + (x - 'a' + 1):'a' 的 ASCII 码值为 97
x - 'a' 即 102 - 97 = 5,再加 1 得到 6
最后 'a' + 6 即 97 + 6 = 103,对应字符 'g'
因此,程序输出结果为 g,正确答案是 A
当除法运算符两端的操作数不全是整数,比如其中一个操作数是浮点数,则得到的结果也是浮点数,如果不指定精度,则默认是6位精度
C语言中提供%作为求余运算符,也可以称为取模运算符,C语言标准中规定%符号两端的操作数必须是整数
可以知道,C语言中的运算符是有优先级的,运算符的优先级指的是多个运算符出现在同一个表达式中,优先执行哪个运算符,可以知道算术运算符* / %的优先级是高于算术运算符+和-
-
Question2:既然运算符有优先级,那如果一个表达式使用的运算符的优先级都一样,那应该如何进行运算?
-
Answer2:
当表达式中运算符优先级相同时,需通过结合性(左结合或右结合)确定运算顺序:
左结合:从左至右依次运算。例如算术运算符+、-,表达式a - b + c,先计算a - b,再用结果与c运算
右结合:从右至左依次运算。例如赋值运算符=,表达式a = b = c,先计算b = c,再将结果赋给a
C语言中的运算符是有结合性的,运算符的结合性指的是多个优先级相同的运算符出现在同一个表达式中,优先执行哪个运算符
运算符的结合性分为两种:一种是左结合性,遵循先左后右原则,比如 a + b - c,相当于(a+b)-c,另一种是右结合性,遵循先右后左原则,比如双目运算符中的赋值运算符 = ,比如表达式a=b=c,相当于a=(b=c)
注意:C语言中的单目运算符和三目运算符都是遵循右结合性,当然也包含双目运算符中的赋值运算符=,其他的运算符都遵循左结合性
C语言中提供了两个增量运算符++和--,属于单目运算符,只能在变量中使用,一般可以作为变量的后缀增量或者后缀减量,++和--也被称为自加运算符和自减运算符,注意:C语言标准中规定++和--也可以作为变量的前缀增量和前缀减量。 作用是让变量的值自动加1或者减1。
a++ :在表达式中则表示先让变量a参与表达式运算,运算之后才会让变量a的值自加
++a :在表达式中则表示先让变量a的值自加,自加之后再参与表达式运算
- Question3:请问结果是什么?请给出简单的推理过程
#include <stdio.h>int main()
{int a,b,c,d;a = 10;b = a++;c = ++a;d = 10*a++;printf("b,c,d:%d,%d,%d",b,c,d);return 0;
}
-
Answer3:
b = 10; c = 12; d = 120;
-
Question4:前缀增量和后缀增量都属于单目运算符,如果一个表达式中同时出现两种运算符,那应该如何进行解释?比如表达式 ++i++ 如何解释?
-
Answer4:
++(i++) 遵循右结合性
-
Question5:请问结果是什么?请给出简单的推理过程
int main()
{int i=3;int j;j = sizeof(++i + i++);printf("i=%d j=%d",i,j);
}A.i=4 j=2 B.i=3 j=2 C.i=3 j=4 D.i=3 j=6
- Answer5:
sizeof 特性:sizeof 是编译期确定结果的操作符,其操作数表达式不会实际执行。因此 ++i + ++i 不会执行,i 仍为初始值 3
sizeof(int) 的结果:int 类型在多数系统中占 4 字节,故 j = sizeof(++i + ++i) 实际等价于 j = sizeof(int),即 j = 4
最终输出 i=3 j=4,对应选项 C
注意sizeof在C语言中是一个操作符,作用是计算数据类型的大小,结果以字节为单位,sizeof括号中的表达式是不会实现运算和处理的
另外,虽然sizeof运算符中的表达式不会被运算,但是如果sizeof表达式中出现多个数据类型的大小计算,这个时候会涉及到C语言基本数据类型的转换,转换的意思指的是将数据(变量、数值、表达式的结果等)从一种类型转换为另一种类型
一般程序中的数据类型转换分为两种情况:自动类型转换 or 强制类型转换。两者区别如下:
-
自动类型转换
自动类型转换就是编译器默默地、隐式地进行的数据类型转换,这种转换不需要程序员干预,会自动发生。比如将一种类型的数据赋值给另外一种类型的变量时就会发生自动类型转换
在赋值运算中,赋值号两边的数据类型不同时,需要把右边表达式的类型转换为左边变量的类型,这可能会导致数据失真,或者精度降低;所以说自动类型转换并不一定是安全的。对于不安全的类型转换,编译器一般会给出警告
在不同类型的混合运算中,编译器也会自动地转换数据类型,将参与运算的所有数据先转换为同一种类型,然后再进行计算
转换的规则:转换按数据长度增加的方向进行,以保证数值不失真,或者精度不降低。例如int 和 long 参与运算时,先把 int 类型的数据转成 long 类型后再进行运算。所有的浮点运算都是以双精度进行的,即使运算中只有 float 类型,也要先转换为 double 类型,才能进行运算。另外char 和 short 参与运算时,必须先转换成 int 类型
-
强制类型转换
自动类型转换是编译器根据代码的上下文环境自行判断的结果,有时候并不是那么“智能”,不能满足所有的需求。如果需要,程序员也可以自己在代码中明确地提出要进行类型转换,这称为强制类型转换
自动类型转换是编译器默默地、隐式地进行的一种类型转换,不需要在代码中体现出来;强制类型转换是程序员明确提出的、需要通过特定格式的代码来指明的一种类型转换。换句话说,自动类型转换不需要程序员干预,强制类型转换必须有程序员干预
强制转换规则: (需要转换的数据类型) 变量
例如:(int *)a (unsigned char)b总结:无论是自动类型转换还是强制类型转换,都只是为了本次运算而进行的临时性转换,转换的结果也会保存到临时的内存空间(栈空间),不会改变数据本来的类型或者值
(2)位操作运算符
C语言中提供了6种位操作运算符,分别是 ~ & ^ | << >>,其中~属于单目运算符,其他五种都属于双目运算符。
~:按位取反,对于二进制数而言,0变为1,1变为0 ~ 1101_1110 = 0010_0001
&:按位与,对于二进制而言,当两个bit同时为1,则结果为1,如果bit存在0,结果为0
|:按位或,对于二进制而言,当两个bit同时为0,则结果为0,如果bit存在1,结果为1
^:按位异或,对于二进制而言,当两个bit相同,则结果为0,两个bit不同,则结果为1
<<:左移运算符,对于二进制而言原则:高位舍弃、低位补0 0111_1010 << 3 -- 1101 0000
>>:右移运算符,对于二进制而言原则:低位舍弃、高位补0 0111_1010 >> 3 -- 0000 1111
- Question6:请问结果是什么?请给出简单的推理过程
int a= 3,b =6执行语句“int k= a^b<<1;"后,变量 k的当前值是()
A、10 B、15 C、3 D、16
- Answer6:
根据运算符优先级,<< 高于 ^,先计算 b << 1:b = 6,二进制为 110,左移 1 位后是 1100(十进制 12)再计算 a ^ (b << 1),即 3 ^ 12:3 二进制 0011,12 二进制 1100,异或结果为 1111(十进制 15)。
因此,变量 k 的值是 15,正确答案为 B。
- Question7:请问结果是什么?请给出简单的推理过程
给定一个整型变量a,第一个设置a的bit3,第二个清除a的bit3。在以上两个操作中,要保持其它位不变
- Answer7:
1. a |= (1<<3)
2. a &= ~(1<<3)
(3)关系运算符
C语言中一共提供了6种关系运算符,分别是 < <= > >= == != ,关系运算符都是双目运算符,都遵循左结合性,一般用在条件判断中,如果表达式中使用关系运算符,则表达式也被称为关系表达式,关系表达式的结果只有两种,用户可以使用布尔型进行结果的表示
通过标准可以知道,关系运算符 < <= > >=的优先级相同的,并且这四种运算符是高于关系运算符 == !=,两者的优先级是相同的
- Question8:请问结果是什么?请给出简单的推理过程
定义a为整型,下列表达式 a=3>6 的运行后,a的值为
A. 0
B. 2
C. 3
D. 表达式错误
- Answer8:
在表达式 a=3>6 中,比较运算符 > 优先级高于赋值运算符 =。先计算 3>6,结果为假(值为 0),再将 0 赋值给 a。因此,a 的值为 0,正确答案是 A
逻辑运算符
C语言中提供了3种逻辑运算符,分别是 && || ! ,对于逻辑与&&和逻辑或||都属于双目运算符,遵循左结合性,而逻辑非!属于单目运算符,遵循右结合性。一般表达式中如果使用了逻辑运算符,则表达式被称为逻辑表达式
还有一个逻辑运算符是 ! (逻辑非) ,属于一元运算符,只有一个操作对象,遵循右结合性,作用是把操作对象的逻辑取反(真变为假,假变为真)
- Question9:请问结果是什么?请给出简单的推理过程
已知x=43,ch='A’,y=0;则表达式(x>=y && ch<’B’ && !y)的值是()
A. 0
B. 语法错误
C. 1
D. 假
- Answer9:
分析表达式 (x>=y && ch<'B' && !y):x=43,y=0,x>=y 为真(值 1);ch='A','A'<'B' 为真(值 1);y=0,!y 为真(值 1)。
逻辑与 && 连接三个真值,最终结果为 1(C 语言中逻辑真用 1 表示)。且表达式语法正确。
因此,正确答案为 C
(5)条件运算符
C语言中提供了1种条件运算符,符号是 ? : ,条件运算符是唯一的一个三目运算符,需要三个操作数
(6)赋值运算符
提供了11种赋值运算符,如下图所示,都属于双目运算符,但是遵循右结合性!!!
(7)逗号运算符
C语言中提供了1种逗号运算符,符号是 , 作用是把多个表达式连在一起,构成一个大的表达式,也被称为逗号表达式。注意按照从左向右的流程对每个表达式进行运算,只是逗号表达式最终结果是最后一个表达式的结果
- Question10:请问结果是什么?请给出简单的推理过程
001.下列运算符中优先级最高的是(
A.
B. +
C.&&
D. !=
- Answer10:
在 C 语言运算符优先级中:B. + 属于算术运算符,优先级高于其他选项A. < 和 D. != 是关系运算符,优先级低于算术运算符C. && 是逻辑运算符,优先级最低
因此,优先级最高的是 B
- Question11:请问结果是什么?请给出简单的推理过程
以下程序的运行结果是
#include <stdio.h>
int main(){
int sum, pad,pAd;
sum = pad = 5;
pAd = ++sum, pAd++, ++pad;
printf("%d\n",pAd);}
- Answer11:
程序执行过程分析:sum = pad = 5:初始化 sum 和 pad 为 5pAd = ++sum:++sum 是前缀自增,sum 先变为 6,再将 6 赋值给 pAd,此时 pAd = 6pAd++:后缀自增,表达式值仍为 6,执行后 pAd 变为 7++pad:pad 自增为 6,不影响 pAd最后 printf("%d\n", pAd) 输出 pAd 的当前值 7
因此,程序运行结果是 7
- Question12:请问结果是什么?请给出简单的推理过程
以下程序运行后的输出结果是
int main(){int a;a=(int)((double)(3/2)+0.5+(int)1,99*2);printf("%d\n", a);
}
- Answer12:
程序中表达式计算过程:3/2 因均为 int 类型,结果为 1(double)(3/2) 转换为 1.0(int)1.99 取整为 1,乘以 2 得 2计算 1.0 + 0.5 + 2 = 3.5(int)3.5 截断取整为 3,赋值给 a
最终输出结果为 3
- Question13:请问结果是什么?请给出简单的推理过程
0x01<<2+3的值为多少?为什么?
- Answer13:
根据运算符优先级,+ 高于 <<,先计算 2+3=5。接着执行左移运算:0x01 是十六进制数,对应十进制 1,二进制为 0000 00011 << 5(左移 5 位),二进制变为 0010 0000,对应十进制 32
因此,0x01<<2+3 的值为 32