C语言学习入门第五节————操作符详解(上)

系列文章目录

C语言学习入门第五节————操作符详解(上)

操作符详解

  1. 操作符分类
  2. 算术操作符
  3. 位移操作符
  4. 位操作符
  5. 赋值操作符
  6. 单目操作符
  7. 关系操作符
  8. 逻辑操作符
  9. 条件操作符
  10. 逗号表达式
  11. 下标引用、函数调用和结构成员
  12. 表达式求值


一、操作符分类

算术操作符: + —— - —— * —— / —— %

移位操作符: << —— >>

位操作符: & —— | —— ^

赋值操作符: = —— += —— -= —— *= —— /= ……

单目操作符: ! —— sizeof —— + —— - —— ~ —— & —— *

关系操作符: > —— < —— >= —— <= —— == —— !=

逻辑操作符: && —— ||

条件操作符: ? —— :

逗号操作符: ,

下标引用、函数调用和结构成员: [] —— () —— . —— ->

二、算术操作符

+ : 加法运算
- :减法运算
* :乘法运算
/ :除法运算(除数不能为0)
% : 取模操作符,得到的是整除后的余数
(注:除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数)

/ :除法运算,除数不能为0

  1. 整数除法(除号两端都是整数)
  2. 浮点数除法(除号两端只要有一个小数就执行浮点数除法)

整数除法(除号两端都是整数)

#include <stdio.h>

