【C语言】操作符详解


在这里插入图片描述

上期回顾: 【C语言】函数递归
个人主页:C_GUIQU
归属专栏:C语言

在这里插入图片描述

前言

各位小伙伴大家好!上期小编给大家讲解了C语言中的函数递归,接下来详细讲讲操作符!
在这里插入图片描述

1. 操作符分类

  • 算术操作符: + 、- 、* 、/ 、%
  • 移位操作符: << 、>>
  • 位操作符: &、 | 、^
  • 赋值操作符: = 、+= 、 -= 、 *= 、 /= 、%= 、<<= 、>>= 、&= 、|= 、^=
  • 单⽬操作符: !、++、–、&、*、+、-、~ 、sizeof、(类型)
  • 关系操作符: > 、>= 、< 、<= 、 == 、 !=
  • 逻辑操作符: && 、||
  • 条件操作符: ? :
  • 逗号表达式: ,
  • 下标引用: []
  • 函数调用:()
  • 结构成员访问:. 、->

由于有⼀些操作符和⼆进制有关,所以我们先铺垫⼀下二进制和进制转换的知识。

2. 二进制和进制转换

2.1 二进制

  • 2进制中满2进1
  • 2进制的数字每⼀位都是0~1的数字组成

2.2 进制转换

2.2.1 二进制转十进制

【方法】基数乘以指数的n次方,以 2 为指数,进制值所在的位置为n(从0开始算起),进制值本身为基数。

在这里插入图片描述
【举例】

如下面列子:1010就是基数,其进制值的位置就是n。

在这里插入图片描述

2.2.2 二进制转八进制

【方法】

在这里插入图片描述
【举例】
在这里插入图片描述

2.2.3 二进制转十六进制

【方法】

  1. 从二进制数的最右边开始,将二进制数每四位分为一组。如果最左边的组不足四位,则在前面补零以使其成为四位。
  2. 将每组四位二进制数转换为其对应的十六进制数。
  3. 将所有十六进制数字连在一起,得到最终的十六进制数。

【举例】
在这里插入图片描述

3. 原码、反码、补码

【整数的2进制表示方法】原码、反码和补码
【符号位和数值位】2进制序列中,最⾼位的1位是被当做符号位(0正1负),剩余的都是数值位。

【概念】

  • 原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
  • 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
  • 补码:反码+1就得到补码。

【性质】

  • 正整数的原、反、补码都相同。
  • 负整数的三种表示方法各不相同。
  • 补码得到原码也是可以使用“取反,+1”的操作。
  • 对于整形来说:数据存放内存中其实存放的是补码。

4. 移位操作符

在这里插入图片描述

4.1 左移操作符

【移位规则】左边抛弃、右边补0

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

在这里插入图片描述

4.2 右移操作符

【移位规则】

  1. 逻辑右移:左边⽤0填充,右边丢弃。
  2. 算术右移:左边⽤原该值的符号位填充,右边丢弃
#include <stdio.h>
int main()
{
	int num = 10;
	int n = num>>1;
	printf("n= %d\n",n);
	printf("num= %d\n",num);
	return 0;
}

【警告】对于移位运算符,不要移动负数位,这个是标准未定义的。

5. 位操作符

& //按位与
| //按位或
^ //按位异或
~ //按位取反
//操作数都必须是整数

【示例】

#include <stdio.h>
int main()
{
	int num1 = -3;
	int num2 = 5;
	printf("%d\n",num1 & num2);
	printf("%d\n",num1 | num2);
	printf("%d\n",num1 ^ num2);
	printf("%d\n",~0);
	return 0;
}

【不能创建临时变量(第三个变量),实现两个整数的交换】

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	a = a^b;
	b = a^b;
	a = a^b;
	printf("a = %d b = %d\n",a,b);
	return 0;
}

6. 单目操作符

++
--
&
*
+
-
~ 
sizeof(类型)

比较简单,不过多赘述。

7. 逗号表达式

  • 逗号表达式,就是⽤逗号隔开的多个表达式。
  • 逗号表达式,从左向右依次执⾏。整个表达式的结果是最后⼀个表达式的结果。
//代码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)
	{
		//业务处理
	}

8. 下标引用操作符

操作数:⼀个数组名 + ⼀个索引值(下标)

int arr[10];//创建数组
arr[9] = 10;//实⽤下标引⽤操作符。
//[ ]的两个操作数是arr和9。

9. 函数调用操作符

接受⼀个或者多个操作数:第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数。

