IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c语言操作符 -> 正文阅读

[C++知识库]c语言操作符

算数操作符

+, - , * ,/ ,%

"/"很特殊,对于 / (除号) 两边都是整数,执行的是整数除法
操作数中有浮点数才执行浮点数除法
在这里插入图片描述
%:取模
取模操作符只能针对整型类型
在这里插入图片描述

移位操作符

<< :左移操作符
在这里插入图片描述
如果a= -1(正整数原反补相同)
在这里插入图片描述

    // << - 左移操作符:左边丢弃,右边补0(针对存储在内存中的补码)


	int a = -1;
	int b = a << 1;
	printf("%d\n", b);//打印的是原码的值


	//移位操作符,移动的是二进制位
	//对于整数的二进制有三种表现形式:原码 - 反码 - 补码
	//正整数:原码,反码,补码相等
	//负整数:
	//原码 - 直接按照数字的正负写出的二进制序列(正:最高位是0;负:最高位是1)
	//反码 - 原码的符号位不变,其他位按位取反
	//补码 - 反码+1
	//整数在内存中,存储的是二进制的补码

">>"右移操作符

  1. 逻辑移位
    右边丢弃,左边补0
  2. 算术移位(vs用的是算术右移)
    右边丢弃,左边补原符号位

不管是左移还是右移,操作符的两边都必须是整型

位操作符

💥这些都是在 补码 下操作

& 按位:有0则0,全1则1

	int a = 3;
	int b = -2;
	int c = a & b;//按内存中的补码来计算,必须写出a,b的二进制补码
	printf("%d\n", c);//打印要打印原码,这里c为2
	
	//%d - 说明要打印c的值,以有符号的形式
	//%u - 无符号的形式

    //10000000000000000000000000000010 -b的原码
	//11111111111111111111111111111101 -b的反码
	//11111111111111111111111111111110 -b的补码

	//&:有0则0,全1则1
	//00000000000000000000000000000011 -a的补码
	//11111111111111111111111111111110 -b的补码
//结果00000000000000000000000000000010 -c的补码
	//因为c是正数,所以原反补相等

| 按位 : 有1则1,全0则0

    int a = 3;
	int b = -2;
	int c = a | b;
	printf("%d\n", c);
	//按位或:有1则1,全0为0
	//00000000000000000000000000000011 -a的补码
	//11111111111111111111111111111110 -b的补码
//结果11111111111111111111111111111111 -c的补码

	//c是负数,要计算原反补
	//11111111111111111111111111111111 - c的补码
	//11111111111111111111111111111110 - c的反码
	//10000000000000000000000000000001 - c的原码,c就为-1

^按位异或 :相同为0,相异为1

    int a = 3;
	int b = -2;
	int c = a ^ b;//异或
	printf("%d\n", c);
	//按位异或:相同为0,相异为1
	//00000000000000000000000000000011 -a的补码
	//11111111111111111111111111111110 -b的补码
	//11111111111111111111111111111101 -c的补码

	//11111111111111111111111111111101 -c的补码
	//11111111111111111111111111111100 -c的反码
	//10000000000000000000000000000011 -c的原码,c就为-

面试题:用异或实现a,b的交换(只适用于整型)

    int a = 3;
    int b = 5;
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;

在这里插入图片描述

a^a=0 ; 0^a=a,并且异或支持交换律

所以a,b用异或交换的代码可以理解为
在这里插入图片描述

赋值操作符

int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//连续赋值

复合操作符

在这里插入图片描述

单目操作符

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

1. !— 逻辑反操作符
0为假,非0为真
在这里插入图片描述
2. + – 正号,负号
正负号不必多说
3. & — 取地址 操作符; * — 解引用操作符

在这里插入图片描述


	int arr[10] = { 0 };
	arr;//数组首元素地址
	&arr[0];//数组首元素的地址
	&arr[19];//取出数组第十个元素的地址
	&arr;//取出数组的地址
	
	int a = 10;
	int* p = &a;

	int b = *p;//相当于把a赋值给b
	*p = 20;//* -- 解引用操作符
	//相当于把a修改成20

等号左边的理解为左值,等号右边的理解为右值
左值 – 空间
右值 – 空间的内容

4.sizeof

