C语言操作符与表达式详解

news2024/11/17 15:33:27

目录

操作符的分类:

(1)算数操作符

(2)移位操作符

(3)位操作符

(4)赋值操作符

(5)单目操作符

(6)关系操作符

(7)逻辑操作符

(8)条件操作符

(9)逗号表达式

(10)下标引用、函数调用和结构成员

表达式求值:

隐式类型转换

 整型提升

 算术转换

操作符的属性

运算符优先级和结合性表格:

一些问题表达式


操作符的分类:


(1)算数操作符

+(加)   -(减)   *(乘 )  /(除)   %(取余)

1.除了%操作符之外,其他的几个操作符可以作用于整数和浮点数

2.对于/操作符如果两个操作数都为整数,执行整数除法,而只要其中有一个浮点数执行的就是浮点数除法

int main() {
	/*int a = 6, b = 5;
	printf("%d", a / b);*/      //打印结果为1

	double a = 6.0;
	int b = 5;
	printf("%lf", a / b);      //打印结果为1.200000
	return 0;
}

3.%操作符的两个操作数必须为整数,返回的是整除之后的余数


(2)移位操作符

正数在内存中用原码(因与补码相同)表示,负数用补码

<<  左移操作符

移位规则:左边抛弃,右边补0

	int a = 2;
	//把a的二进制位向左移动一位(0010->0100)
	int b = a << 1;        //并不改变a的值
	printf("%d",b);        //打印结果为4

>>右移操作符

移位规则:

1.逻辑移位:左边用0补充,右边丢弃

2.算数移位:左边用原来的符号位填充,右边丢弃

int a = 10;
	//把a的二进制位向右移动一位(1010->0101)
	int b = a >> 1;         //并不改变a的值
	printf("%d", b);        //打印结果为4


(3)位操作符

&     //按位与

	int a = 3;
	int b = 5;
	//& - 按(2进制)位与
	int c = a & b;
	//0011 -a
	//0101 -b
	//0001 -c(对应位上同为1才为1,否则为0)
	printf("%d", c);        //打印结果为1

|      //按位或

    int a = 3;
	int b = 5;
	//| -按(2进制)位或
	int c = a | b;
	//0011 -a
    //0101 -b
    //0111 -c(对应位上同为0才为0,否则为1)
	printf("%d", c);        //打印结果为7

^     //按位异或

	int a = 3;
	int b = 5;
	// ^ -按(2进制)位异或
	int c = a ^ b;
	//0011 -a
	//0101 -b
	//0110 -c(对应位相同为0,相异为1)
	printf("%d", c);        //打印结果为6

注:他们的操作数必须是整数

异或操作的用途之一:不创建中间变量即可交换两个整型元素的值(同时保证交换过程中不发生范围溢出),例:

	//不创建中间变量交换a和b的值
	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);


(4)赋值操作符

  =   +=    -=   *=    /=   >>=   <<=   %=

连续的等号赋值是从左至右依次赋值:

	int a = 20;
	int x = 0;
	int y = 20;
	a = x = y + 1;
	printf("%d %d",a,x);//打印结果为21  21

复合赋值符的含义:

	int a = 10;
	a = 100;
	a += 100;//与a = a + 100等价
	//其他复合赋值符同理

注:C语言中一个=是赋值,两个=是判断


(5)单目操作符

!     逻辑反操作

	int flag = 5;//为真
	printf("%d\n", !flag);//打印结果为0(为假)
	flag = 0;//为假
	printf("%d\n", !flag);//打印结果为1(为真)

-     负值

将某数变为其相反数

int a=10;
a=-a;
printf("%d",a);//打印结果为-10

+     正值

 对操作数不做何改变

int a=10;
a=+a;
printf("%d",a);//打印结果为10

sizeof     操作数的类型长度(以字节为单位)