#include <stdio.h>
void test1()
{
	printf("hehe\n");
}
void test2(const char* str)
{
	printf("%s\n",str);
}
int main()
{
	test1(); //这⾥的()就是作为函数调⽤操作符。
	test2("hello bit.");//这⾥的()就是函数调⽤操作符。
	return 0;
}

10. 结构体和结构成员访问操作符

10.1 结构体

10.1.1 结构的声明

struct tag
{
	 member-list;
}variable-list;

【描述一个学生】

struct Stu
{
	 char name[20];//名字
	 int age;//年龄
	 char sex[5];//性别
	 char id[20];//学号
}; //分号不能丢

10.1.2 结构体变量的定义和初始化

//代码1:变量的定义
struct Point
{
	int x;
	int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//代码2:初始化。
struct Point p3 ={ 10, 20 };
struct Stu //类型声明
{
	char name[15];//名字
	int age; //年龄
};
struct Stu s1 ={ "zhangsan", 20 };//初始化
struct Stu s2 ={ .age=20, .name="lisi" };//指定顺序初始化
//代码3
struct Node
{
	int data;
	struct Point p;
	struct Node* next;
}n1 ={ 10, {4,5}, NULL }; //结构体嵌套初始化
struct Node n2 ={ 20, {5, 6}, NULL };//结构体嵌套初始化

10.2 结构成员访问操作符

10.2.1 结构体成员的直接访问

#include <stdio.h>
struct Point
{
	int x;
	int y;
}p ={ 1,2 };
int main()
{
	printf("x: %d y: %d\n",p.x,p.y);
	return 0;
}

10.2.2 结构体成员的间接访问

#include <stdio.h>
struct Point
{
	int x;
	int y;
};
int main()
{
	struct Point p ={ 3, 4 };
	struct Point* ptr = &p;
	ptr->x = 10;
	ptr->y = 20;
	printf("x = %d y = %d\n",ptr->x,ptr->y);
	return 0;
}
#include <stdio.h>
#include <string.h>
struct Stu
{
	char name[15];//名字
	int age; //年龄
};
void print_stu(struct Stu s)
{
	printf("%s %d\n",s.name,s.age);
}
void set_stu(struct Stu* ps)
{
	strcpy(ps->name,"李四");
	ps->age = 28;
}
int main()
{
	struct Stu s ={ "张三", 20 };
	print_stu(s);
	set_stu(&s);
	print_stu(s);
	return 0;
}

11. 操作符的属性:优先级、结合性

11.1 优先级

【优先级】如果⼀个表达式包含多个运算符,哪个运算符应该优先执行。
【示例】
表达式 3 + 4 * 5 ⾥⾯既有加法运算符( + ),⼜有乘法运算符( * )。由于乘法的优先级⾼于加法,所以会先计算 4 * 5 ,⽽不是先计算 3 + 4 。

11.2 结合性

如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符
是左结合,还是右结合,决定执⾏顺序。⼤部分运算符是左结合(从左到右执⾏),少数运算符是右 结合(从右到左执⾏),⽐如赋值运算符( = )。

圆括号( () )
• ⾃增运算符( ++ ),⾃减运算符( -- )
• 单⽬运算符( + 和 - )
• 乘法( * ),除法( / )
• 加法( + ),减法( - )
• 关系运算符( <> 等)
• 赋值运算符( = )
由于圆括号的优先级最⾼,可以使⽤它改变其他运算符的优先级。

12. 表达式求值

在C语言中,表达式的求值遵循特定的规则和运算符优先级。这些规则确保了表达式的求值顺序是一致的,无论表达式的复杂性如何。以下是一些基本的求值规则和概念:

  1. 运算符优先级:C语言中的运算符按照特定的优先级进行分组,优先级高的运算符先于优先级低的运算符进行求值。例如,乘法和除法的优先级高于加法和减法。
  2. 结合性:当表达式中存在多个相同优先级的运算符时,根据结合性决定求值的顺序。大多数运算符是左结合的,这意味着它们从左到右进行求值。例如,在表达式 a = b = c 中,b = c 先求值,然后将结果赋值给 a
  3. 括号:括号可以改变运算符的优先级,括号内的表达式首先被求值。例如,在表达式 (a + b) * c 中,首先求值 a + b,然后将结果与 c 相乘。
  4. 求值顺序:在C语言中,除了一些特殊情况(如逗号运算符和条件运算符),运算符的求值顺序是不确定的。这意味着在表达式 a++ + b 中,a++ 可能会在 b 之前、之后或同时被求值,这取决于具体的编译器实现。
  5. 副作用:表达式的求值可能会产生副作用,如修改变量的值(例如,a++*p = 42)。副作用的顺序也是不确定的,除非使用了序列点(sequence point),例如在表达式的末尾或逻辑与(&&)、逻辑或(||)运算符的求值过程中。
  6. 类型转换:在表达式中,如果操作数的类型不同,C语言会根据规则进行隐式类型转换,使得操作数具有相同的类型后再进行运算。
    例如,考虑以下C语言表达式:
int a = 5, b = 3, c = 2, d = 8;
int result = a * b + c / d;

求值步骤如下:

