【C语言】操作符详解

news2025/7/26 8:12:42

目录

1、操作符分类

2、算术操作符 

3、移位操作符 (二进制)

3.1 左移操作符

3.2 右移操作符

4、位操作符 

5、赋值操作符 

6、单目操作符 

6.1 单目操作符介绍

6.2 sizeof和数组 

7、关系操作符

8、逻辑操作符 

9、条件操作符 

10、逗号表达式 

11、下标引用、函数调用和结构成员 

11.1 [ ] 下标引用操作符

 11.2 ( ) 函数调用操作符

11.3 访问一个结构的成员 

12、表达式求值 

12.1 隐式类型转换

12.2 算术转换 


1、操作符分类

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

2、算术操作符 

   +      -      *      /      %

【注】

1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点      数除法。
3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。

3、移位操作符 (二进制)

<<    左移操作符

>>    右移操作符

注:移位操作符的操作数只能是整数。

【补】原码,反码,补码

 计算机存储的形式是补码,我们平时写的二进制都是原码

三者关系如下:

  1. 如果是正数的话,其原码,反码,补码相同(首位是0)
  2. 如果是负数的话,原码首位是1,原码取反得到反码(除符号位),反码加一得到补码。

 从补码到原码也有两种方法,其中取反加一可以来回计算,体现出计算机语言设计的巧妙性。

3.1 左移操作符

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

int main()
{
	int a = 10;
	//00000000000000000000000000001010
	int b = a << 1;
	//00000000000000000000000000010100->20
	printf("%d\n", b);
	return 0;
}

左移有乘2的效果

3.2 右移操作符

移位规则:

  1. 逻辑移位:左边用0填充,右边丢弃
  2. 算术移位:左边用原该值的符号位填充,右边丢弃(常见)
int main()
{
	int a = -1;
	//10000000000000000000000000000001--原码
	//11111111111111111111111111111110--反码
	//11111111111111111111111111111111--补码
	int b = a >> 1;
	//直接取反加一
	//10000000000000000000000000000001--原码--》-1
	printf("%d\n", b);
	return 0;
}

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

int num = 10;
num>>-1;//error

4、位操作符 

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

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

【练习】

int main()
{
	int num1 = 1;
	//00000000000000000000000000000001
	int num2 = 2;
	//00000000000000000000000000000010
	printf("%d\n", num1 & num2);
	//00000000000000000000000000000000
	printf("%d\n", num1 | num2);
	//00000000000000000000000000000011
	printf("%d\n", num1 ^ num2);
	//00000000000000000000000000000011
	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;
}

【总结】1.异或之间满足交换律,0和任何数异或等于该数。

              2.可读性差

              3.效率不如使用临时变量的方法

              4.异或只能对整数进行交换

【练习】编写代码实现:求一个整数存储在内存中的二进制中1的个数。

//方法1
#include <stdio.h>
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;
}
//思考这样的实现方式有没有问题?————负数问题————需要把int类型改为unsigned int


//方法2:
#include <stdio.h>
int main()
{
	int num = -1;
	int i = 0;
	int count = 0;//计数
	for (i = 0; i < 32; i++)
	{
		if ((num>>i)&1==1)
			count++;
	}
	printf("二进制中1的个数 = %d\n", count);
	return 0;
}
//思考还能不能更加优化,这里必须循环32次的。


//方法3:
#include <stdio.h>
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;
}
//这种方式是不是很好?达到了优化的效果,但是难以想到。

5、赋值操作符 

赋值操作符是一个很棒的操作符,他可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。
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;//连续赋值
//这样的代码感觉怎么样?
那同样的语义,你看看:
x = y+1;
a = x;
//这样的写法是不是更加清晰爽朗而且易于调试。

 复合赋值符:

+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
这些运算符都可以写成复合的效果。
比如:
int x = 10;
x = x+10;
x += 10;//复合赋值
//其他运算符一样的道理。这样写更加简洁。

6、单目操作符 

6.1 单目操作符介绍