注: sizeof是一个操作符,不是函数

	int a = 10;
	int arr[10] = { 0 };
	printf("%d\n", sizeof(arr));//计算arr所占空间大小,单位是字节,打印结果为40,因为int类型大小是4个字节,数组有10个元素
	printf("%d\n", sizeof(int));//打印结果是4,可以直接对类型用sizeof

 注sizeof括号内的表达式不参与运算

	short s = 5;
	int a = 10;
	printf("%d\n", sizeof(s = a + 2));//打印结果为2(short类型大小为2个字节)
	printf("%d\n", s);//打印结果为5,sizeof括号内的表达式不参与运算

~     对一个数的二进制按位取反(包括符号位)

	int a = -1;
	//10000000000000000000000000000001 -原码
	//11111111111111111111111111111110 -反码
	//11111111111111111111111111111111 -补码
	// ~ 按位取反
	//00000000000000000000000000000000(补码按位取反)
	int b= ~a;
	printf("%d",b);//打印结果为0

 ++     前置、后置++

后置++:

	int a = 10;
	int b = a++;//后置++,先使用,再++

	printf("%d\n", a);//打印结果为11
	printf("%d\n", b);//打印结果为10

 前置++:

	int a = 10;
	int b = ++a;//前置++,先++,后使用
	printf("%d\n", a);//打印结果为11
	printf("%d\n", b);//打印结果为11

- -     前置、后置- -

 原理同++

int a = 10;
printf("%d\n", a--); //打印结果为10
printf("%d\n", a);//打印结果为9

*     间接访问操作符(解引用操作符)、 &     取地址操作符

int a = 10;
      printf("%p\n", &a);//& - 取地址操作符
      int *pa = &a;//pa是用来存放地址的 - pa就是一个指针变量
      *pa = 20;// * 解引用操作符 - 间接访问操作符
      printf("%d",a);//打印结果为20,*pa就代表着a

(类型)     强制类型转换

      int a = (int)3.14;//将3.14double类型变量强制转换为int类型
	  printf("%d", a);//打印结果为3


(6)关系操作符

>

>=

<

<=

!=            用于测试“不相等”

==           用于测试“相等”

常用于判断语句中,较为简单


(7)逻辑操作符

&&                逻辑与

||                   逻辑或

    int a = 3;
	int b = 0;
	if (a && b) {//a和b同时为真时,才进入下面的语句
		printf("hello");//不执行此语句
	}
	if (a || b) {//a和b有一个为真,就进入下面的语句
		printf("world");//执行此语句
	}

:区分逻辑与按位与     区分逻辑或按位或

1&2---------->0             (0001和0010----->0000)

1&&2-------->1

1|2----------->3             (0001和0010----->0011)

1||2---------->1

 注:(表达式)1&&(表达式2)时,若(表达式1)=0,则(表达式2)不再计算

    int i = 0 , a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	printf("%d\n%d\n%d\n%d\n", a, b, c, d);//打印结果为 1 2 3 4

 注:(表达式)1||(表达式2)时,若(表达式1)=1,则(表达式2)不再计算

	int i = 0, a = 1, b = 2, c = 3, d = 4;
	i = a++ || ++b || d++;
	printf("%d\n%d\n%d\n%d\n", a, b, c, d);//打印结果为 2 2 3 4


(8)条件操作符

  又称作三目操作符

exp1 ?exp2 : exp3

exp1结果为真返回exp2,否则返回exp3

	int a = 3;
	int b = 0;
	//三目操作符
	b = (a > 5 ? 1 : -1);//表达式1 ?表达式2 :表达式3
	printf("%d", b);//打印结果为-1


(9)逗号表达式

exp1, exp2, exp3, ...expN

 逗号表达式 - 要向右依次计算,但是整个表达式的结果是最后一个表达式的结果

    int a = 3;
	int b = 5;
	int c = 0;
	//逗号表达式要向右依次计算,但是整个表达式的结果是最后一个表达式的结果
	int d = (c = 5, a = c + 3, b = a - 4, c += b);
	printf("%d",d);//结果为9


(10)下标引用、函数调用和结构成员

[ ]  :  下标引用操作符

操作数:一个数组名+一个索引值

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

( ):  函数调用操作符:接受一个或多个操作数

