(一)操作符分类
算术操作符;移位操作符;位操作符;赋值操作符;单目操作符;关系操作符;逻辑操作符;条件操作符;逗号表达式;下标引用,函数调用和结构成员。
(二)算术操作符
1./操作符的两个操作数都是整数,执行整数除法(取商),而只要有浮点就是浮点除法;
2.%操作符只适用于整形数,其他操作符都适用于整数和浮点数;
(三)移位操作符(移的是补码)
//移动的是二进制位
>> //右移操作符
<< //左移操作符
1.右移操作符(移一次相当于除2)
1.1逻辑右移
右边丢弃,左边用0填充
1.2算术右移
右边丢弃,左边补原符号位
2.左移操作符(移一次相当于乘2)
左边丢弃,右边补0
注:移位操作符只作用于整数,而且不要移动负数位!
(四)位操作符(按二进制位)
& //按位与 对应二进制位有0为0
| //按位或 对应二进制位有1为1
^ //按位异或 对应二进制位相同为0,相异为1
1.面试题:不创建临时变量,交换两个数
错误,这样可能会溢出
#include<stdio.h>
int main()
{
//加减法
int a = 3;
int b = 5;
printf("交换前a=%d,b=%d\n", a, b);
a = a + b;
b = a - b;
a = a - b;
printf("交换后a=%d,b=%d\n", a, b);
return 0;
}
正确,异或
#include<stdio.h>
int main()
{
//加减法
int a = 3;
int b = 5;
printf("交换前a=%d,b=%d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后a=%d,b=%d\n", a, b);
return 0;
}
a = a ^ b______a110=a011^b101
b = a ^ b______b011=a110^b101
a = a ^ b______a101=a110^b011
a,b异或产生的密码,和原来的a异或产生b,和原来的b异或产生a;
2.求一个储存在内存中的二进制数中1的个数
#include<stdio.h>
int main()
{
int count = 0;
int num = 0; scanf("%d", &num);
{
while (num)
{
if (num % 2 == 1) //类似十进制数,模10,商10就可以逐渐得到每一位数。
count++;
num = num / 2;
}
printf("%d", count);
}
return 0;
}
看似正确,但为负数时错误,优化算法如下:
#include<stdio.h>
int main()//思路:通过移位,和1按位与来确定每一位数是否为1.
{
int i = 0;
int count = 0;
int num = 0;
scanf("%d", &num);
for (i = 0; i < 32; i++)
{
if ((1 & (num >> i)) == 1)
count++;
}
printf("%d\n", count);
return 0;
}
还可以优化,但是很难想到:
#include <stdio.h>
int main()
{
int num = -1;
int i = 0;
int count = 0;
while (num)
{
count++;
num = num & (num - 1);
}
printf("%d\n", count);
return 0;
}
(五)赋值操作符
a=1;
连续使用a=x=y+1
,但是代码风格不好;
符合赋值
+=
a+=b______a加b的值赋给a
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
(六)单目操作符
像a+b这种有两个操作数的时双目操作符
1.常见类型
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(字节为单位)
~ 对一个数的二进制按位取反
-- 自减
++ 自增
* 间接访问操作符
(类型) 强制类型转换
2.sizeof
#include<stdio.h>
int main()
{
int a = 10;
char c = 'r';
char* p = &c;
int arr[10] = { 0 };
printf("%d\n", sizeof a);
printf("%d\n", sizeof(int));//类型不能去括号
printf("%d\n", sizeof(c));
printf("%d\n", sizeof(char));
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(char*));
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(int[10]));//可以通过数组名或类型来计算大小
return 0;
}
观察一以下式子,解释为什么结果为2,0:
sizeof内部的表达式不参与运算,所以s最后还是为0;short限制了sizeof的类型,所以无论整么加,都是2字节。
练习
#include <stdio.h>
void test1(int arr[])
{
printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));//(4)
}
int main()
{
int arr[10] = { 0 };
char ch[10] = { 0 };
printf("%d\n", sizeof(arr));//(1)
//printf("%d\n", sizeof(int[10]));结果也是40
printf("%d\n", sizeof(ch));//(3)
test1(arr);
test2(ch);
return 0;
}
//问:
//(1)、(2)两个地方分别输出多少?
//(3)、(4)两个地方分别输出多少?
3.~
#include <stdio.h>
int main()
{
int a = 0;
//000000000000000000000000000;计算机中储存的补码;
//111111111111111111111111111;按位取反得到的补码;
//想要输出,需要先转回原码:
//111111111111111111111111110;反码
//100000000000000000000000001;原码
printf("%d\n",~a);
return 0;
}
打印结果为-1
尝试理解以下代码:
int main()
{
int a = 11;//0000000000000000001011
//0000000000000000000100___1<<2
//0000000000000000001111
a = a | (1 << 2);
printf("%d\n", a);
//还原
a = a & (~(1 << 2));
printf("%d\n", a);
return 0;
}
4.++ --
前置先加加再使用,后置先使用后加加
#include <stdio.h>
void test1(int arr[])
{
printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));//(4)
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
printf("%d\n", sizeof(arr));//(1)
printf("%d\n", sizeof(ch));//(3)
test1(arr);
test2(ch);
return 0;
}
//问:
//(1)、(2)两个地方分别输出多少?
//(3)、(4)两个地方分别输出多少?