C语言学习笔记(6)详解操作符

操作符

算数操作符

在这里插入图片描述
除了%操作符之外,其他的几个操作符可以作用于整数和浮点数。

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

#include<stdio.h>
int main()
{
	int a = 6 / 5;
	printf("a=%d\n", a);
	float b = 6.0 / 5;//或float a=6/5.0;
	printf("b=%f\n", b);
	return 0;
}

在这里插入图片描述

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

int main()
{
	int a = 7 % 3;
	printf("%d\n", a);
	return 0;
}

在这里插入图片描述

位移操作符

在这里插入图片描述
在这里插入图片描述
左边抛弃,右边补0

int main()
{
	int a = 2;
	//把a的二进制位向左移动一位
	int b = a << 1;
	printf("b = %d\n", b);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
首先右移运算分两种:

  1. 逻辑移位左边用0填充右边丢弃
  2. 算术移位左边用原该值的符号位填充,右边丢弃

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里是移动-1的补码
在这里插入图片描述

对于正整数来说
原码,反码,补码相同

位操作符

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

小练笔
不创建临时变量,实现两个数的交换

方法一

int main()
{
	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);
	return 0;
}

在这里插入图片描述
这种方法有缺陷,当a,b值较大时会溢出

方法二

int main()
{
	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);
}

在这里插入图片描述

赋值操作符

在这里插入图片描述

单目操作符

在这里插入图片描述

0表示假,非0表示真,非上任何不为0的数都为0(假),非0为固定值1。
在这里插入图片描述
sizeof
在这里插入图片描述
看如下代码

#include<stdio.h>
int main()
{
	short i = 0;
	int j = 3;
	printf("sizeof(i = j + 2)=%d\n", sizeof(i = j + 2));
	printf("i=%d\n", i);
	return 0;
}

运行结果为
在这里插入图片描述

这里不管j为何种类型,j+2都放入短整型i中sizeof(i=j+2)等于 sizeof(i)等于sizeof(short)等于2。

sizeof里面放的表达式并不会真实进行运算,只是一个摆设也就是说 i=j+2 这一步操作并未真实执行,所以i还是原来的值:0。

~

补码中所有二进制位按位取反。
在这里插入图片描述
在这里插入图片描述
思考题
怎么把二进制中第n位置为1,怎么把二进制中第n位置为0

把二进制中第n位置为1可以或上2(n-1)

int main()
{
	int a = 13;
	//把a的二进制中的第5位置成1
	a = a | (1 << 4);
	printf("a = %d\n", a);
	return 0;
}

在这里插入图片描述
把二进制中第n位置为0可以与上~2(n-1)

int main()
{
	int a = 29;
	//把a的二进制中的第5位置成0
	a = a & ~(1 << 4);
	printf("a = %d\n", a);
	return 0;
}

在这里插入图片描述
&和*

int main()
{
	int a = 10;
	printf("%p\n", &a);//& - 取地址操作符
	int * pa = &a;//pa是用来存放地址的 - pa就是一个指针变量
	*pa = 20;//* - 解引用操作符 - 间接访问操作符
	printf("%d\n", a);
	return 0;
}

(类型)强制类型转换

int main()
{
	int a = 3.14;
	printf("%d\n", a);
	return 0;
}

运行如上代码时,会提出警告
在这里插入图片描述
当强制类型转换后警告就消除了

int main()
{
	int a = (int)3.14;
	printf("%d\n", a);
	return 0;
}

关系操作符

在这里插入图片描述

注意:==(判断相等)和 =(赋值)的区别

逻辑操作符

在这里插入图片描述
计算下面代码

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

在这里插入图片描述
&&逻辑与中只要有一个表达式为假,那么整个逻辑与表达式就为假。
上述代码中因为a为假所以之后的表达式就不用计算了,整个表达式都为假。

逻辑或只要有一个表达式为真,就会停止计算,下面中的b>0为真,就停止了计算。
在这里插入图片描述

条件操作符(三目操作符)

exp1?exp2:exp3

  • exp1成立,表达式结果为exp2
  • exp1不成立,表达式结果为exp3
int main()
{
	int a = 3;
	int b = 5;
	int max = 0;
	max = a > b ? a : b;
	printf("max=%d\n", max);
	return 0;
}

在这里插入图片描述

逗号表达式

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

int main()
{
	int a = 3;
	int b = 5;
	int c = 0;
	int d = (c = 1, a = c + 3, b = a - 4, c += b);
	printf("a=%d\n", a);
	printf("b=%d\n", b);
	printf("c=%d\n", c);
	printf("d=%d\n", d);
	return 0;
}

在这里插入图片描述

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

在这里插入图片描述
[ ]
下标引用操作符

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", arr[4]);//[] - 就是下标引用操作符
	return 0;
}

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

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

.
->
访问一个结构体成员
结构体.成员名
结构体指针->成员名

//创建了一个自定义的类型
struct Book
{
	//结构体的成员(变量)
	char name[20];
	char id[20];
	int price;
};
int main()
{
	struct Book b = {"C语言", "C20210509", 55};
	printf("书名:%s\n", b.name);
	printf("书号:%s\n", b.id);
	printf("定价:%d\n", b.price);

	return 0;
}
struct Book
{
	char name[20];
	char id[20];
	int price;
};
int main()
{
	struct Book b = {"C语言", "C20210509", 55};
	struct Book * pb = &b;
	printf("书名:%s\n", (*pb).name);
	printf("书号:%s\n", (*pb).id);
	printf("定价:%d\n", (*pb).price);

	return 0;
}
struct Book
{
	char name[20];
	char id[20];
	int price;
};
int main()
{
	struct Book b = { "C语言", "C20210509", 55 };
	struct Book * pb = &b;
	//结构体指针->成员名
	printf("书名:%s\n", pb->name);
	printf("书号:%s\n", pb->id);
	printf("定价:%d\n", pb->price);

	return 0;
}

上述代码运行结果均为
在这里插入图片描述

表达式求值

  1. 表达式求值的顺序一部分是 由操作符的优先级和结合性决定。
  2. 同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。

隐式类型转换

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

整型提升的意义:

表达式的整型运算要在CPU的相应运算器件内执行, CPU内整型运算器(ALU)的操作数的字节长度-般就是int的字节长度,同时也是CPU的通用寄存器的长度。

因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。

通用CPU ( general-purpose CPU )是难以直接实现两个8比特字节直接相加运算( 虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。

如何进行整型提升呢?

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

在这里插入图片描述

int main()
{
	char a = 3;
	char b = 127;
	char c = a + b;
	printf("c=%d\n", c); 
	return 0;
}

在这里插入图片描述

在这里插入图片描述

算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。
在这里插入图片描述
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外个操作数的类型后执行运算

警告:但是算术转换要合理,要不然会有一些潜在的问题。

操作符的属性

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

  1. 操作符的优先级。
  2. 操作符的结合性。
  3. 是否控制求值顺序。

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

操作符优先级表

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值