第一个 操作数是函数名,剩余的操作数就是传递给函数的参数

	int Add(int x, int y) {//函数的定义
		return x + y;
	}
	int a = 10;
	int b = 20;
	int ret = Add(a, b);//调用函数  () - 函数调用操作符

   访问一个结构的成员:

.            结构体.成员名

->         结构体指针->成员名

	//结构体
	//书:书名,书号,定价
	//创建了一个自定义的类型
	struct Book
	{
		//结构体的成员变量
		char name[20];
		char id[20];
		int price;
	};


	int num = 10;
	struct Book b = { "C语言","20191112537",55 };
	//结构体变量.成员名
	printf("%s\n", b.name);
	printf("%s\n", b.id);
	printf("%d", b.price);
	//结构体指针->成员名
	struct Book* pb = &b;
	printf("%s\n", pb->name);
    printf("%s\n", pb->id);
    printf("%d", pb->price);
    //输出结果与上方代码输出结果相同


表达式求值:

表达式求值的顺序一部分是由操作符的优先级和决定性决定。

同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。


隐式类型转换

C的整型算数运算总是至少以缺省整型类型的精度来进行的。

为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为

整型提升

(只有长度小于int长度(short、char)才进行整型提升)

	char a, b, c;
	//...
    a = b + c;

b和c的值被提升为普通整型,然后再执行加法运算。

加法运算完成之后,结果被截断,然后再存储于a中。

整型提升的意义:

具体例子:

    char a = 3;
	//00000011 - a(char只能存8个bite位)
	char b = 127;
	//01111111 - b
	char c = a + b;
	//a和b都是char类型,都没有达到一个int的大小
	//这里会发生整型提升,高位补的都是符号位(无符号统一补0)

	//a整型提升后:00000000000000000000000000000011
	//b整型提升后:00000000000000000000000001111111
	//          c=00000000000000000000000010000010 
	//c发生截断,只存8个bite位,c = 10000010
	//此时c是char类型的变量,需要打印整型变量,再次发生整型提升
	//c - 11111111111111111111111110000010     (高位补符号位1)
	//但负数在内存中形式是补码,所以还要再求c的原码
	//c的原码 - 10000000000000000000000001111110 = -126
	printf("%d\n", c);//打印结果为-126
    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
	//%u是输出无符号整型数
	//+c  -c  !c  参与了运算,发生了整型提升,所以变为int的大小


 算术转换

  如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换位另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

long  double

double

float

unsigned  long  int

long  int 

unsigned  int

int

上方从大至小排列

   如果某个操作数的类型在上面的这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算

	int a = 4;
	float f = 4.5f;
	a + f;//需要将a的类型转换为float类型去计算

注:算数转换要合理,不然存在一些潜在的问题

	float f = 3.14;
	int num = f;//会丢失精度


操作符的属性

复杂表达式的求值有三个影响的因素

1.操作符的优先级

2.操作符的结合性

3.是否控制求值顺序(如(表达式1)&&(表达式2):(表达式1)是0后(表达式2)不再计算))

两个相邻的操作符优先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。

	int a = 4;
	int b = 5;
	int c = a + b * 7;//优先级决定了计算顺序
	int c = a + b + 7;//优先级不起作用,结合性决定

运算符优先级和结合性表格:

(引用自博主星空之路Star的博客C语言34种运算符优先级及结合性)

一些问题表达式

注:有些表达式的运算顺序可能还是不唯一的

//表达式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
    int c=3; 
	c + --c;
    //优先级只能保证--运算在+之前,无法得知+操作符的左操作数的获取在右操作数之前还是之后求值,所以结果不可预测,有歧义
    //2+2=4 或 3+2=5
	//表达式3
	int i = 1;
	int ret = (++i) + (++i) + (++i);
	printf("%d\n", ret);// VS里打印出12       gcc打印出10

    //因为VS中先算了三次++i,再将三个结果相加
    //而gcc中先算了两次++i,再相加,再执行++i,再相加(与上方表达式1原理类似)

  以上为C语言中操作符和表达式相关内容的详细讲解,感谢您花费宝贵的时间阅读本文章!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1376351.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度解析 Compose 的 Modifier 原理 -- ParentDataModifier

