3.C语言运算符

运算符与表达式

基本概念:

1.运算符:

​ 用来进行某种运算的符号,如我们最常见的+,-,*,/

2.几目运算符 :

​ 几目就是看有几个操作数,如:

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

​ 双目运算符:只有两个操作数的运算符

​ 三目运算符:只有三个操作数的运算符

3.优先级:

​ 决定在运算中谁先算谁后算

​ 优先级简记:

​ 初等运算符(() [] -> .) > 单目运算符 > 算术运算符 > 移位运算符>关系运算符 >位运算符> 逻辑运算符 > 条件运算符 >赋值运算符 > 逗号运算符

​ 下面是在别人的博客上找的2张运算符优先级的图,互为补充:
在这里插入图片描述
在这里插入图片描述

4.结合性:

​ 决定运算中操作数怎么去结合在一起,是从左到右,还是从右到左

​ 如:a + b 和b + a在c语言里面是不一样的,“+”运算符结合性是从左到右

​ 例: i = 5; j = 6;

​ (i++) + (i + j) //结果为17

​ (i + j) + (i++) //结果为16

5.表达式:

​ 只要能表达某一个意思的式子都叫表达式

​ 在c语言里面,只要是合法的表达式都可以求值

算数运算符:

即进行算术运算的运算符

(1) + - / * %: 双目运算符,结合性从左到右

​ 需要注意的地方:

​ 5 / 4 -> 1 取整

​ 5.0 / 4 -> 1.25 除以

​ 因此我们在用的时候 ,如果你要用除法实现5/4,可以将5/4改写为以下形式

​ 5 * 1.0 / 4 ->1.25

​ (double)5 / 4 -> 1.25

​ 如果将上面的表达式不小心写成了下面这样,其结果是不一样的

​ (double)(5 / 4)-> 1.0

​ %:取余 只有操作数是整数的时候才有意义

​ ->因此两个操作数都要是整数

(2) ++ – : 单目运算符,自增自减运算符

​ int i = 5;

​ 表达式 表达式的值 做完表达式后i的值

​ i++ i(5) i = i + 1 = 6

​ ++i i + 1(6) i = i + 1 = 6

​ 小结: ++在前和在后做完表达式后的值是一样的,但表达式的值是不一样的

​ 思考:

​ int i= 9;

​ printf("%d %d %d %d %d\n",i–,--i,i,i++,++i);

​ 输出结果是什么?

解析:

​ 首先我们要明白printf在底层就是一个函数,一个实现输出功能的函数

​ C语言中规定: 函数调用的时候,结合性是从右到左

​ 根据从右到左的结合性:

​ 首先计算++i -----> 表达式的值为10, i的值也为10;

​ 然后计算i++ ------->表达式值为10,i的值为11;

​ 接着计算–i --------> 表达式值为10,i的值为10;

​ 最后计算i-- ------> 表达式值为10,i的值为9;

​ printf函数是计算完了再输出

​ 所以:i–,--i,i,i++,++i ------>10, 9, 9, 10,9

关系运算符:

​ 判断两者之间的关系 ,双目运算符 ,结合性是从左到右

​ 有: < > >= <= != ==

​ 关系表达式 : 关系运算符连在一起的式子

​ 既然是表达式,那必然会有值, 成立值为1 ,不成立值为0

​ 如:

​ 5>4 -->成立,所以表达式值为1

​ 2==3 ->不成立,表达式值为0

逻辑运算符:

​ ! 逻辑非 单目运算符 即真的变成假的 , 假的变成真的

​ && 逻辑与 双目运算符 结合性从左到右 并且的意思

​ || 逻辑或 双目运算符 结合性从左到右 或者的意思

​ 逻辑表达式:逻辑运算符连在一起的式子

​ 逻辑表达式的值, 逻辑真 -> 1 ,逻辑假 -> 0

​ 如:

​ !1 && 4 -> 假, 0

​ 4 && 0 || 1 -> 真, 1

惰性运算:

​ C语言里面有一个东西叫惰性运算

​ 只要表达式能得到最后的结果 , 后面得表达式就没有再计算下去得意义了。

​ ------> 所以,只要能知道了最后表达式值,就不会再计算后面表达式的值

​ 如:

​ int a = 1,b = 2,c = 3,d = 4,e = 5;

​ m = 1,n = 2;

​ (m = a > b) && (n = c > d > e)

​ 最后的m n的值为多少 ?

​ 答:0 2

​ 解析:

​ (m = a > b) && (n = c > d > e)

	&&:只要有一个假就全部为假了

​ 由于m = a > b是个假的 ----->可以确定这个表达式绝对是假的