!                逻辑反操作
-                负值
+               正值
&               取地址
sizeof       操作数的类型长度(以字节为单位)
~               对一个数的二进制按位取反
--               前置、后置 --
++             前置、后置 ++
*                间接访问操作符 ( 解引用操作符 )
( 类型 )       强制类型转换
#include <stdio.h>
int main()
{

		int a = -10;
		int* p = NULL;
		printf("%d\n", !2);
		printf("%d\n", !0);
		a = -a;
		p = &a;
		printf("%d\n", sizeof(a));
		printf("%d\n", sizeof(int));
		printf("%d\n", sizeof a);//这样写行不行?--行
		printf("%d\n", sizeof int);//这样写行不行?--不行
		return 0;
}
关于 sizeof 其实我们之前已经见过了,可以求变量(类型)所占空间的大小。

6.2 sizeof和数组 

#include <stdio.h>

void test1(int arr[])
{
	printf("%d\n", sizeof(arr));//(2)  4或者8  本质上是指针
}
void test2(char ch[])
{
	printf("%d\n", sizeof(ch));//(4)   4或者8  本质上是指针
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d\n", sizeof(arr));//(1)  40  数组大小
	printf("%d\n", sizeof(ch));//(3)   10  数组大小
	test1(arr);
	test2(ch);
	return 0;
}
问:
1 )、( 2 )两个地方分别输出多少?
3 )、( 4 )两个地方分别输出多少?

//前置++和--
#include <stdio.h>
int main()
{
    int a = 10;
    int x = ++a;
    //先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
    int y = --a;
    //先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
    return 0;
}
//后置++和--
#include <stdio.h>
int main()
{
    int a = 10;
    int x = a++;
    //先对a先使用,再增加,这样x的值是10;之后a变成11;
    int y = a--;
    //先对a先使用,再自减,这样y的值是11;之后a变成10;
    return 0;
}

7、关系操作符

>
>=
<
<=
!=        用于测试 不相等
==       用于测试 相等

这些关系运算符比较简单,没什么可讲的,但是我们要注意一些运算符使用时候的陷阱。

【注】在编程的过程中== =不小心写错,导致的错误。 

8、逻辑操作符 

逻辑操作符有哪些:
&&          逻辑与
||             逻辑或
区分 逻辑与 按位与
区分 逻辑或 按位或
1 & 2      ----> 0
1 && ----> 1
1 | 2      ----> 3
1 || 2      ----> 1
#include <stdio.h>
int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	//i = a++||++b||d++;
	printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
	return 0;
}
//程序输出的结果是什么?
//a = 1
//b = 2
//c = 3
//d = 4

 上述代码被称为逻辑短路或者叫短路求值

9、条件操作符 

exp1 ? exp2 : exp3
if (a > 5)
       b = 3;
else
       b = -3;
转换成条件表达式,是什么样?
b = a>5?3:-3;
2. 使用条件表达式实现找两个数中较大值。

int get_max(int a,int b)
{
    return a>b?a:b;
}

10、逗号表达式 

exp1 , exp2 , exp3 , …expN
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
//c是多少?---13

//代码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)
{
         //业务处理
}

11、下标引用、函数调用和结构成员 

11.1 [ ] 下标引用操作符

操作数:一个数组名 + 一个索引值
int arr [ 10 ]; // 创建数组
arr [ 9 ] = 10 ; // 实用下标引用操作符。
[ ] 的两个操作数是 arr 9 。//这也说明java里面数组定义比C语言里面的更严谨 

 11.2 ( ) 函数调用操作符

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

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

【注】我们之前用的时间函数time( ),后面的括号就是调用操作符,不能丢!

11.3 访问一个结构的成员 

      结构体 . 成员名
->      结构体指针 -> 成员名
#include <stdio.h>
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;
}

12、表达式求值 

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

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

12.1 隐式类型转换

C 的整型算术运算总是至少以缺省(就是默认)整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型 提升

整型提升的意义

表达式的整型运算要在 CPU 的相应运算器件内执行, CPU 内整型运算器 (ALU) 的操作数的字节长度一般就是int 的字节长度,同时也是 CPU 的通用寄存器的长度。
因此,即使两个 char 类型的相加,在 CPU 执行时实际上也要先转换为 CPU 内整型操作数的标准长度。
通用 CPU general-purpose CPU )是难以直接实现两个 8 比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int 长度的整型值,都必须先转换为int unsigned int ,然后才能送入 CPU 去执行运算。
//实例1
char a,b,c;
...
a = b + c;

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

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

如何进行整体提升呢?

整形提升是按照变量的数据类型的符号位来提升的  