1.sizeof是操作符,不是函数
2.sizeof是计算变量或者类型创建变量的内存大小,单位是字节,和内存中存放什么数据没有关系

	char arr[10] = "abc";
	printf("%d\n", sizeof(arr));//10
	printf("%d\n", strlen(arr));//3 //strlen求的是字符串的长度
	//关注内存中是否有\0,计算的是\0之前出现的字符个数

我们也要知道sizeof 内部的表达式是不参与运算的!

	int a = 5;
	short s = 10;
	printf("%d\n", sizeof(s = a + 2));//2,因为short占两个字节
	printf("%d\n", s);//10,因为sizeof 内部的表达式是不参与运算,s没变

5.~ 按位取反


	int a = 0;
	//00000000000000000000000000000000
	int b = ~a;//按位取反,得到在内存中的补码
	//11111111111111111111111111111111 --补码
	//11111111111111111111111111111110 --反码
	//10000000000000000000000000000001 --原码

	printf("%d\n", b);
	//%d代表有符号,因此二进制第一位为符号位

	int a = 13;
	a |= (1 << 1);
	printf("%d\n", a);//15

	//00000000000000000000000000001101 13跟下面一行按位或
	//00000000000000000000000000000010 1<<1
//得到00000000000000000000000000001111 15,再跟下面一行按位与
	//11111111111111111111111111111101 这一行代表~(1<<1)
	a &= (~(1 << 1));
	printf("%d\n", a);//13
}

6.前置++和后置++

    int a = 10;
	int b = a++;//后置++,先使用后++
	//先把a的值赋给b,a再++

	int c = ++a;//前置++,先++后使用
	//a先++,再赋值给c

7.(类型)强制类型转换
如果我们int a = 3.14;//直接写出的浮点数是double类型这么写,编译器会有警告
在这里插入图片描述
所以我们可以在前面加(int),int a = (int)3.14;

sizeof和数组

#include <stdio.h>
void test1(int arr[])
{
printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));//(4)
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
printf("%d\n", sizeof(arr));//(1)
printf("%d\n", sizeof(ch));//(3)
test1(arr);
test2(ch);
return 0;
}
问:
(1)、(2)两个地方分别输出多少?
(3)、(4)两个地方分别输出多少

在这里插入图片描述
因此(1),(2)输出40,4;(3)(4)输出10,4

逻辑操作符

💝 逻辑与 &&

    int a = 3;
	int b = 0;
	int c = a && b;//逻辑与:只关心真假
	//a与b都为真,结果为真,用1表示
	//a和b其中一个为假,结果就是假,用0表示

💝 逻辑或 ||

    int a = 3;
	int b = 0;
    int d = a || b;//逻辑或
	//a和b只要一个为真,结果就为真
	//a和b都为假,结果才为假

360面试题

#include <stdio.h>
int main()
{
  int i = 0,a=0,b=2,c =3,d=4;
  i = a++ && ++b && d++;

  
  printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
  return 0;
}
//程序输出的结果是什么

在这里插入图片描述

所以程序结果是1,2,3,4

如果把a改成1(真)结果又是什么?
在这里插入图片描述

所以结果就是2,3,3,5

如果把&&改成||结果又是什么?
在这里插入图片描述

结果就为 2 2 3 4

条件操作符

exp1 ? exp2 : exp3(三目操作符)
表达式1的结果为真,表达式2的结果就是整体的结果,否则整体的结果就是表达式3的结果

    int a = 3;
	int b = 5;
	int m = (a > b ? a : b);
	//m得到的就是a和b之间的最大值

逗号表达式

exp1, exp2, exp3, …expN
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果,前面表达式的改变可能会改变结果。

int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?

执行a>b不会改变a,b;执行a=b+10,a就改变成12;a也不改变什么;b=a+1,b改变成13
所以c就是最后一个表达式的值13

下标引用,函数调用,结构体

1.[ ] 下标引用操作符
操作数:一个数组名 + 一个索引值

int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
//arr[9]跟*(arr+9)等价,跟9[arr]也等价
//[ ]的两个操作数是arr和9。

2.()函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数

void test1()
{
printf("hehe\n");
}
void test2(const char *str)
{
printf("%s\n", str);
}
int main()
{
test1();       //实用()作为函数调用操作符。
test2("hello bit.");//实用()作为函数调用操作符。
return 0;
}

3.访问一个结构的成员

. 结构体.成员名
-> 结构体指针->成员名
(*结构体指针).成员名

//struct Book;//不想在前面定义,可以先声明

