首页 > 其他分享 >操作符详解

操作符详解

时间:2024-01-21 23:32:44浏览次数:24  
标签:return int ++ 详解 操作符 printf main

一、操作符

算术操作符:+ - * / %

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

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

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

#include <stdio.h>
int main()
{
	int a = 5 / 2;//商2余1
	int b = 5 % 2;//余1
	double c = 5.0 / 2;//商2.500000
	//double d = 5.0 % 2;//报错
	printf("a = %d\n", a);
	printf("b = %d\n", b);
	printf("c = %lf\n", c);
	return 0;
}


移位操作符:>> <<

对于移位操作符,不要移动负数位,这个是标准未定义的,例如a>>-1.

对于位操作符,只能作用于整数,浮点数和整数的存储类型是不一样的。

右移操作符>>

1,算术右移:右边丢弃,左边补原符号位(一般情况下编译器采用的都是算数右移);

2,逻辑右移:右边丢弃,左边补零。

int main()
{
	//>> - 右移操作符
	//移动的是二进制位
	int a = 16;
	int b =a >> 1;
	//a - 00000000000000000000000000010000
	//b - 00000000000000000000000000001000
	printf("%d\n", b);//8
	return 0;
}
int main()
{
	int a = -1;
	//整数的二进制表示有:原码,反码,补码
  //实际上只对于负数有意义,正数的原、反、补码是相同的
	//整数存储在内存中的是补码
	//a的原码 - 10000000000000000000000000000001
	//a的反码 - 11111111111111111111111111111110
	//a的补码 - 11111111111111111111111111111111
	int b = a >> 1;
	printf("%d\n", b);//-1
	return 0;
}

十六进制中f=15,二进制中15=1111,所以f=1111,下图中ffffffff就是32个1,表示内存中a的补码。

操作符详解_结构体

左移操作符<<

左边丢弃,右边补0。

int main()
{
	int a = 5;//00000000000000000000000000000101
	int b = a << 1;//00000000000000000000000000001010
	printf("%d\n", b);//10
}


位操作符:& | ^

按位与&

int main()
{
	//& - 按二进制位与
	int a = 3;//00000000000000000000000000000011
	int b = 5;//00000000000000000000000000000101
	int c = a & b;//00000000000000000000000000000001
	printf("%d", c);//1
	return 0;
}

按位或|

int main()
{
  & - 按二进制位或
	int a = 3;//00000000000000000000000000000011
	int b = 5;//00000000000000000000000000000101
	int c = a | b;//00000000000000000000000000000111
	printf("%d", c);//7
	return 0;
}

按位异或^

int main()
{
	//& - 按二进制位异或,相同为0,相异为1
	int a = 3;//00000000000000000000000000000011
	int b = 5;//00000000000000000000000000000101
	int c = a ^ b;//00000000000000000000000000000110
	printf("%d", c);//6
	return 0;
}

e.g.1: 变量a=3, b=5, 交换两个变量的值,不使用第三变量。

int main()
{
	int a = 3;
	int b = 5;
	a = a + b;
	b = a - b;//3
	a = a - b;//5
	printf("a=%d\nb=%d", a, b);
	return 0;
}

解1:加减法,理解简单,但存在内存溢出的风险(a+b值过大导致部分二进制位丢失)。

int main()
{
	int a = 3;
	int b = 5;
	a = a ^ b;
	b = a ^ b;//3
	a = a ^ b;//5
	printf("a=%d\nb=%d", a, b);
	return 0;
}

解2:异或法,即两数异或产生密码,该密码与两数之一异或得到另一数,不会存在溢出的风险。

e.g.2: 求一个整数存储在内存中的二进制中的1的个数。

int main()
{
	int num = 0;
	int count = 0;
	scanf("%d", &num);
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if ((num >> i) & 1 == 1)
			count++;
	}
	printf("%d", count);
	return 0;
}


赋值操作符:=

复合赋值符

+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=


单目操作符:只有一个操作符

逻辑反操作!

int main()
{
	int a = 0;
	if (!a)//如果a为假,则!a为真,执行if语句
	{
		printf("呵呵\n");
	}
	return 0;
}

负值-

int main()
{
	int a = -5;
	a = -a;//5
	printf("%d", a);
	return 0;
}

取地址操作符&

间接访问操作符(解引用操作符)*

int main()
{
	int a = 10;
	int* p = &a;//取地址操作符
	*p = 20;//解引用操作符
	return 0;
}

sizeof 计算变量所占内存空间的大小,单位是字节

如果sizeof后是变量,括号可以省略,是变量类型则不可以

int main()
{
	int a = 10;
	char c = 'r';
	char* p = &c;
	int arr[10] = { 0 };
	printf("%d\n", sizeof(a));//4
	printf("%d\n", sizeof(int));//4
	printf("%d\n", sizeof(c));//1
	printf("%d\n", sizeof(char));//1
	printf("%d\n", sizeof(p));//8
	printf("%d\n", sizeof(char*));//8
	printf("%d\n", sizeof(arr));//40
	printf("%d\n", sizeof(int [10]));//40
	return 0;
}