// 负数的整形提升
char c1 = - 1 ;
变量 c1 的二进制位 ( 补码 ) 中只有 8 个比特位:
11111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为 1
提升之后的结果是:
11111111111111111111111111111111
// 正数的整形提升
char c2 = 1 ;
变量 c2 的二进制位 ( 补码 ) 中只有 8 个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为 0
提升之后的结果是:
00000000000000000000000000000001
// 无符号整形提升,高位补 0
//【补充】有符号型的char的范围为-128~127,无符号型的char的范围为0~255

 整形提升的例子:

//实例1
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;
}
实例 1 中的 a,b 要进行整形提升 , 但是 c 不需要整形提升。a,b整形提升之后 , 变成了负数 , 所以表达式 a==0xb6 , b==0xb600 的结果是假 , 但是 c 不发生整形提升 , 则表达式 c==0xb6000000 的结果是真.因此只能打印出c。
//实例2
int main()
{
	char c = 1;
	printf("%u\n", sizeof(c));
	printf("%u\n", sizeof(+c));
	printf("%u\n", sizeof(-c));
	return 0;
}
实例 2 中的 ,c 只要参与表达式运算 , 就会发生整形提升 , 表达式 +c , 就会发生提升 , 所以 sizeof(+c) 4 个字节. 表达式 - c 也会发生整形提升 , 所以 sizeof( - c) 4 个字节 , 但是 sizeof(c) , 就是 1 个字节 .

12.2 算术转换 

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
【注】但是算术转换要合理,要不然会有一些潜在的问题
float f = 3.14 ;
int num = f ;      // 隐式转换,会有精度丢失

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

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

相关文章

微信对账单功能开发(V2)

下载交易账单接口开发 应用场景&#xff1a; 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致&#xff0c;通过对账单核对后可校正支付状态。 注意&#xff1a; 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易…

Azure Integrator Delphi版

Azure Integrator Delphi版 Azure Integrator包括表、队列和Blob等标准Windows Azure结构的实现&#xff0c;使开发人员能够快速轻松地将基于云的数据存储、队列管理、表配置等添加到任何桌面、Web或移动应用程序中。 Azure Integrator功能 用于访问Windows Azure表、Blob和队列…

python folium 实现地图平台制作

python实现泸定地震点观测平台制作 数据来自[走天涯徐小洋地理数据科学]&#xff0c;原始数据来自微博中国地震台网 的正式测定数据。 以下是地震点的数据&#xff1a; MagnitudeDateTimeLongitudeLatitudeDepth6.82022-9-512:52102.0829.59163.12022-9-65:28102.0729.64113…

[附源码]java毕业设计览宏公司会议管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

01. 信息搜集:Web 1~10

Web 1~10web1知识点题解web2知识点题解web3知识点题解web4知识点题解web5知识点题解web6知识点题解web7知识点题解web8知识点题解web9知识点题解web10知识点题解web1 知识点 查看网页源码&#xff1a;ctrl u 或 F12 开发注释未及时删除 题解 查看网页源码即可。 web2 知识…

学习UI设计,哪些软件是必学的

UI设计软件的学习并不重要。许多设计软件功能相似&#xff0c;操作相似&#xff0c;设计效果相似&#xff0c;此时我们只需要选择相同类型的软件进行深入学习&#xff0c;当我们掌握软件时&#xff0c;使用其他类型的软件基本上不会有太大的困难。 ​一、位图软件&#xff1a; …

spring-data-mongodb生成的Query语句order字段顺序错误

前言&#xff1a; 最近在实现一个需求的时候&#xff0c;需求要求查询的数据需要根据播放量倒叙、创建时间倒叙来排序&#xff0c;考虑到播放量、创建时间都有可能是相同的&#xff0c;就会出现排序不稳定的情况&#xff0c;于是就加入了"_id"作为第三个排序字段&am…

Unity程序在VR一体机(Android)上卡死(闪退)后怎么办?——用adb查看android上某Unity app的debug信息

一、之前面临的困境 Unity的程序build到android一体机后&#xff0c;仿佛进入了一个黑箱子&#xff0c;你既看不到脚本的debug报错信息&#xff0c;也看不到任务管理器里的内存和CPU使用情况&#xff1f;如果黑屏、闪屏、花屏怎么办&#xff1f; 最近面临的一个问题就是&…

【快速上手系列】使用七牛云+webuploader实现对象云存储(OSS)

