【C语言】操作符解析

1. 算数操作符(+、 -、 *、 /、 %)

在算数操作符中 +、 -、 * 和在我们平时在数学上所学到的运算法则都是相同的

#include<stdio.h>
int main()
{
    int a = 3;
    int b = 8;
    int sum = 0;
    //a与b相加
    sum = a + b;
    //a与b相减
    sum = a - b;
    //a与b相乘
    sum = a * b;
    return 0;
}

不同的是 /、 % ,所以接下来我们一起来看一看这两个操作符的具体用法吧

1.1 /(除法) 操作符的使用

对于 / 来说不是我们所熟悉的,但是换一下表达方式就明白了,就是 ÷(除法),哎 / 这个操作符就是我们的除法操作符,它的用法有点区别,分为两种

第一种,就是 / 左边的数大于右边,则得出的结果是取商的那部分,相反的,若 / 左边的数小于右边,则得到的结果不是小数而是为0

#include <stdio.h>
int main()
{
	int a = 7;
    int b = 2;
	int sum = a / b;
	printf("%d ", sum);//此时打印出来的结果为3
	                   //7除以2 商3余1
	
	a = 2;
    b = 7;//将a b重新赋值
    sum = a / b;
	printf("%d ", sum);
	//此时打印出来的结果就是0
	return 0;
}

第二种,就是 / 两边有一边是浮点数

浮点数又是什么呢,也就是我们常说的小数嘛,对吧,很简单的

在除法运算中,只要有一个操作数是浮点数,就是浮点数的除法运算,所谓的浮点数除法运算就是,最后的结果是一个浮点数

#include <stdio.h>
int main()
{
	double sum = 7 / 2.0;
	printf("sum = %lf \n", sum);
	//此时打印出来的结果为3.5
 	//1f 就是保留一位小数
    
	sum = 2 / 7.0;
	printf("sum = %lf \n", sum);
	//此时打印出来的结果是0.2
    
	return 0;
}

1.2 %(取余) 操作符的使用

取模操作符,取的是一个数除另外一个直至除不尽的余数,若取模对象刚好是自己的公约数,则结果为0

例如 5%1=0 5%2=1 5%3=2 5%4=1 5%5=0

需要注意的是取模的对象不能为0,且不能为浮点型,必须为整数

#include <stdio.h>
int main()
{
	int a, b, sum;
	scanf("%d %d", &a, &b);
	sum = a % b;
	printf("%d", sum);
	//若a=5 b=1  则sum=0
    //若a=5 b=2  则sum=1
    //若a=5 b=3  则sum=2
    //若a=5 b=4  则sum=1
    //若a=5 b=5  则sum=0
	return 0;
}

2. 移位操作符( << >> )

在正式介绍移位操作符之前我们需要了解一下原码,反码和补码

2.1 原码,反码和补码

整数的2进制表示方法有三种,即原码、反码和补码

有符号整数的三种表示方法均有符号位和数值位两部分,2进制序列中,最高位的1位是被当做符号位,剩余的都是数值位

符号位都是用0表示“正”,用1表示“负”

正整数的原、反、补码都相同

负整数的三种表示方法各不相同

原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码

反码:将原码的符号位不变,其他位依次按位取反就可以得到反码

补码:反码+1就得到补码

例如:
10 - 原码:00000000000000000000000000001010

​ 反码:00000000000000000000000000001010

​ 补码:00000000000000000000000000001010

-10 - 原码:10000000000000000000000000001010

​ 反码:11111111111111111111111111110101

​ 补码:11111111111111111111111111110110

在这里插入图片描述

这里我们还要补充一个知识点

我们认为对于整形来说:数据存放内存中其实存放的是补码

这是为什么呢

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路

简单来说,就是计算机只会进行加法运算,那怎么才能减法运算呢,哎,我们说了,7 - 2 ,可以看做 7 + (-2) , -2就可以用补码表示,所以数据存放内存中其实存放的是补码

2.2 << 左移操作符

这里又需要注意的是移位操作符的操作数只能是整数

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

#include <stdio.h>
int main()
{
	int num = 10;
	int n = num<<1;
	printf("n= %d\n",n);
    printf("num= %d\n", num);
    return 0;
}

在这里插入图片描述

2.3 >> 右移操作符

移位规则:首先右移运算分两种:

1.逻辑右移:左边用0填充,右边丢弃

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

#include <stdio.h>
int main()
{
    int num = -1;
	int n = num<<1;
	printf("n= %d\n",n);
    printf("num= %d\n", num);
    return 0;
}

在这里插入图片描述

警告:对于移位运算符,不要移动负数位,这个是标准未定义的

例如:

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

3. 位操作符(&、|、^、~)

位操作符有:

& – 按位与 – 有0为0,全为1为1

| – 按位或 – 有1为1 ,同0为0

^ – 按位异或 – 相同为0,相异为1
– 按位取反 – 0变成1 ,1变成0

这里大家也需要注意一下,他们的操作数必须是整数

是吧,很简单,咱们直接上代码理解一下

