- 算数操作符
- 位移操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标应用,函数调用和结构成员
1| + - * / %
- 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
- / 操作符是取商,% 操作符是取余
- 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。(例如:int a= 3 / 5 ,a结果为0 , 但 int a = 5.0 / 3 或 int a = 5 / 3.0 , a 的结果依然为0。如果想要小数位上有值就要写成double a = 5.0 / 3 或 flout a = 5 / 3.0)
- % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
注:移位操作符的操作数只能是整数。
1| << >>
举个例子
int a = 1; int b = a<<1;//向左移动一位
打印出来b的结果是2。
其实这里的移位移的是二进制位,例子中的a在内存中的存放是 :
00000000000000000000000000000001
左移一位后得到的b结果为
00000000000000000000000000000010
这里可以看出左移操作符的特点为:左边丢弃,右边补零
再举一个例子
int a = -1; int b = a>>1//向右移动一位
这里打印出来b的结果还是-1
其实右移操作符有两种右移方法
右边丢弃,左边补原符号位
2.逻辑右移(正数)右边丢弃,左边补零
所以上面代码a在内存中的存放为:
原码:10000000000000000000000000000001
反码:1111111111111111111111111111111111110
补码:1111111111111111111111111111111111111
所以右移一位,左边补符号位,右边丢弃,得到的结果为
补码:1111111111111111111111111111111111111
所以-1右移一位得到的结果b还是-1
注意a向右移动,是把a向右移动之后的值赋给了b,这里的a没有发生改变它的值还是之前a赋的值
正数与负数在内存中的存放方式都是以补码的方式存放(正数的原码,反码,补码都相同)
负数的符号位就是在二进制数列的第一位写1
正数的符号位是0
整数二进制的表达形式其实有三种
原码:直接根据数值写出二进制序列就是原码
反码:原码的符号位不变,其它的按位取反就是反码
补码:反码+1,就是补码
& //按位与 | //按位或 ^ //按位异或
注:他们的操作数必须是整数。
举例说明:
int a = 3; int b = 5; // & - 按(二进制)位与 int c = a & b;
a 的二进制为 00000000000000000000000000000011
b 的二进制为 00000000000000000000000000000101
c 的二进制为 00000000000000000000000000000001
如果a,b对应二进制位相同那么输出 c 的二进制对应位不变,如果a,b二进制位不同那么输出 c 的对应二进制位为0。所以 c 的值为1
如果 int c = a | b;
对应的二进制位只要有1则输出为1,只有两个都为0结果才为0;故结果为00000000000000000000000000000111;故c的值为7
如果 int c = a ^ b;
对应的二进制位相同则为0 ,相异则为1;故结果为00000000000000000000000000000110;故c的值为6
可是这个操作符到底有什么用呢???
先来看一道题:
创建两个变量int a = 3; int b = 5。要求不能创建一个新的变量,并且交换他们两个的值
这里你又想到了什么方法呢?
先用一个以往的方法
#includeint main() { int a = 3; int b = 5; a = a + b;//a=8 b = a - b;//b=3 a = a - b;//a=5 printf("a=%d,b=%d",a,b); }
得到的结果
但是这样写有一个缺陷,如果a赋一个很大的值,b赋一个很大的值,a+b可能会超出int整形表示的最大值
所以我们使用刚刚学到的那种方法
#includeint main() { int a = 3; int b = 5; a = a ^ b;//a=8 b = a ^ b;//b=3 a = a ^ b;//a=5 printf("a=%d,b=%d",a,b); }
得到的结果
这里的b可以写成 b = a ^ b ^ b ;两个相同的数异或一定为0,那b就等于a ^ 0,并且0^任何数都等于它本身,那b就等于a的值了
= += -= *= /= >>= <<= %= &= |= ^=
复合赋值:
int x = 10; x = x+10; x += 10;//复合赋值 //其他运算符一样的道理。这样写更加简洁。
需要注意的是: ‘=’ 一个等号才叫赋值,两个等号叫判断相等
5.单目操作符! 逻辑反操作 - 负值 + 正值 & 取地址 sizeof 操作数的类型长度(以字节为单位) ~ 对一个数的二进制按位取反 -- 前置、后置-- ++ 前置、后置++ * 间接访问操作符(解引用操作符) (类型) 强制类型转换!逻辑取反
来看两张图来理解
可以看出这里的 !逻辑取反意思就是把真变假,把假变真
可以写成
#includeint main() { int a = 3; printf("%d",sizeof(a)); printf("%d",sizeof(int)); printf("%d",sizeof a ); }
输出结果为
这里的 printf(“%dn”,sizeof a ) a可以不加括号说明 sizeof 不是函数,是一个操作符
再来举一个例子:
#includeint main() { short s = 5; int a = 10; printf("%dn",sizeof(s = a + 5)); printf("%d",s); }
先想一下这道题的答案再看下面的结果
这里 s = a + 5 是把 a+5 的值赋给了 s 所以 sizeof 输出的结果还是一个短整型 short 所占的的内存,还可以看出 sizeof 括号内的值不参与运算所以下面 s 的输出值没有改变
例如 -1 在二进制中的存放
原码:10000000000000000000000000000001
反码:11111111111111111111111111111110
补码:11111111111111111111111111111111
所以 -1 按位取反后为
00000000000000000000000000000000
得到的 ~-1 的结果为 0
举个例子
int a = 3;
int b = 5;
int c = --a;
int d = b++;
printf("%d %d %d %d",a,b,c,d);
输出结果为
这里的 ++a 是先 运算再赋值;–a是先 赋值再运算
这里看下面的代码就可以很好的理解了
看图来理解
这里可以看到在编译时出现的问题,但如果在3.14前加上一个括号来转换类型就不会出现下面的提示了
> >= < <= != 用于测试“不相等” == 用于测试“相等”
这些关系运算符比较简单,,但是我们要注意一些运算符使用时候的陷阱。
1 . = 是赋值,== 是判断相等。
2 . 比较字符串不能使用 == 来判断
&& 逻辑与 || 逻辑或
他们都是用来判断真假的
&&:(A 和 B都为真,结果才为真,其中一个为假,结果便为假)
|| :(A 和 B其中一个为真,结果就为真,两个都为假,结果才为假)
这里给大家出一道 && 的题:
先自己做完再往下看
#includeint main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++; printf("%d %d %d %d",a, b, c, d); return 0; }
结果为:
这里的 i = a++ && ++b && d++;是先判断a++,但a++是先赋值再运算,这里赋值为 0 了,所以后面的 ++b && d++ 就没有运算
再来一到 || 的题:
#includeint main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ || ++b || d++; printf("%d %d %d %d", a, b, c, d); return 0; }
结果为:
这里的i = a++ || ++b || d++;,判断a++为 0 - 假 ,继续执行 ++b ,++b为真,停止运行,所以结果输出为1 3 3 4
总结:若&&运算符左边表达式为假(0),则其右侧表达式不再计算,整个表达式必然为假;若||运算符左边的表达式为真(非0的值)则其右侧表达式不再计算,整个表达式为真
exp1 ? exp2 : exp3
这里的意思就是如果exp1成立(为真)就执行exp2,否则执行exp3
9.逗号表达式exp1, exp2, exp3, …expN
逗号表达式,从左向右依次计算,但是整个表达式的结果是最后一个表达式的结果
举个例子来理解:
int main()
{
int a = 3;
int b = 4;
int c = 0;
int d = (c = 5, a = b + c, b = c + a);
printf("%d", d);
}
这道题d的结果为14
这里需要注意的是前面的表达式虽然不打印,但也要计算,一定要注意不能直接计算最后一个表达式!
看下面代码来理解
arr【5】是把数组中第六个元素改变了
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
举例:
// 函数的定义
int Add(x,y)
{
return x+y;
}
void text()
{}
int main()
{
int a = 10;
int b = 20;
int ret = Add(a, b);// 这个括号便是叫函数调用操作符;
text();//即使不传参也要加括号
return 0;
}
3. 访问一个结构的成员
. 结构体.成员名 -> 结构体指针->成员名
举例:
假如这里有一本书:书名,书号,价格
创建一个自定义的类型
#includestruct book { char name[20]; char id[20]; int price; }; int main() { struct book a = { "c语言","c54564546",30 }; printf("%sn", a.name); printf("%sn", a.id); printf("%dn", a.price); struct book* pa = &a; printf("%sn", (*pa).name); printf("%sn", (*pa).id); printf("%dn", (*pa).price); printf("%sn", pa->name); printf("%sn", pa->id); printf("%dn", pa->price); }
输出结果