【快速上手系列】使用七牛云webuploader实现对象云存储&#xff08;OSS&#xff09; 步骤 一、七牛云配置 1、新建存储空间 进入七牛云&#xff0c;注册登录&#xff0c;进入控制台&#xff0c;选择对象存储 Kodo 选择空间管理——新建空间&#xff08;免费30天&#xff0…

[附源码]java毕业设计企业人力资源管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【Bio】基础生物学 - 基因 gene

文章目录1. DNA 脱氧核糖核酸、RNA 核糖核酸1.1 核苷酸1.2 脱氧核糖核酸1.3 核糖核酸2. 基因2.1 基因组2.2 染色体2.3 基因与脱氧核苷酸的牵连2.4 基因与DNA的牵连2.5 基因与染色体的牵连Ref1. DNA 脱氧核糖核酸、RNA 核糖核酸 1.1 核苷酸 核苷酸 (Nucleotide)\blue{\text{核苷…

如何使用家庭网络运行Aleo Prover

目前ALEO三测第二阶段太卷了&#xff0c;虽然现阶段没有激-励&#xff0c;但是仍然有不少人卷进去&#xff0c;导致现在8核的云服务器一天才只能跑出三四个scores&#xff0c;可见大家的热情还是非常高的&#xff0c;但是这对于之前购买云服务器的用户来说&#xff0c;就比较难…

全网营销如何落地?全网营销的途径有哪些?

随着移动互联网的遍及&#xff0c;如今企业的经营发展越来越离不开全网营销。有些小伙伴可能对全网营销的具体操作方法有些不解&#xff0c;这里小马识途营销顾问系统解读下全网营销。 一、 什么是全网营销&#xff1f; 全网营销是全网整合营销的简称&#xff0c;即从产品规划、…

同花顺_代码解析_技术指标_D

本文通过对同花顺中现成代码进行解析&#xff0c;用以了解同花顺相关策略设计的思想 目录 DBCD DDI DMAFS DMI DMI_QL DPO DBCD 异同离差乖离率 公式描述&#xff1a; 先计算乖离率BIAS&#xff0c;然后计算不同日的乖离率之间的离差&#xff0c; 最后对离差进行指数移…

ArcGIS pro求点线最短距离Near

ArcGIS pro求点线最短距离Near 如果是ArcGIS经典版&#xff0c;可以从以下路径找到&#xff1a; ArcGIS pro就更简单了&#xff0c;在Analysis面板&#xff1a; 打开之后来介绍一下各参数意义&#xff1a; 按照ArcGIS帮助&#xff0c;该工具可求点、线、面之间的最短距离。 其…

React-Mobx(入门)

目录 1. Mobx介绍 优势 社区评价 ​编辑 2.配置开发环境 3.基础使用 1&#xff09;初始化mobx 2&#xff09;React使用store 4.计算属性&#xff08;衍生状态&#xff09; 5.异步数据处理 6. 模块化 1&#xff09;定义task模块 2&#xff09;定义counterStore 3&am…

配置错误的smb共享

介绍 Windows 是当今最流行的操作系统&#xff0c;不仅由个人用户使用&#xff0c;而且在大公司中也广泛使用。由于其操作简单性以及使用图形界面&#xff0c;如今&#xff0c;大量实体的公司网络充满了运行Windows操作系统的主机和服务器。无论这些机器针对的是最终用户、我们…

XSS-labs靶场实战(一)——第1-3关

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是XSS-labs靶场实战。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未授权设备…

Linux安全--iptables详解

目录 1、iptables介绍 2、iptables四表五链详解 3、iptables基本语法 4、实际操作 4.1 增加规则 4.2 删除规则 4.3 修改规则 5、命令语法总结 6、基本匹配条件 7、iptables进阶用法 7.1 iprange扩展模块 7.2 string扩展模块 8、iptables进行端口转发 1、iptables介绍 …

【Python】面向Sqli-Labs Less15的布尔盲注二分法脚本

前言 其实写这个python脚本是为了完成我某节课的某个实验 代码里有一堆一堆的for循环&#xff0c;导致程序整个运行下来起码需要一个小时&#xff0c;而且还是基于二分法的qwq。本来想说去学一学python的多线程提升一下效率&#xff0c;但我发现我这代码一环扣一环&#xff0c…