算术运算符
运算符 | 含义 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 取模(求余数) |
ps:
整数除法会截断结果中的小数部分。(即只保留整数部分)
%运算符只能用于整型数据。
算术运算符采用从左到右结合规律。
关系运算符
运算符 | 含义 |
---|---|
> | 大于 |
>= | 大于等于 |
< | 小于等于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
在关系表达式中,若关系为真则表达式的结果值为1,若为假,则结果值为0。
逻辑运算符
运算符 | 含义 |
---|---|
&& | AND(并且) |
|| | OR(或者) |
! | NOT(非) |
在逻辑表达式中,如果运算结果为真,则结果值为1,若为假,则结果值为0。
(实际上就是将所连接的表达式的值进行布尔运算)
ps:
由&&和|| 连接的表达式按从左到右的顺序进行求值,一旦能够推断出结果值的真假后立即停止运算。(如:&&连接中有一假则结果为假,||连接中有一真则结果为真)
&&运算进行到遇到的第一个假值或最后(全为真)。
||运算进行到遇到的第一个真值或最后(全为假)。
练习
在不使用&&或||的情况下编写一个与下面for循环语句等价的循环语句。
for (i = 0; i < lim - 1 && (c=getchar()) != '\n' && c != EOF ; ++i)
//循环体
解答1:
enum loop { NO, YES};
enum loop okloop = YES;
i = 0;
while (okloop == YES)
if (i >= lim - 1)
okloop = NO;
else if ((c = getchar()) == '\n')
okloop = NO;
else if (c == EOF)
okloop = NO;
else {
//循环体
++i;
}
解答2:
while (i < lim - 1){
if ( (c = getchar()) != '\n')
if ( c != EOF)
//循环体
else
break;
else
break;
++i;
}
类型转换
隐式类型转换
也被称为自动类型转换。
算术类型转换:通常时把“比较窄的”(精确度低)数据转换为“比较宽的“(精确度高)数据。精确度尽力保持最高。
精确度:char < int < long < folat < double < long double
如:整型 + 浮点型,整型将转换为浮点型。
单精度浮点型 + 双精度浮点型,单精度浮点型将转换为双精度浮点型。
赋值时类型转换:将左边要赋的值转换为右边所指定的类型。
函数参数类型转换:将传入的参数的值转换为参数所指定的类型。
算术类型转换是尽量保持数据的精确性,不丢失信息。
赋值时类型转换和函数类型转换则是要迁就指定的类型,有时需要将精确度高的数据转换为精确度低的数据,这就有肯能丢失信息。
ps:
char类型实际上可以看作范围较小的整型。
显式类型转换
也称强制类型转换。
(类型名)数据/表达式
数据/表达式首先被赋值给类型名指定类型的某个变量,然后再用该变量替换上述整条语句。
ps:
不允许使用无意义(非法)的的表达式。如:将浮点数作为数组下标。
当转换可能会造成信息丢失时,编译器肯能会给出警告。如:将浮点型转换为整型。
题目:
编写函数htoi(s),把由十六进制数字组成的字符串(包含可选的前缀0x或0X)转换成与之等价的十进制整数。
注:这里认为字符串以‘\0’作为结束标志,若不是十六进制数则返回0。
int htoi(char s[]){
int i = 0, num = 0;
if (s[0] == '0' && (s[1] == 'X' || s[1] == 'x'))
i = 2;
while (s[i] != '\0'){
num *= 16;
if ( s[i] >= '0' && s[i] <= '9')
num += s[i] - '0';
else if ( s[i] >= 'a' && s[i] <= 'f')
num += s[i] - 'a' + 10;
else if ( s[i] >= 'A' && s[i] <= 'F')
num += s[i] - 'A' + 10;
else{
break;
num = 0;
}
i += 1;
}
return num;
}
自增运算符与自减运算符
自增操作符++使其操作数+1
自减操作符–使其操作数-1
用在变量前(如:++n),先将n的值+1,在使用n的值。
用在变量后(如:n++),先使用n的值,再将n的值+1。
如:
m = ++n; 等价于 n = n+1;m = n;
m = n++; 等价于 m = n;n = n+1;
即:用在前面先+1,用在后面后+1。
题目1
写一个函数,将字符串s1中任何与字符串s2中字符匹配的字符都删掉。
void method1(char s1[], char s2[]){
int i, j;
i = j = 0;
while (s1[i] != '\0'){
int k;
for (k = 0; s2[k] != '\0' && s2[k] != s1[i]; k++);
if (s2[k] == '\0')
s1[j++] = s1[i];
i++;
}
s1[j] = '\0';
}
题目2
编写一个函数,将字符串s2中的字符在字符串s1中第一次出现的位置作为结果返回。若s1中不包含s2中的字符,则返回-1。
int method2(char s1[], char s2[]){
int i = 0;
while (s1[i] != '\0'){
int k;
for (k = 0; s2[k] != '\0' && s2[k] != s1[i]; k++);
if (s2[k] != '\0')
return i;
i++;
}
return -1;
}
按位运算
位操作运算符只能作用于整型操作数,即:char,short,int,long
运算符 | 含义 |
---|---|
& | 按位与(AND) |
| | 按位或(OR) |
^ | 按位异或(XOR) |
<< | 左移 |
>> | 右移 |
~ | 按位求反 |
&:按位与运算符,经常用来屏蔽某些二进制位。用来将某几位置为0。
每一位:与0进行&,置为0;与1进行&,保持不变。
|:按位或运算符,经常用来将某些二进制位置为1。用来将某几位置为指定值。
每一位:与0进行|,保持不变;与1进行|,置为1。
^:按位异或运算符,当两个操作数的对应位不相同时将该位置为1,相同置为0。每一位:与0进行^,保持不变;与1进行^,取反。
<<:左移运算符,如:x << 3 将x的二进制表示左移3位,右边空出的3位用0填补。相当于将x乘以8(2^3)。
>>:右移运算符,如:x >> 3 将x的二进制表示右移3位。对于无符号值,左边空出的部分将用0填补。对于有符号值,某些机器对左边空出的部分用符号位填补(算术移位),另一些机器则用0填补(逻辑移位)。
~:用于求整数的二进制反码,二进制位上1变为0,0变为1。
题目1:
编写一个函数setbits(x,p,y,n),该函数返回对x执行下列操作后的结果:将x从第p位开始的n个(二进制)位设置为y中最右边的n位的值。
unsigned setbits(unsigned x, int p, int n; unsigned y){
// 把一个所有位都为1的屏蔽码左移n位
// ~0 << n
// 按位取反,得到只有最右边n位为1,其余位为0的屏蔽码
// ~(~0 << n)
// 把屏蔽码最右边的n个1左移到第p位处
// ~(~0 << n) << (p - n + 1)
// 按位取反,得到只有从p开始n位为0,其余位都为1的屏蔽码
// ~(~(~0 << n) << (p - n + 1))
// 将x & 屏蔽码,使得x从第p位开始n位清0
// x & ~(~(~0 << n) << (p - n + 1)
// 将y & 从p位开始n位为1,其余位为0的屏蔽码,使得y从第p位开始保持n位,其余位清0
// y & ~(~0 << n) << (p - n + 1)
return x & ~(~(~0 << n) << (p - n + 1) | (y & ~(~0 << n)) << (p - n + 1);
}
题目2:
编写一个函数invert(x, p, n),该函数返回对x执行下列操作后的结果值:将x中从第p位开始的n个(二进制)位求反,其余位不变。
unsigned invert(unsigned x, int p, int n){
// 与0进行^(异或),保持不变
// 与1进行^(异或),取反
return x ^ (~(~0 << n)) << (p - n + 1));
}
题目3:
编写一个函数rightrot(x, n),该函数返回将x循环右移(即从最右端移出的位将从最左端再移入)n个(二进制)位所得到的值。
int wordlength(void){
int len;
unsigned v = (unsigned)~0;
for (len = 1; (v >>= 1) > 0; len++);
return len;
}
unsigned rightrot(unsigned x, int n){
int rbit;
while (n-- > 0){
rbit = (x & 1) << (wordlength() - 1);
x >>= 1;
x |= rbit;
}
return x;
}
赋值运算符
是赋值表达式的缩式
+=,-=,*=,/=,%=,<<=,>>=,&=,^=,|=
如:
x += y 等价于 x = x + y
条件表达式
使用三元运算符 ? :
expr1 ? exper2 : expr3
首先计算expr1。
若其值不等于0(为真),则计算expr2的值,并将expr2的值作为条件表达式的值。若其值等于0(为假),则计算expr3的值,并将expr3的值作为条件表达式的值。
可以用来替换if else
if (a > b)
c = a;
else
c = b;
等价于:
c = (a > b) ? a : b;
题目:
用条件表达式写一个将所有大写字母转换为小写字母的函数。
int lower (int c){
return (c >= 'A' && c <= 'C') ? (c - 'A' + 'a') : c;
}
运算符优先级与求值次序
同一行的运算符有相同的优先级。
优先级从上往下逐行降低。
运算符 | 结合性 |
---|---|
( ) [ ] -> . | 从左至右 |
! ~ ++ – (type) sizeof() | 从右至左 |
* / % | 从左至右 |
+ - | 从左至右 |
<< >> | 从左至右 |
< <= > >= | 从左至右 |
== != | 从左至右 |
& | 从左至右 |
^ | 从左至右 |
| | 从左至右 |
&& | 从左至右 |
|| | 从左至右 |
?: | 从右至左 |
= += -= *= /= %= &= | 从右至左 |
^= |= <<= >>= | 从左至右 |