#include <stdio.h>
int main()
{
    int num1 = -3;
    int num2 = 5;
    printf("%d\n", num1 & num2);
    //10000000000000000000000000000011 - 3的原码
    //11111111111111111111111111111101 - 3的补码
    //00000000000000000000000000000101 - 5的原码
    //00000000000000000000000000000101 - 5的补码
    //00000000000000000000000000000101 - 按位与之后的补码
    //00000000000000000000000000000101 - 按位与之后的原码,5
    printf("%d\n", num1 | num2);
	//11111111111111111111111111111101 - 3的补码
    //00000000000000000000000000000101 - 5的补码
    //11111111111111111111111111111101 - 按位或之后的补码
    //10000000000000000000000000000011 - 按位或之后的原码,-3
    printf("%d\n", num1 ^ num2);
    //11111111111111111111111111111101 - 3的补码
    //00000000000000000000000000000101 - 5的补码
    //11111111111111111111111111111000 - 按位异或之后的补码
    //10000000000000000000000000001000 - 按位异或之后的补码,-8
    printf("%d\n", ~0);
    //00000000000000000000000000000000 - 0的原码
    //00000000000000000000000000000000 - 0的补码
    //111111111111111111411111111111111 - 0按位取反之后的补码
    //10000000000000000000000000000001 - 0按位取反之后的原码,-1
    return 0;
}

有小伙伴就要问了有什么用,别急,我们先看一道变态的题目

⼀道变态的题目:

不能创建临时变量(第三个变量),实现两个数的交换

我相信小伙伴们,对于实现两个数的交换很熟悉了,就是

int tmp = a;
a = b;
b = tmp;

很简单,对不对,但是不能创建临时变量,我们应该怎么做呢,这就需要用到我们的 ^ 按位异或

在给出答案之前,我们需要知道两个基础的公式

a ^ 0 = a;

a ^ a = 0;

#include <stdio.h>
int main()
{
    int a = 10;
    int b = 20;
    a = a^b;
    b = a^b;//(a ^ b) ^ b = a ^ b ^ b = a
    a = a^b;//(a ^ b) ^ a = a ^ b ^ a = b
    printf("a = %d b = %d\n", a, b);
    return 0;
}

这样是不是就很轻松的不创建临时变量进行两个数的交换,小伙伴们学到了吗

如果学到的话,咱们来继续看几个练习吧,没学到的话,那就通过一些练习慢慢学吧

练习1:编写代码实现:求⼀个整数存储在内存中的⼆进制中1的个数

我们来想一想,假如是一个10进制的数字,怎么算

假如我给一个十进制的数字 1010 ,然后让我们求1的个数

是不是

1010%10 = 0
1010/10 = 101

先算个位上的数字,然后再算更高位的,对吧,这是算十进制数字的基本思路

然后我们接下来想想二进制的数字怎么办

还是 1010 ,不过这次是二进制的数字

1010%2 = 0
1010/2 = 101

是吧,很顺理成章吧,还是很容易想到的

你们加上一点while循环的小细节,代码就写出来了

#include <stdio.h>
int main()
{
    int num = 1010;
    int count = 0;//计数
    while(num)//num不为0,就进入循环
    {
    if(num%2 == 1)
    count++;
    num = num/2;
    }
    printf("⼆进制中1的个数 = %d\n", count);
    return 0;
}

有没有问题,其实再仔细想想看的话,还是有点小问题的

假如我要求 -1 二进制中的1的个数怎么办

前面我们已经提到了计算机存储数据的时候,存的是数据的补码

而 -1 的补码是 11111111111111111111111111111111

也就是32个1,这时怎么办

我们就要用到一个谷歌的算法

num = num&(num-1);

什么意思

假如 num = 1010

num - 1 = 1001

1010 & 1001 = 1000

这样从右往左的第一个1就被提出来了,有些小伙伴就不行,那我们再来看看

书接上回 num = 1000

num - 1 = 0111

1000 & 0111 = 0000;

怎么样,这下行了吧,然后我们再在原有的代码上这么一改就行了,好好体会一下这个算法吧

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

4. 单目操作符(!、++、–、&、*、+、-、 ~、sizeof、(类型))

单⽬操作符的特点是只有⼀个操作数

  • !:逻辑反操作符 、

  • -:负值

  • +:正值

  • & :取地址

  • sizeof 操作符

  • ++:自增

  • – :自减

  • *:解引用操作符

  • (类型):强制类型转换

这么多的操作符,有一部分已经讲过了,&和*,这2个操作符,我们会放在学习指针的时候讲到

那我们说说 ++、–、 (类型) 这三个单目操作符吧

4.1 ++(自增)

前置++:先++后使用(先让变量自增1,再使用)

后置++:先使用后++(先使用,再让变量自增1)

这个很好理解吧

来几个代码看看吧