  1. 根据优先级,先进行乘法和除法:
    • a * b 结果为 15
    • c / d 结果为 0(因为C语言中的整数除法会向下取整)
  2. 然后进行加法:
    • 15 + 0 结果为 15
  3. 最后,将结果 15 赋值给变量 result

在实际编程中,理解这些规则对于编写正确且高效的代码至关重要。如果需要更精确的控制表达式的求值顺序,应该使用括号来明确指定。

结语

以上就是小编对操作符的详细讲解。
如果觉得小编讲的还可以,还请一键三连。互三必回!
持续更新中~!
在这里插入图片描述

下载前可以先看下教程 https://pan.quark.cn/s/16a53f4bd595 小天才电话手表刷机教程 — 基础篇 我们将为您简单的介绍小天才电话手表新机型的简单刷机以及玩法,如adb工具的使用,magisk的刷入等等。 我们会确保您看完此教程后能够对Android系统有一个最基本的认识,以及能够成功通过magisk root您的手表,并安装您需要的第三方软件。 ADB Android Debug Bridge,简称,在android developer的adb文档中是这么描述它的: 是一种多功能命令行工具,可让您与设备进行通信。 该命令有助于各种设备操作,例如安装和调试应用程序。 提供对 Unix shell 的访问,您可以使用它在设备上运行各种命令。 它是一个客户端-服务器程序。 这听起来有些难以理解,因为您也没有必要去理解它,如果您对本文中的任何关键名词产生疑惑或兴趣,您都可以在搜索引擎中去搜索它,当然,我们会对其进行简单的解释:是一款在命令行中运行的,用于对Android设备进行调试的工具,并拥有比一般用户以及程序更高的权限,所以,我们可以使用它对Android设备进行最基本的调试操作。 而在小天才电话手表上启用它,您只需要这么做: - 打开拨号盘; - 输入; - 点按打开adb调试选项。 其次是电脑上的Android SDK Platform-Tools的安装,此工具是 Android SDK 的组件。 它包括与 Android 平台交互的工具,主要由和构成,如果您接触过Android开发,必然会使用到它,因为它包含在Android Studio等IDE中,当然,您可以独立下载,在下方选择对应的版本即可: - Download SDK Platform...
已经博主授权,源码转载自 https://pan.quark.cn/s/b24469074755 SmartDNS English SmartDNS SmartDNS 是一个运行在本地的 DNS 服务器,它接受来自本地客户端的 DNS 查询请求,然后从多个上游 DNS 服务器获取 DNS 查询结果,并将访问速度最快的结果返回给客户端,以此提高网络访问速度。 SmartDNS 同时支持指定特定域名 IP 地址,并高性匹配,可达到过滤广告的效果; 支持DOT,DOH,DOQ,DOH3,更好的保护隐私。 与 DNSmasq 的 all-servers 不同,SmartDNS 返回的是访问速度最快的解析结果。 支持树莓派、OpenWrt、华硕路由器原生固件和 Windows 系统等。 使用指导 SmartDNS官网:https://pymumu..io/smartdns 软件效果展示 仪表盘 SmartDNS-WebUI 速度对比 阿里 DNS 使用阿里 DNS 查询百度IP,并检测结果。 SmartDNS 使用 SmartDNS 查询百度 IP,并检测结果。 从对比看出,SmartDNS 找到了访问 最快的 IP 地址,比阿里 DNS 速度快了 5 倍。 特性 多虚拟DNS服务器 支持多个虚拟DNS服务器,不同虚拟DNS服务器不同的端口,规则,客户端。 多 DNS 上游服务器 支持配置多个上游 DNS 服务器,并同时进行查询,即使其中有 DNS 服务器异常,也不会影响查询。 支持每个客户端独立控制 支持基于MAC,IP地址控制客户端使用不同查询规则,可实现家长控制等功能。 返回最快 IP 地址 支持从域名所属 IP 地址列表中查找到访问速度最快的 IP 地址,并返回给客户端,提高...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【Air】

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值