" Jetpack Compose - - Modifier 系列文章 " &#x1f4d1; 《 深入解析 Compose 的 Modifier 原理 - - Modifier、CombinedModifier 》 &#x1f4d1; 《 深度解析 Compose 的 Modifier 原理 - - Modifier.composed()、ComposedModifier 》 &#x1f4d1; 《 深入解…

解决PS“暂存盘已满”错误

问题&#xff1a;PS“暂存盘已满”错误 原因&#xff1a; PS在运行时会将文件的相关数据参数保存到暂存区。当提醒暂存盘满时&#xff0c;说明你当前PS运行的使用盘符空间不足&#xff0c;所以在运行时一定要保留有足够的盘符空间来运行PS。 效果图 解决方案 注意: 我们在使用P…

威士忌品鉴:如何体验这美妙的细节与品质

在浩瀚的品鉴中&#xff0c;威士忌以其特别的魅力吸引了无数品鉴者的目光。作为一种源于苏格兰的蒸馏酒&#xff0c;威士忌的味蕾丰富、香气特别&#xff0c;让人沉醉其中。本文将结合雷盛537威士忌&#xff0c;带你深入探索威士忌的品鉴之道&#xff0c;领略这一美妙的细节与品…

构建基于RHEL8系列(CentOS8,AlmaLinux8,RockyLinux8等)的MySQL8.0.32的RPM包

本文适用&#xff1a;rhel8系列&#xff0c;或同类系统(CentOS8,AlmaLinux8,RockyLinux8等) 文档形成时期&#xff1a;2023年 因系统版本不同&#xff0c;构建部署应略有差异&#xff0c;但本文未做细分&#xff0c;对稍有经验者应不存在明显障碍。 因软件世界之复杂和个人能力…

虹科分享 | 用Redis为LangChain定制AI代理——OpenGPTs

文章速览&#xff1a; OpenGPTs简介Redis在OpenGPTs中的作用在本地使用OpenGPTs在云端使用OpenGPTsRedis与LangChain赋能创新 OpenAI最近推出了OpenAI GPTs——一个构建定制化AI代理的无代码“应用商店”&#xff0c;随后LangChain开发了类似的开源工具OpenGPTs。OpenGPTs是一…

配电柜监测:别再人工巡检!一文讲透!

随着现代社会对电力的依赖性不断增强&#xff0c;各行各业对电力系统的可靠性和安全性提出了更高的要求。 配电柜作为电力系统的核心组成部分&#xff0c;其监控与管理显得尤为重要。为了满足企业对电力系统监测的需求&#xff0c;配电柜监控系统应运而生。 客户案例 制造企业…

cad的模型怎么打散导入3d---模大狮模型网

将CAD中的模型打散并导入3D建模软件&#xff0c;需要以下步骤&#xff1a; 将CAD中的模型进行分组或分层&#xff1a;在CAD中&#xff0c;将模型按照不同的组或层进行分组或分层。这样可以方便地控制每个部分的显示和隐藏&#xff0c;在导入3D建模软件后&#xff0c;也可以更方…

iOS rootless无根越狱解决方案

据游戏工委数据统计&#xff0c;2023年国内游戏市场实际销售收入与用户规模双双创下新高&#xff0c;游戏普遍采用多端并发方式&#xff0c;成为收入增长的主因之一。 中国市场实际销售收入及增长率丨数据来源&#xff1a;游戏工委 多端互通既是机遇&#xff0c;也是挑战。从游…

MySQL中datetime和timestamp的区别

datetime和timestamp的区别 相同点: 存储格式相同 datetime和timestamp两者的时间格式都是YYYY-MM-DD HH:MM:SS 不同点: 存储范围不同. datetime的范围是1000-01-01到9999-12-31. 而timestamp是从1970-01-01到2038-01-19, 即后者的时间范围很小. 与时区关系. datetime是存储…

tiktok_浅谈hook ios之发包x-ss-stub