#include <stdio.h>
int main()
{
	//前置++
	int a = 10;
	int b = ++a;
	//分为两步
	// a=a+1;
	// b=a;
	// 先让a自增1 再使用a 把a的值赋给b
	printf("%d\n", b);//b的值为11
 
	//后置++
	int c = 20;
	int d = c++;
	//分为两步
	// d=c;
	// c=c+1;
	//先使用c 把c的值赋给d 再让c自增1
	printf("%d\n", d);//d的值为20
	return 0;
}

4.2 --(自减)

前置–:先–,后使用 (先让变量自减1,再使用)

后置–:先使用,后-- (先使用,再让变量自减1)

这个也很好理解吧

来几个代码看看吧

#include <stdio.h>
int main()
{
	//前置--
	int a = 10;
	int b = --a;
	//此代码执行了两部操作
	// 第一步:a=a-1;
	// 第二步:b=a;
	printf("%d\n", b);//b的值为9
 
	//后置--
	int c = 20;
	int d = c--;
	//此代码也执行了两步操作
	// 第一步:d=c;
	// 第二步:c=c-1;
	printf("%d\n", d);//d的值为20
	return 0;
}

4.3 (类型)(强制类型转换)

强制类型转换就是将一种类型的数据,强制转换成另一种类型的数据

注意:当大类型往小类型转换时会发生截断

为什么是截断呢

当 float 或者 dauble 类型强转为 int 类型时: 发生截断 取到的是整数部分

当 char 类型 强转为 int 类型时:取到的是其对于的 ACSII码值

不好理解?来几个代码看看

#include <malloc.h>
#include <stdio.h>
 
int main()
{
	// float 转 int 截断取整数部分 
	float a = 3.14f;
	int b = (int)a;
	printf("%d\n", b);// b为3
 
	// double 转 int 截断取整数部分 
	double d = 4.225;
	int e = (int)d;
	printf("%d\n", e);// e为4
 
	// char 转 int  取到ASCLL值
	char c = 'A';
	int f = (int)c;
	printf("%d\n", f);// f 为 65
    
	return 0;
}

5. 逗号表达式

表达式1,表达式2,……,表达式n

逗号表达式,就是⽤逗号隔开的多个表达式

逗号表达式,从左向右依次执行,整个表达式的结果是最后⼀个表达式的结果

来几个代码吧

#include <stdio.h>
int main()
{
	int a = 1;
	int b = 2;
	int c = (a>b, a=b+10, a, b=a+1);
	//        1,   12,    12,   13
    printf("%d\n",c);//13
    return 0;
}

很简单吧,小伙伴们想对了吗

我再给几个代码,小伙伴们下去在看看吧

//代码1
if (a =b + 1, c=a / 2, d > 0)
    
//代码2
a = get_val();
count_val(a);
while (a > 0)
{
 //业务处理
 a = get_val();
 count_val(a);
}

//如果使⽤逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
 //业务处理
}

6. 下标访问[]、函数调用()

6.1 [ ] 下标引用操作符

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

int arr[10];//创建数组
arr[9] = 10;//实⽤下标引⽤操作符。
[ ]的两个操作数是arr和9。
#include <stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	//下标引用
	arr[0] = 8;
	//打印数组
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

6.2 ()函数调用操作符

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

#include <stdio.h>
void test1()
{
	printf("hehe\n");
}
void test2(const char *str)
{
	printf("%s\n", str);
}
int main()
{
	test1(); //这⾥的()就是作为函数调⽤操作符。
	test2("hello qiken");//这⾥的()就是函数调⽤操作符。
	return 0;
}

7. 操作符的属性:优先级、结合性

C语⾔的操作符有2个重要的属性:优先级、结合性,这两个属性决定了表达式求值的计算顺序

7.1 优先级

优先级指的是,如果⼀个表达式包含多个运算符,哪个运算符应该优先执⾏。各种运算符的优先级是不⼀样的

3 + 4 * 5;

上⾯⽰例中,表达式 3 + 4 * 5 ⾥⾯既有加法运算符 +,⼜有乘法运算符 * ,由于乘法的优先级⾼于加法,所以会先计算 4 * 5 ,⽽不是先计算 3 + 4

和我们在数学中的运算法则有点像,但还是有区别的

7.2 结合性

如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执⾏顺序。⼤部分运算符是左结合(从左到右执行),少数运算符是右结合(从右到左执行),⽐如赋值运算符=

5 * 6 / 2;

上面示例中, * 和 / 的优先级相同,它们都是左结合运算符,所以从左到右执行,先计算 5 * 6 ,再计算 6 / 2

运算符的优先级顺序很多,下面是部分运算符的优先级顺序(按照优先级从高到低排列),建议⼤概记住这些操作符的优先级就行,其他操作符在使用的时候查看下面表格就可以了

在这里插入图片描述

好了,我们到这里也结束了,其实还有几个重要的知识点还没讲到,比如,整形提升,算术转换,对于没有讲到的知识点,我现在还是蒙的,讲的话也解释不清楚,索性就不讲了,感兴趣可以自己下去了解,这里就抱歉了

最后,感谢你能看到这里,希望这篇文章对你有用,溜了溜了,我们下个星期再见吧

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值