​ 因此后面(n=c>d>e)就不会算了,n没有被赋值,值不变。

 小结:     

​ 在c语言里面,只要事先知道了这个表达式的值 ,那么后面的运算就不需要进行了

题目:闰年的判断

题目: 用逻辑表达式来判断一个年份是否为闰年

​ 1. 能被4整除 但是不能被100整除的年份为闰年

​ 2. 如果这个年份能被400整除也是闰年

#include<stdio.h>

int main()
{
	int year;
	while (1)
		{
			printf("请输入年份:");
			scanf("%d",&year);
			if(!year)
				break;
			if(year%400==0||(year%4==0&&year%100!=0))		//使用到了惰性运算
				printf("yes\n");
			else
				printf("no\n");
		}
}

位运算符:

​ 按照bit位来进行运算, 每一个bit位都要参与运算

​ 位运算符有下面的一些:

​ & 按位与

​ | 按位或

​ ~ 按位取反

​ << 左移

​ >> 右移

​ ^ 按位异或

​ ~是单目 , 剩余的都是双目的,结合性从左到右

进行位运算的前提:(重要)

​ 操作数必须是整型

1.按位取反

​ ~ :按位取反, 0变1 , 1变0

​ 例:

​ int a = -3;

​ a = ~a;

​ printf("%d\n",a); // 2

​ printf("%u\n",a); // 2

第一步:写出-3在计算机中的二进制表示形式(补码表示),负数补码 = 对应正数原码取反 + 1

​ 00000000 00000000 00000000 00000011
11111111 11111111 11111111 11111100

+1 11111111 11111111 11111111 11111101

第二步:取反得 结果
00000000 00000000 00000000 00000010

最后结果为2

2.按位与

& 按位与 : 同1才为1 , 只要有0就是0

​ 1 & 0 -> 0

​ 0 & 1 -> 0

​ 0 & 0 -> 0

​ 1 & 1 -> 1

例1:

​ 3 & 5 = ?

​ 00000000 00000000 00000000 00000011

& 00000000 00000000 00000000 00000101

-----------------------------------------------------------------

​ 00000000 00000000 00000000 00000001

所以 3&5 = 1

思考:

​ 假设有一个整形的变量a ,我不知道等于多少,要将这个a的第5bit变成0怎么办?

​ xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

& 11111111 11111111 11111111 11011111

-------------------------------------------

​ xxxxxxxx xxxxxxxx xxxxxxxx xx0xxxxx

​ 即 a & ~(1 << 5)

结论:

​ 想让某一个bit为变成0 其它的不变 那么我就要与上一个值

​ 这个值有个特点, 其它的bit都是1, 只有这个bit是0

拓展:

​ 假设有一个整形的变量a ,我不知道等于多少

 要将这个a的第Nbit变成0 ,怎么办?

​ -----> a & ~(1 << N)

3.按位或

​ | 按位或:双目运算符 只要有1就是1 全为0才是0

​ 1 | 0 ------> 1

​ 0 | 1 ------> 1

​ 0 | 0 ------> 0

​ 1 | 1 ------->1

思考:

​ 假设有一个整形的变量a ,我不知道等于多少,

​ 要将这个a的第Nbit变成1, 怎么办?

  xxxxxxxx   xxxxxxxx  xxxxxxxx   xxxxxxxx

​ | 00000000 00000000 00000000 00100000

​ --------------------------------------------------------------

​ xxxxxxxx xxxxxxxx xxxxxxxx xx1xxxxx

结论:

​ a | (1 << N)

4.按位异或

​ ^ 按位异或:相同为0 不同为1

​ 1 ^ 0 ----->1

​ 0 ^ 1 -----> 1

​ 0 ^ 0 -----> 0

​ 1 ^ 1 ------> 0

题目:交换两个变量的值

题目: 有 int a = 3,b = 5; 交换两个变量的值

//代码功能:实现a,b值的交换
#include<stdio.h>
#define M 1
int main()
{
	int a,b;
	a = 3;b = 5;
	//适用性不强,只针对某个a,b的数值
	#if(!M)
	a = a ^ 6;
	b = b ^ 6;
	printf("a=%d,b=%d\n",a,b);
	#endif
	//适用性强,但在a=b且都不为0的情况下不能交换a,b的值
	#if(M)
	a = 4;b = 5;
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("a=%d,b=%d\n",a,b);
	#endif
	return 0;
}
/*以下交换a,b的方法效率不如上面的方法,
需要给开辟一段新的内存存放临时变量,但可以交换任意a,b的值
int a,b,temp;
a = 3; b = 4;
temp = a;
a = b;
b =temp;
*/