sizeof括号中并不会进行真实的赋值及运算,所以s依然为0。

int main()
{
	short s = 0;
	int a = 10;
	printf("%d\n",sizeof(s = a + 5));//2
	printf("%d\n", s);//0
	return 0;
}

按位取反~

int main()
{
	int a = 0;
	//~按二进制位取反
	//00000000000000000000000000000000
	//11111111111111111111111111111111-此时存在内存中的是一个负数的补码
	//11111111111111111111111111111110-补码-1得到反码
	//10000000000000000000000000000001-反码取反得到原码
	printf("%d\n", ~a);//-1
	return 0;
}
int main()
{
	int a = 11;//00000000000000000000000000000000000001011
	a = a | (1 << 2);//1011|0100
	printf("%d\n", a);//1111=15
	a = a & (~(1 << 2));//0...1111|1...1011
	printf("%d\n", a);//0...1011=11
	return 0;
}

前置、后置++, --

int main()
{
	int a = 10;
	printf("%d\n", ++a);//前置++,先自增1,后使用
	printf("%d\n", a++);//后置++,先使用,后自增1
	printf("%d\n", a);//12
	return 0;
}

(类型)强制类型转换

int main()
{
	int a = (int)3.14;
	return 0;
}


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


逻辑操作符:&& ||

int main()
{
	int a = 3;
	int b = 5;
	int c = 0;
	int d = a && b;//逻辑与&&,同时为真即为真
	int e = a && c;//只要有假便是假
	printf("%d\n", d);//1
	printf("%d\n", e);//0
	return 0;
}
int main()
{
	int a = 3;
	int b = 0;
	int c = 0;
	int d = a || b;//逻辑或||,只要有真便是真
	int e = b || c;//同时为假才为假
	printf("%d\n", d);//1
	printf("%d\n", e);//0
	return 0;
}

p.s.使用逻辑与操作符时,只要左边算出0,则结果必定为0,后续便不再计算(下题中b和d的自增没有执行计算)。

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
	return 0;
}

操作符详解_结构体_02

同理,使用逻辑或操作符时,只要左边算出1,则结果必定为1,后续便不再计算(下题中d的自增没有执行计算)。

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ || ++b || d++;
	printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);//1,3,3,4
	return 0;
}


条件操作符:exp1?exp2:exp3

int main()
{
	int a = 0;
	int b = 0;
	if (a > 5)
		b = 3;
	else
		b = -3;
	b = (a > 5 ? 3 : -3);//使用三目操作符
	return 0;
}
int main()
{
	int a = 10;
	int b = 20;
	int max = 0;
	if (a > b)
		max = a;
	else
		max = b;
	max = (a > b ? a : b);//使用三目操作符
	return 0;
}

逗号表达式:exp1,exp2,exp3,...,expn

逗号表达式,就是用逗号隔开的多个表达式。逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。


下标引用操作符:[]

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


函数调用操作符:()

操作数:函数名+函数操作符内的对象

int get_max(int x, int y)//这里的()不是函数调用操作符
{
	return x > y ? x : y;
 }

int main()
{
	int a = 10;
	int b = 20;
	//调用函数的时候的()就是函数调用操作符
	int max = get_max(a, b);
	return 0;
}


访问一个结构成员:. ->

结构体变量.成员名

结构体指针->成员名

struct stu//创建了一个结构体类型-struct stu
{
	//成员变量
	char name[20];
	int age;
	char id[20];
};

int main()
{
	int a = 10;
	struct stu s1 = { "张三",20,"2019010305" };
	struct stu* ps1 = &s1;
  
	printf("%s\n", (*ps1).name);
	printf("%s\n", ps1->name);//结构体指针->成员名
  
	//使用struct stu这个类型创建了一个学生对象s1,并初始化
	printf("%s\n", s1.name);
	printf("%d\n", s1.age);
	printf("%s\n", s1.id);
	//结构体变量.成员名
	return 0;
}


二、表达式求值

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

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

隐式类型转换

整型提升

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

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

按照变量的数据类型的符号位进行提升,例如char(00000011),按照最高位(即符号位)向前24位全部补0;char(10000001),按照最高位(即符号位)向前24位全部补1;如果是无符号数则直接补0。

int main()
{
	char a = 3;
	//00000000000000000000000000000011
	//00000011-a
	char b = 127;
	//00000000000000000000000001111111
	//01111111-b
	char c = a + b;
	//a和b如何相加?先整型提升,再相加,结果将被截断存储与c中
	//00000000000000000000000000000011
	//00000000000000000000000001111111
	//00000000000000000000000010000010
	//10000010-c

	printf("%d\n", c);//-126
	//打印整型类型,再次进行整型提升
	//11111111111111111111111110000010-补码
	//11111111111111111111111110000001-反码
	//10000000000000000000000001111110-原码
}