int main()
{
	int r = 7 / 2;// 两端都是整数,是整数除法
	printf("%d\n", r);
	double d = 7 / 2;
	printf("%lf\n", d);//3.5?
	                   //用浮点数类型变量存放整数除法结果,结果是不能够精确到小数位的。 
	                   //所以结果是3.00000
	return 0;

在这里插入图片描述
###浮点数除法(除号两端只要有一个小数就执行浮点数除法)

#include <stdio.h>

int main()
{
	double d = 7.0 / 2.0;
    printf("%lf\n", d);//3.500000
	return 0;
}

在这里插入图片描述

除数不能为0

#include <stdio.h>
int main()
{
	int n = 0;
	int d = 7 / n;
    printf("%lf\n", d);
	return 0;
}

在这里插入图片描述

%:取模操作符,得到的是整除后的余数

#include <stdio.h>
int main()
{
	int d = 7 % 3;//%得到的是整除后的余数。
    printf("%d\n", d);
	return 0;
}

在这里插入图片描述

%取模操作符的两个操作数必须是整数

#include <stdio.h>
int main()
{
	int d = 7 % 3.0;//%取模操作符的两个操作数必须都是整数。 
	int c = 7.0% 3.0;
	printf("%d\n", d);
	return 0;
}

在这里插入图片描述

三、移位操作符 * * *

移位操作符的操作数只能是整数,对于一位运算符,不要移动负数位,这是标准未定义的,计算结果将取决于编译器,结果不可预料.

整数的二进制表示形式 * * * * *

有三种表现形式:

原码 // 反码 // 补码

  1. 正整数的原码、反码、补码是相同的

  2. 负整数的原码、反码、补码是要计算的

  3. 不管是正整数还是负整数都可以写出二进制原码

  4. 根据正负直接写出的二进制序列就是原码

  5. 移位移动的是二进制信息

  6. 整数在内存中存储的是补码

  7. 计算的时候也是使用补码计算的

#include <stdio.h>
//不管是正整数还是负整数都可以写出二进制原码
//根据正负直接写出的二进制序列就是原码
int main()
{
	//1个整型是4个字节 = 32个bit位
	//符号位是 1 表示负数
	//符号位是 0 表示正数
 
	int a = 15;
	//正整数的原码、反码、补码是相同的
	//00000000000000000000000000001111 -- 原码
	//00000000000000000000000000001111 -- 反码
	//00000000000000000000000000001111 -- 补码
 
	int b = -15;
	//负整数的原码、反码、补码是要计算的
	//10000000000000000000000000001111 -- 原码
	//11111111111111111111111111110000 -- 反码(原码的符号位不变,其它位按位取反得到的就是反码)
	//11111111111111111111111111110001 -- 补码(反码 +1 就是补码)
 
	return 0;
}

<< : 左移操作符 – 补码 左边丢弃,右边补0 ( * * *

#include <stdio.h>
 
int main()
{
//正整数:
	int a = 6;
	//   00000000000000000000000000000110 -- 正整数的 原码、反码、补码 相同
	//   00000000000000000000000000000110 -- 补码 (移位操作的是 补码)
					//左移后:
	// 0 00000000000000000000000000001100 -- 补码 (原码 、 反码)
	//   因为正整数的 原码、反码、补码 相同,所以这也是原码
	int b = a << 1;
	printf("%d\n", b);
	printf("%d\n", a);
//负整数:
	int c = -6;
	//   10000000000000000000000000000110 -- 原码
	//   11111111111111111111111111111001 -- 反码 (原码按位取反)
	//   11111111111111111111111111111010 -- 补码 (反码 +1 )
	int d = c << 1;
				//左移后:
	// 1 11111111111111111111111111110100 -- 补码
	//   11111111111111111111111111110011 -- 反码 (补码 -1)
	//   10000000000000000000000000001100 -- 原码 (符号位不变,反码按位取反)
	// -12
	printf("%d\n", d);
 	printf("%d\n", c); 
	a = a << 1;
	// 也可以写成:
	a <<= 1; //符合符号 <<= :左移等于 ,类似 a += 1
	return 0;
}

在这里插入图片描述

>> : 右移操作符 ( * * * *

  1. 算术 右移 (补码 右边 丢弃, 左边 补原来的符号位)
  2. 逻辑 右移 (补码 右边 丢弃, 左边 直接补0)
  3. 有类似 除以2向下取整 的效果

C语言没有明确规定到底是算术右移还是逻辑右移,一般编译器上采用的是算术右移

#include <stdio.h>
 
int main()
{
//正整数:
	int a = 15;
	//00000000000000000000000000001111 -- 补码
	int b = a >> 1;
	// 0 0000000000000000000000000000111 1 -- 补码(移位后)
	//C语言没有明确规定到底是算术右移还是逻辑右移,一般编译器上采用的是算术右移
	printf("%d\n", b); //算术右移
	// b 得到的是 a 移位后的结果
	// 算术右移(右边丢弃,左边补原来的符号位)
	// 从 二进制的1111 变成 二进制的111 ,从 十进制的 15 变成了 十进制的 7 	
	printf("%d\n", a);
	// a >> 1,进行移位后,a没有发生变化,
	// 表达式不会影响 a 的 值
	
//负整数:
	int c = -15;
	//11111111111111111111111111110001 -- 补码 (符号位是 1 表示负数)
	int d = c >> 1;
	// 1 1111111111111111111111111111000 1 -- 补码 (移位后)
	// 空出的位置补的是 1 ,说明是算术右移(右边丢弃,左边补原来的符号位)
 
	// 实际值是用 原码 表示的
 
	printf("%d\n", d); //算术右移
	// 反码 +1 就是补码 ,补码 -1 就是反码:
	//  11111111111111111111111111110111 -- 反码
	// 原码的符号位不变,反码按位取反得 原码
	//  10000000000000000000000000001000 -- 原码 (-8)
	printf("%d\n", c);	
	return 0;
}

在这里插入图片描述

四、位操作符 * * * * *

  1. 整数在内存中存储的是补码

  2. 计算的时候也是使用补码计算的
    注:位操作符的操作数必须是整数
    位操作符有:

& —— 按位与
| —— 按位或
^ —— 按位异或

& : 按(二进制)位与 ----- 对应二进制位有0则为0,两个 同时为1,才为1( * * * * *

#include <stdio.h>
 
int main()
{
	int a = 3;
	// 00000000000000000000000000000011 -- 补码(正整数的原码、反码、补码相同)
 
	int b = -5;
	// 10000000000000000000000000000101 -- 原码
	// 11111111111111111111111111111010 -- 反码
	// 11111111111111111111111111111011 -- 补码
 
	int c = a & b;
	// & -- 对应二进制位有0则为0,两个同时为1,才为1
	// 00000000000000000000000000000011 -- a补码
	// 11111111111111111111111111111011 -- b补码
	//				得:
	// 00000000000000000000000000000011	-- 补码(两个补码计算出来的也是补码)
	// 这里计算出来的结果符号位是 0 ,说明是 正整数,三个码相同,所以这也是原码
	
 
	printf("%d\n", c); // 所以结果是3
 
	return 0;
}

在这里插入图片描述

| : 按(二进制)位或 ----- 对应二进制位有1则为1,两个同时为0才为0( * * * * *

//位操作符
#include <stdio.h>
 
int main()
{
	int a = 3;
	// 00000000000000000000000000000011 -- 补码(正整数的原码、反码、补码相同)
	int b = -5;
	// 10000000000000000000000000000101 -- 原码
	// 11111111111111111111111111111010 -- 反码
	// 11111111111111111111111111111011 -- 补码
	int c = a | b;
	// | -- 按(二进制)位或 -- 对应二进制位有1则为1,两个同时为0,才为0
	// 00000000000000000000000000000011 -- a补码
	// 11111111111111111111111111111011 -- b补码
	//				得:
	// 11111111111111111111111111111011	-- 补码(两个补码计算出来的也是补码)
	// 
	// 这里计算出来的结果符号位是 1 ,说明是 负整数,还要计算 反码 和 补码
	// 11111111111111111111111111111010 -- 反码
	// 10000000000000000000000000000101 -- 原码
	printf("%d\n", c); // 所以结果是-5
	return 0;
}

在这里插入图片描述

^ : 按(二进制)位异或 -----对应二进制位相同为0相异为1( * * * * *

#include <stdio.h>
 
int main()
{
	int a = 3;
	// 00000000000000000000000000000011 -- 补码(正整数的原码、反码、补码相同)
	int b = -5;
	// 10000000000000000000000000000101 -- 原码
	// 11111111111111111111111111111010 -- 反码
	// 11111111111111111111111111111011 -- 补码 
	int c = a ^ b;
	// ^ -- 按(二进制)位异或 -- 对应二进制位相同为0, 相异为1
	// 00000000000000000000000000000011 -- a补码
	// 11111111111111111111111111111011 -- b补码
	//				得:
	// 11111111111111111111111111111000	-- 补码(两个补码计算出来的也是补码)
	// 
	// 这里计算出来的结果符号位是 1 ,说明是 负整数,还要计算 反码 和 补码
	// 10000000000000000000000000000111 -- 反码
	// 10000000000000000000000000001000 -- 原码
	printf("%d\n", c); // 所以结果是-8
	return 0;
}

在这里插入图片描述

^(按位异或) 的一些规律:

  1. 变量a ^ 变量a = 0
  2. 0 ^ 变量a = 变量a
  3. 满足交换律
#include <stdio.h>
 
int main()
{
	int a = 3;
	int b = 5;
 
	printf("%d\n", a ^ a); // 0 (每一位都是相同的,32位全是0)
	printf("%d\n", a ^ 0); // a = 3
	// 011 - 3 (a)
	// 000 - 0
	// 011 -- 异或结果 :a = 3 
 
	printf("%d\n", a ^ b ^ a); // b = 5
	// 011 - 3 (a)
	// 101 - 5 (b)
	// 110 -- 异或结果
	// 011 - 3 (a)
	// 101 -- 异或结果 : b = 5
 
	printf("%d\n", a ^ a ^ b); // b = 5
	// a ^ a --> 0
	// 0 ^ b --> b = 5
 
 
 
	return 0;
}

在这里插入图片描述

不使用临时变量,交换两个数的值

方法一(有缺陷)

当a,b特别大时a + b会超出整形能表示的最大值

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

在这里插入图片描述

求一个整数存储在内存中的二进制中1的个数( * *

#include <stdio.h>
 
int main() {
    int input = 0;
    int count = 0; //统计 1 的个数
    //输入
    scanf("%d", &input);
 
    int i = 0;
    for (i = 0; i < 32; i++)
    { // 共32位,判断32次
 
        int test = input & 1; //按位与1 取出32位最低位
        //判断是不是1
        if (test == 1) {
            count++; //是的话,统计加1
        }
        //判断下一位:
        input >>= 1; //向右移一位,继续判断,使用循环
 
    }
 
    //输出:
    printf("%d", count);
 
    return 0;
}

在这里插入图片描述

五、赋值操作符

=: 赋值操作符 – 可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值

int weight = 120;
//体重 weight = 89; //不满意就赋值换掉
double salary =10000.0;
salary = 20000.0 //使用赋值操作符赋值

可以连续赋值(不推荐)

int a = 10;
int x = 0;
int y = 20;
 
a = x = y+1; //选择赋值
//先把 y+1 赋给 x ,再把 x 赋给 a
 
//更好的写法:
x = y + 1;
a = x;
//这样写更加清晰而且方便一步步调试 

复合赋值符:

+= : 加等于

-= : 减等于

*= : 乘等于

/= : 除等于

%= : 模等于

>>= : 右移等于

<<= : 左移等于

&= : 按位与等于

|= : 按位或等于

^= : 按位异或等于

六、单目操作符

1.单目操作符介绍( * * * *

! 逻辑反操作(if语句、while语句中、表达式中)
- 负值
+ 正值
& 取地址(应用于指针)
sizeof操作数的类型长度(以字节为单位)(不是函数,是操作符;计算的是类型创建变量的大小) ~ 对一个数的二进制按位取反(对补码32个bit位按位取反,1变成0,0变成1,取反后还是补码,要转换为原码)
- - 前置、后置- -
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型)强制类型转换(应用于指针,告诉我们哪个变量是指针变量;解引用:通过指针变量中存放的地址,找到指向的 空间/内容 )

2.sizeof 和 数组( * * *

#include <stdio.h>
void test1(int arr[]) 
//传过来的首元素指针 ,一个 int*类型 大小是 4个字节
{
	printf("%d\n", sizeof(arr));
}
 
void test2(char ch[])
//传过来的首元素指针 ,一个 char*类型 大小是 4个字节
{
	printf("%d\n", sizeof(ch));
}
 
int main()
{
//整型数组:
	int arr[10] = { 0 };
	printf("%d\n",sizeof(arr)); //使用 数组名
	//40 - 计算整个数组的大小、单位字节
	printf("%d\n", sizeof(int[10])); //使用数组的字符类型,包括[]和元素个数
	test1(arr);
//字符数组
	char ch[10] = { 0 };
 
	printf("%d\n", sizeof(ch)); //使用 数组名
	//10 -- 字符数组中 sizeof(数组名) 计算 的是 字符个数
	printf("%d\n", sizeof(int[10])); //使用数组的字符类型,包括[]和元素个数
	//40 -- 一个 char类型元素 是 4个字节,10个就是40
 
	test2(ch);
 
	return 0;
}

在这里插入图片描述

3.单目操作符运用

~ 按位取反的运用,结合 & (按位与) 和 | (按位或):( * * * *

//将 13 的 32bit位从右往左第5位,换为 1 ,再换为 0
#include <stdio.h>
 
int main()
{
	int a = 13;
 
	// 00000000000000000000000000001101 - 13 的 原、反、补码
	//			按位或:有1就是1
	// 00000000000000000000000000010000 - 1 << 4
	// 00000000000000000000000000011101 -- 29 的 原、反、补码
	a |= (1 << 4);
	// 这样就把第五位换成了 1 , 13 变成了 29 
 
	printf("%d\n", a); 
 
	// 再把第五位换成 0
	// 00000000000000000000000000011101 - 29 的 原、反、补码
	// 00000000000000000000000000010000 - 1 << 4
	// 11111111111111111111111111101111 - ~(1 << 4) 进行按位取反
	//			按位或:两个都是 1 才是 1
	// 00000000000000000000000000001101 -- 13 的 原、反、补码
	a &= (~(1 << 4));
 
	printf("%d", a);
 
	return 0;
}

在这里插入图片描述

运用 ~按位取反 实现 多组输入

#include <stdio.h>
 
int main()
{
	int a = 0;
 
	// scanf 读取失败返回的是EOF
	// 假设 scanf 读取失败,返回EOF ,即 -1
	// -1 的补码:
	// 11111111111111111111111111111111
	//			~ 按位取反后:
	// 00000000000000000000000000000000
	//			得0,条件即为假
	
	while (~scanf("%d", &a))
	{
		printf("%d\n", a);
	}
 
	return 0;
}

在这里插入图片描述

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值