//自定义类型
struct Book
{
	char name[20];
	float price;
	char id[10];
};

void Print(struct Book b)//传值传参
{
    //字符使用“%c”占位符,“字符串”使用的是“%s”占位符
	printf("书名:%s 价格:%.2f  书号:%s", b.name, b.price, b.id);
	printf("\n");
}

void Print1(struct Book* pb)//传址传参
{
	printf("书名:%s 价格:%.2f  书号:%s", pb->name, pb->price, pb->id);
	printf("\n");
}

int main()
{
	//float类型,数字后面要加f
	struct Book b = { "三体",55.4f,"c2022213" };
	Print(b);
	b.price = 100.1f;//价格能改
	//b.name = "数据结构";
	//因为name是个数组,在这里相当于首元素地址
	
	//所以用到---字符串拷贝strcpy
	strcpy(b.name, "数据结构");
	//意思是把"数据结构"这个字符串,拷贝到name指向的空间
	Print1(&b);
	return 0;
}

隐式类型转换

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

如何整型提升?

整型提升是按照变量的数据类型的符号位来提升的;
负数高位补1,正数高位补0;

下面代码进行了两次整型提升,a+b一次,printf("%d",c)一次

int main()
{
	char a = 3;//a是一个byte - 8个bit位
  //00000000000000000000000000000011  3是正数,原反补相同
  //00000011 --截断后的a
	char b = 127;
  //00000000000000000000000001111111  127是正数,原反补相同
  //01111111 --b

	//a和b都是char类型,自身大小都是一个字节,所以这里计算时要进行整型提升

	//计算a+b要进行整型提升;char是有符号,二进制第一位就是符号位
	//a:00000000000000000000000000000011
	//b:00000000000000000000000001111111
    //  00000000000000000000000010000010
	char c = a + b;
	//10000010 -c因为c也只能存放8个bit位
	printf("%d", c);
	//这里要打印整型并且打印是打印原码,所以c又会发生整型提升
	
	//  11111111111111111111111110000010 注意:这是c的补码!!!
	//  11111111111111111111111110000001 反码
	//  10000000000000000000000001111110 原码
	//  -126
	return 0;
}

不要觉得charshort在存储时,就发生了整型提升!发生这个整型提升的前提是它们参与整型运算!!而且整型运算结束后,4个字节的数据将发生截断,再返回值。也就是说,运算完成后,CPU返回值的字节数仍为这个数据原本类型的字节数,而不是提升后的字节数。截断的规则是留低位弃高位

整型提升的例子:

int main()
{
	char a = 0xb6;//11010110 char是有符号,高位补符号位;unsigned int 是无符号,高位补0;
	//a整型提升后:11111111111111111111111111010110(补码)

	short b = 0xb600;//1101011000000000 b占两个字节--16个bit位
	//b整型提升后
	//11111111111111111101011000000000(补码)
	int c = 0xb6000000;
	//"=="逻辑运算符,所以会发生整型提升
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)//c不会整型提升
		printf("c");
	return 0;
}

a,b要进行整形提升,但是c不需要整形提升

例2:

int main()
{
	char c = 1;
	printf("%u\n", sizeof(c));//1;没有参与运算 
	printf("%u\n", sizeof(+c));//4 "+c"参与运算,会进行整型提升
	printf("%u\n", sizeof(-c));//4 "+c"参与运算,会进行整型提升
	return 0;
}

算术转换

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

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

操作符的三个属性

1.操作符的优先级
2.操作符的结合性
3.是否控制求值顺序; 比如&&,左边为假,右边的就不用算了
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。

在这里插入图片描述

问题表达式1:a*b + c*d + e*f二义性

注释:代码1在计算的时候,由于比+的优先级高,只能保证的计算是比+早,但是优先级并不能决定第三个*比第一个+早执行
所以表达式1计算顺序可能是

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:c + --c;,可能会计算出不同结果

假设c=3,最左边的c不知道什么时候准备好
可能13+2
可能22+2

问题代码3:

int fun()
{
  static int count = 1;
  return ++count;
}
int main()
{
  int answer;
  answer = fun() - fun() * fun();
  printf( "%d\n", answer);//输出多少?
  return 0;
}

我们只知道*优先级高于 -,但是我们不知道谁先调用fun(),没有唯一计算路径

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-16 12:52:35  更:2022-02-16 12:54:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:23:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码