算术转换

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

long double
double
float
unsigned long int
long int 
unsigned int
int


操作符的属性

1.操作符的优先级

2.操作符的结合性

3.是否控制求值顺序

a*b+c*d+e*f;

p.s.由于比+优先级高,只能保证相邻的两个操作符的顺序,即第一个和第二个比第一个+计算更早,但操作符的优先级并不能决定第三个比第一个+更早执行

c + --c;

p.s.同理,操作符的优先级只能决定--运算在+之前,但是无法得知,+的左操作数的获取在右操作数之前还是之后,所以结果是不可预测的,是有歧义的


标签:return,int,++,详解,操作符,printf,main
From: https://blog.51cto.com/u_16292010/9355916

相关文章

  • 详解ffmpeg avcodec_encode_video2 函数报错
    详解ffmpegavcodec_encode_video2函数报错在使用FFmpeg进行视频编码时,开发者经常会使用avcodec_encode_video2函数来进行编码操作。然而,有时候会遇到该函数报错的情况,本文将详细解析这个问题及其可能的解决方法。问题描述当调用avcodec_encode_video2函数时,可能会出现以下错误信......
  • sed的&操作符+复盘和把经验转化为能力+sed替换关联环境变量+SystemC+C++的struct和cla
    sed的&操作符sed一般是按行操作,如果匹配到,那么匹配到的内容被表示为&。以下是在单行操作中,想要实现在某行数据特定字符前后插入字符的方法。复盘和把经验转化为能力https://www.163.com/dy/article/GEI2Q9EN05429MRP.html通过寻找和尝试新的做事方式,你才能提高自己的能力。......
  • Servlet系列:生命周期(init、 service、destroy)详解
    Servlet的生命周期是由Web容器(如Tomcat)管理的,包括以下三个阶段:加载和实例化:当Web应用程序启动时,Web容器会加载和实例化Servlet。加载和实例化过程可以在应用程序启动时自动完成,也可以通过Servlet的名称手动加载。在实例化Servlet后,Web容器会调用其init()方法进行初始化。处理请......
  • 详解Redisson
    第1章:Redisson简介大家好,我是小黑,咱们今天来聊聊Redisson,Redisson不只是简单地对Redis进行了封装,它还提供了一系列高级的分布式Java数据结构,像是分布式锁、原子长整型这种。首先,Redisson的核心特点是什么呢?它提供了对Redis的各种操作的高层封装,这让咱们在使用Redis时更加方便、......
  • linux之线程互斥(万字长文详解)
    linux之线程互斥多线程在访问共享资源时的问题假如我们设置一个全局变量!inttickets=1000;//充当有1000张票void*getTicket(void*args){std::stringusername=static_cast<constchar*>(args);while(true){if(tickets>0){......
  • C++多重返回值:引用参数、结构体和元组实例详解
     在C++中,函数通常只能返回一个值。但是,可以通过引用参数、结构体、元组(C++11及以后版本支持)等方式实现函数具有多个返回值的效果。以下是其中几种方法的实例:1.通过引用参数:#include<iostream>//通过引用参数实现多个返回值voidmultipleReturns(inta,intb,int&......
  • sringboot整合shiro实现前后端鉴权控制,标签注解速成(包含常见错误的出现,前后端注解标签
    搭建shiro环境1:导入boot项目中要用到的shiro依赖<!--shiro部分--><!--shiro核心源码--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version......
  • 详解SIFT,SURF,ORB,FAST 特征提取算法比较
    详解SIFT,SURF,ORB,FAST特征提取算法比较在计算机视觉领域中,特征提取是一项重要的任务,可以用于图像匹配、目标识别、图像拼接等应用。SIFT、SURF、ORB和FAST是广泛使用的特征提取算法。在本文中,我们将详细比较这些算法并讨论各自的优缺点。1.SIFT(尺度不变特征变换)SIFT算法......
  • 热血江湖服务端开服遇到的小问题详解
    热血江湖服务端开服遇到的小问题详解大家好我是艾西,今天跟大家分享下你们自己在搭建热血江湖或是开服过程中会遇到的小问题以及常用到的一些指令都是什么意思,有了一定的基础了解在后期您干起来肯定会更加的得心应手!出现ODBC链接不了:出现ODBC数据库配置连接失败的问题,可能是由于以下......
  • Spring IOC 容器加载过程详解
    在Spring框架中,IOC(InversionofControl)容器是核心的概念之一。IOC容器负责管理和装配各个组件,本文将详细介绍SpringIOC容器的加载过程,包括如何配置、初始化和装配Bean。1.什么是IOC容器IOC容器是Spring框架的一个关键组件,负责管理Java对象的生命周期、配置信息以及对象之间的......