既然我们要交换位置 只要每一个bit上面都交换是不是就可以了

a = a ^ bb = a ^ ba = a ^ b
a=0 b=0000
a=1 b=1011
a=1 b=0110
a=0 b=1101

上述真值表表明 ,经过三次异或之后 a和b就交换了位置

局限:当a=b 且不等于0时,使用这种方法会导致a=b=0

5.按位左移与按位右移

<< >>: 按位左移与按位右移

双目运算符, 尤其注意其优先级要高于& | ^,并且高于关系运算符

左移: 整体进行向左移位

<< :高位直接舍弃,低位直接补0

如果舍弃的高位全部是0 ,那么就相当于这个数瞬间放大 2 ^ n

右移: 整体进行向右移位

​ >>: 低位直接舍弃,高位

​ 对于有符号,高位补符号位

​ 对于无符号,高位补0

条件运算符:

​ ? : 三目运算符

​ 表达式 ? 表达式1 : 表达式2

​ 条件表达式的值为:如果表达式值如果为真 ,那么取表达式1的值,如果为假则取表达式2的值

​ 如:

​ int c = a > b ? a : b; //如果a>b, c = a, 否则c=b

​ (c = 4) ? a : b; //赋值表达式恒为真,该条件表达式的值恒为a

赋值运算符:

​ 双目运算符 结合性是从右到左

​ a = b = c = d; //先算右边

​ 赋值表达式有左值与右值之分

​ 如:

​ x=4; //赋值表达式的值为右值4

复合型的赋值运算符:

赋值运算符和算术运算符或位运算符组合起来便是复合型的赋值运算符

​ += -= *= /=

​ <<= >>= |= &= ^=

​ a += 5; -> a = a + 5;

​ a >>= 3; -> a = a >> 3;

逗号运算符:

双目运算符, 结合性从左到右

表达式1,表达式2,…

求值顺序:先求表达式1,然后再求表达式2…

整个表达式的值为最后一个表达式的值

int a = 4,b = 5;

a = (a = 4,b = 5) //括号里面的是逗号表达式,其值为最后一个表达式的值,所以a = 5

指针运算符:

*(指向一个地址)

&(取一个变量的地址)

求字节运算符: sizeof

sizeof在C语言中既是判断数据类型长度符的关键字,也是C/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数。

用法:

​ sizeof (类型说明符)

​ sizeof 表达式

如:

int i;
sizeof(i);		//ok
sizeof i;		//ok
sizeof(int);	//ok
sizeof int;		//error

//sizeof(i) 等于sizeof i 等于 sizeof(int)

struct node * p = malloc(sizeof(*p));	//sizeof(*p)为p指针所指向的结构体的大小
sizeof(p) = 4/8							//指针大小,32位系统为4,64位系统为8
    

sizeof与strlen(char*)函数的区别

​ strlen -> 求字符串的长度 , 遇到’\0’就结束, 字符’\0’等于十进制的0,十六进制的0x00,八进制的000

​ int a = 0x01000304; //小端模式,低位存低地址, 04 03 00 01

​ n = strlen((char *)(&a)); ----> 2

​ int a = 0x01030004; //小端模式 ,04 00 03 01

​ n = strlen((char *)(&a)); ----> 1

分量运算符:

  .       结构体变量成员引用用这个

   ->     结构体指针的成员引用用这个

示例:

struct node
{
    int a;
	char b;
};

struct node sb;

sb.a = 12;
sb.b = 'A';

struct node *sb = malloc(sizeof(*p));

sb -> a = 12;
sb -> b = 'A';

下标运算符:

​ []:常用于数组元素的引用

​ int a[3];

​ a[0] —>访问0号元素

​ a[1] —>访问1号元素

​ a[2] —>访问2号元素

​ a[3] -->你硬是要用也可以,就是一个内存 ,只是你已经非法访问了

​ 会不会出错我也不知道

强制类型转换运算符:

​ (类型)变量/值

​ (double)3 / 2; -> 1.5 //int类型转double类型

​ int(4.25) ->4 //double/float类型转int类型

函数调用运算符():

​ 函数调用实际上就是一个指针

​ 代码是放在.text段, 函数就是在这里

​ 我想执行一个函数 ,那么就是跳转到这个内存

​ 实际上就是进入这个地址

​ 函数的名字代表的是这个函数的地址

看到还不错的C语言中的运算符用法链接:

https://blog.csdn.net/dark_cy/article/details/88550777

https://blog.csdn.net/dark_cy/article/details/88550777?spm=1001.2014.3001.5506

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值