【C语言有这个就够了】四.操作符详解(1)

时间:2022-10-09 16:15:03

(一)操作符分类

算术操作符;移位操作符;位操作符;赋值操作符;单目操作符;关系操作符;逻辑操作符;条件操作符;逗号表达式;下标引用,函数调用和结构成员。

(二)算术操作符

+ - * / %

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;
}

【C语言有这个就够了】四.操作符详解(1)

观察一以下式子,解释为什么结果为2,0:

【C语言有这个就够了】四.操作符详解(1)

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.++   --

【C语言有这个就够了】四.操作符详解(1)

前置先加加再使用,后置先使用后加加

#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)两个地方分别输出多少?