frida-trace ios手机一部&#xff0c;需要越狱的电脑一台idacrackerXI 目标app&#xff1a; ipa 包&#xff0c;点击前往 密码&#xff1a;8urs 协议分析起始从抓包开始&#xff0c;个人习惯 一般安卓逆向可以直接搜关键词&#xff0c;但是ios 都在 Mach-O binary (reverse…

vue3+ts+vite项目从0 搭建,配置安装router/pinia/element-plus/scss等

一、安装vite环境 官网&#xff1a;https://cn.vitejs.dev/guide/why.html npm init vite1.选择vue 2.选择typescipt 3.创建成功 默认项目结构如下 4.安装项目依赖 npm install 5.启动项目 npm run dev二。安装配置scss 1.运行安装scss npm install -D sass sass-loa…

搜维尔科技:【简报】元宇宙数字人赛道,《全息影像技术应用》!

期待着看展的主角来到今天要参观的全息影像展&#xff0c;平时就喜欢看展的她对于所谓的全息影像非常好奇&#xff0c;于是她带着期待的心情进入展内。进入展内的主角看到的是与之前完全不同的画展&#xff0c;每幅画看起来就像真的一样&#xff0c;充满好奇的她在展览的各处游…

如何在Docker本地搭建流程图绘制神器draw.io并实现公网远程访问

推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 前言 提到流程图&#xff0c;大家第一时间可能会想到Visio&#xff0c;不可否认&#xff0c;VIsio确实是功能强大&#xff0c;但是软…

PyPDF2 3.0.0更新,一些函数被弃用,需要重新写

1.PdfFileWriter is deprecated and was removed in PyPDF2 3.0.0. Use PdfWriter instead. 这错误表明你正在使用的 PyPDF2 版本中已经移除了 PdfFileWriter&#xff0c;并在版本 3.0.0 中被替代为 PdfWriter。这是因为在 PyPDF2 的更新中&#xff0c;一些 API 被重新组织和更…

目标检测脚本之mmpose json转yolo txt格式

目标检测脚本之mmpose json转yolo txt格式 一、需求分析 在使用yolopose及yolov8-pose 网络进行人体姿态检测任务时&#xff0c;有时需要标注一些特定场景的中的人型目标数据&#xff0c;用来扩充训练集&#xff0c;提升自己训练模型的效果。因为单纯的人工标注耗时费力&…

笔记软件内怎么查看文章字数 笔记查看字数的操作步骤

在记录生活点滴、工作要务时&#xff0c;你是否曾像我一样&#xff0c;为了知道写了多少字而犯愁&#xff1f;尤其是在需要精确控制字数时&#xff0c;那种焦虑感更是如影随形。 记得有一次&#xff0c;我为了一个项目报告苦思冥想&#xff0c;好不容易写了个初稿&#xff0c;…

0111qt

实现闹钟&#xff0c;并播报懒虫...~ daytest.pro: QT core gui texttospeechgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (th…

堆叠线:实现高效连接和数据传输的利器

堆叠线是一种常见的网络连接解决方案&#xff0c;主要应用于数据中心和企业网络等领域。本文将介绍堆叠线的定义、分类、作用以及与光纤线的区别&#xff0c;同时提供详细的堆叠线接法和相关问题的解答。 第一部分&#xff1a;堆叠线是什么 堆叠线是一种用于连接网络设备的高…

mysql日志那些事

一、Mysql常见日志 MySQL有不同类型的日志文件&#xff0c;用来存储不同类型的日志&#xff0c;分为二进制日志、错误日志、通用查询日志、慢查询日志和中继日志&#xff0c;使用这些日志可以查看MySQL内部发生的事情。 二、慢查询日志&#xff08;slow query log&#xff0…

windows安装RabbitMq,修改数据保存位置

1、先安装Erlang&#xff0c; Erlang和RabbitMQ有版本对应关系。 官网RabbitMQ与Erlang版本对应RabbitMQ Erlang Version Requirements — RabbitMQ 2、安装RabbitMQ。 3、修改数据保存地址。找到安装目录下的sbin文件夹&#xff0c;找到rabbitmq-env.bat&#xff0c;编辑文件…