操作符分类:
1. 算术操作符
+ - * / %
2.移位操作符(操作数只能是整数)
<< 左移操作符
>> 右移操作符
左边抛弃、右边补0
例如:
int a = 2;
int b = a << 1; //把a的二进制位向左移一位
//对一个数移位操作完成后,当前的数不会改变的,除非把它赋值给另外一个变量
printf("a=%d\n",a); // a = 2;
printf("b=%d\n",b); // b = 4;
a的二进制位向左移动一位:
例1:
int a = 10;
int b = a >> 1; //把a的二进制位向右移一位
//对一个数移位操作完成后,当前的数不会改变的,除非把它赋值给另外一个变量
printf("a=%d\n",a); // a = 10
printf("b=%d\n",b); // b = 5
例2(测试该编译器执行 算术右移or逻辑右移):
int a = -1;
int b = a >> 1;
printf("b=%d\n",b); // b = -1 ? b = 2^31 ?
//此时结果b = -1 说明改编译器执行 算术右移
若补0 则输出 2的31次方 ---->逻辑右移
若补1 则输出 1 ---->算术右移
3.位操作符
& 按位与 | 按位或 ^ 按位异或注:他们的操作数必须是整数.
规则:两个位都为1时,结果才为1
例:
按位与的应用:
判断奇偶
根据,末尾是0还是1来决定,末尾为0的是偶数,为1的是奇数
if((a&1)==0)//为偶数则进入条件
规则:两个位都为0时,结果才为0
例:
规则:俩个位相同为0,相异为1
按位异或小公式:
a^a=0 a^0=a a^0^a=0
按位异或的应用:
不能创建临时变量(第三变量),实现两个数的交换
方法二中利用公式:a^a=0 a^0=a
b=a^b=a^(b^b)=a^0=a
a=a^b=a^b^a=b
//方法1
#include
int main()
{
int num = 10;
int count = 0;//计数
while (num)
{
if (num % 2 == 1)
count++;
num = num / 2;
}
printf("二进制中1的个数 = %d\n", count);
return 0;
}
//思考这样的实现方式有没有问题?
//方法2:
#include
int main()
{
int num = -1;
int i = 0;
int count = 0;//计数
for (i = 0; i < 32; i++)
{
if (num & (1 << i))
count++;
}
printf("二进制中1的个数 = %d\n", count);
return 0;
}
//思考还能不能更加优化,这里必须循环32次的。
//方法3:
#include
int main()
{
int num = -1;
int i = 0;
int count = 0;//计数
while (num)
{
count++;
num = num & (num - 1);
}
printf("二进制中1的个数 = %d\n", count);
return 0;
}
//这种方式是不是很好?达到了优化的效果,但是难以想到。
4.赋值操作符
= += -= *= /= %= >>= <<= &= |= ^=
复合赋值符:+= -= *= /= %= >>= <<= &= |= ^=
5.单目操作符
! | 逻辑反操作 |
- | 负值 |
+ | 正值 |
& | 取地址 |
sizeof | 操作符的类型长度(已字节为单位) |
~ | 对一个数的二进制按位取反 |
-- | 前置、后置-- |
++ | 前置、后置++ |
* | 间接访问操作符(解引用操作符) |
(类型) | 强制类型转换 |
1.sizeof操作符计算的是变量(类型)所占空间的大小,是按字节来计算,重要的是,sizeof (a+b)里面的表达式不参与计算,若a,b都是int行类型,其结果依然是4;
2. 当数组作为参数为函数传参时,由于数组要发生降级,其会降级为一个指针,如果此时在一个函数中sizeof计算数组的大小是不可以的,其计算的是数组降级为指针的大小(4个字节or8个字节),所以,若函数要得到一个数组的大小,应该在主函数中计算。
例如:
(2)和(4)传的是地址(指针),sizeof(指针)--指针的大小,取决于使用32位or64位的操作系统
前置++、--
后置++、--
6.关系操作符
> >= < <= !=(不等于) ==(等于)
7.逻辑运算符
&& 逻辑与 || 逻辑或
1 & 2 -----> 0
1 && 2 -----> 1
1 | 2 -----> 3
1 || 2 -----> 1
|
360面试题
求a,b,c,d等于多少?
i = a++ && ++b && d++ 当&&有0时,后面表达式不再计算 例如这里 a++表示先使用a再++,此时a = 0 则后面的表达式++b d++ 不再计算 |
改编一下
i = a ++ || ++b || d++ 当||有1时,后面的表达式不再计算 |
8.条件操作符
exp1 ? exp2 : exp3
9.逗号表达式
exp1 , exp2 , exp3 , …expN
//代码1
int a = 1;
int b = 2;
int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式
c是多少?
//代码2
if (a = b + 1, c = a / 2, d > 0)
//代码3 a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
a = get_val();
count_val(a);
}
如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a > 0)
{
//业务处理
}
10.下标引用、函数调用和结构成员
int arr [ 10 ]; // 创建数组
arr [ 9 ] = 10 ; // 实用下标引用操作符。
[ ] 的两个操作数是 arr 和 9 。
|
#include
void test1()
{
printf("hehe\n");
}
void test2(const char *str)
{
printf("%s\n", str);
}
int main()
{
test1(); //实用()作为函数调用操作符。
test2("hello bit.");//实用()作为函数调用操作符。
return 0;
}
#include
struct Stu
{
char name[10];
int age;
char sex[5];
double score;
};
void set_age1(struct Stu stu) {
stu.age = 18; }
void set_age2(struct Stu* pStu) {
pStu->age = 18;//结构成员访问
}
int main()
{
struct Stu stu;
struct Stu* pStu = &stu;//结构成员访问
stu.age = 20;//结构成员访问
set_age1(stu);
pStu->age = 20;//结构成员访问
set_age2(pStu);
return 0;
}
11.表达式求值
//实例1
char a,b,c;
...
a = b + c
// 负数的整形提升
char c1 = - 1 ;
变量 c1 的二进制位 ( 补码 ) 中只有 8 个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为 1
提升之后的结果是:
11111111111111111111111111111111
// 正数的整形提升
char c2 = 1 ;
变量 c2 的二进制位 ( 补码 ) 中只有 8 个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为 0
提升之后的结果是:
00000000000000000000000000000001
// 无符号整形提升,高位补 0
|
//实例1
//整型提升
int main()
{
char a = 3;
//3 --> 00000000000000000000000000000011
//00000011 --> a
char b = 127;
//127 --> 00000000000000000000000001111111
//01111111 --> b
char c = a + b;
//00000000000000000000000000000011
//00000000000000000000000001111111
//00000000000000000000000010000010
//截断后得到10000010
//10000010 --> c 此时C还是char类型,要想输出int类型,就要整型提升
//11111111111111111111111110000010(我们知道在内存当中存放的其实是补码,打印出来的是原码)
//求原码得:10000000000000000000000001111110 ——> -126
//a和b都是char类型,都没有达到一个int的大小
//这里就会发生整型提升
printf("c=%d\n", c);// -126
return 0;
}
//实例2
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if(a==0xb6)
printf("a");
if(b==0xb600)
printf("b");
if(c==0xb6000000)
printf("c");
return 0; }
//实例3
int main()
{
char c = 1;
printf("%u\n", sizeof(c)); //1
printf("%u\n", sizeof(+c)); //4
printf("%u\n", sizeof(-c)); //4
printf("%u\n", sizeof(!c)); //4 - gcc
return 0; }
long double
double
float
unsigned long int
long int
unsigned int
int
|
float f = 3.14 ;
int num = f ; // 隐式转换,会有精度丢失
|
// 表达式的求值部分由操作符的优先级决定。
// 表达式 1
a * b + c * d + e * f
|
a * b —>c * d —>a * b + c * d —>e * f —>a * b + c * d + e * f
或者
a * b—>c * d —>e * f —>a * b + c * d —>a * b + c * d + e * f
|
// 表达式 2
c + -- c ;
|
//代码3-非法表达式
int main()
{
int i = 10;
i = i-- - --i * ( i = -3 ) * i++ + ++i;
printf("i = %d\n", i);
return 0;
}
//代码4
int fun()
{
static int count = 1;
return ++count; }
int main()
{
int answer;
answer = fun() - fun() * fun();
printf( "%d\n", answer);//输出多少?
return 0; }
//代码5
#include
int main()
{
int i = 1;
int ret = (++i) + (++i) + (++i);
printf("%d\n", ret);
printf("%d\n", i);
return 0; }
//尝试在linux 环境gcc编译器,VS2022环境下都执行,看结果。
自己尝试一下吧!