目录
总结
前言
上一节我们讲解了操作符的第一部分,即算术操作符,移位操作符和位操作符,接下来我们来学习操作符的第二部分。
一、赋值操作符
int main() {
int a = 0;
a = 10;
printf("%d", a);
return 0;
}
初始化a=0,当我们想改变a的值时,我们可以通过复制操作符来改变它。
赋值操作符可以连续使用,比如:int a = 10 ;int x = 0 ;int y = 20 ;a = x = y + 1 ; //连续赋值这样的代码感觉怎么样?那同样的语义,你看看:x = y + 1 ;a = x ;这样的写法是不是更加清晰爽朗而且易于调试。
复合赋值符
+=-=*=/=%=>>=<<=&=|=^=
这些运算符都可以进行复合复制,例如:
a=a+1;
a+=1;
a++;
这三种表达形式都是正确的,在我们写代码的过程中,合适的用上复合复制操作符有助于简化我们的代码。
二、单目操作符
1.单目操作符类型
! 逻辑反操作- 负值+ 正值& 取地址sizeof 操作数的类型长度(以字节为单位)~ 对一个数的二进制按位取反-- 前置、后置 --++ 前置、后置 ++* 间接访问操作符 ( 解引用操作符 )( 类型 ) 强制类型转换
2. !逻辑反操作符
逻辑反操作符就是代表反过来,非的意思,在我们的C语言中有一种bool类型,false代表假,而true代表真,一个数为0时为假,非0时为真,一个负数也为真,只要不为0就为真。
下边一个例子来说明逻辑反操作符:
int main() {
int a = 0;
if (a) {
printf("a\n");
}
if (!a) {
printf("!a\n");
}
return 0;
}
2.-负值 +正值
负值,正值这两个操作符可以改变数值的正负号,由于正号并不会对数值产生实质性的影响,平时我们将这个正号省略,想要改变数值的正负时,加上一个负号“-”。
int main() {
int a = 1;
int b = -a;
int c = +a;
printf("%d %d %d ", a, b, c);
return 0;
}
可见,负号可以改变数字的正负,而正号不会产生影响。
3.取地址& 解引用*
取地址操作符在我们的函数和指针中很常见,如果我们定义了一个变量,内存为它分配了空间,它有了自己的地址,我们想要得到这个地址时,我们就可以通过取地址操作符来获得地址。
int main() {
int a = 0;
int* pa = &a;
printf("%p", pa);
return 0;
}
而解引用操作符相反,当我们得到一个地址,我们就可以通过解引用来获得这个地址所对应的元素,在我们前边的传值调用和传址调用中我们已经有所涉及,传递过去的是地址,通过地址解引用获得对应的元素来进行操作。
int main() {
int a = 0;
int* pa = &a;
*pa = 10;
printf("%d", a);
return 0;
}
我们得到变量a的地址时,我们可以通过解引用来改变a的值。
4.sizeof操作符
sizeof操作符可以计算出该类型元素所占字节的大小,如:
int main() {
int a = 0;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof a);
//printf("%d\n", sizeof int);这种写法不行
return 0;
}
我们也要记得sizeof()内表达式不计算,例如:我们在sizeof(),在操作符内部计算b的值,b并不会发生变化。
int main() {
int a = 0;
int b = 0;
int sz = sizeof(b = a + 1);
printf("%d\n", sz);
printf("%d\n", b);
return 0;
}
同时,sizeof关键字可以计算出数组中元素的个数,在数组arr中,sizeof(arr)/sizeof(arr[0])可以计算出arr数组中元素的个数。
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int num = sizeof(arr) / sizeof(arr[0]);
printf("%d", num);
return 0;
}
5.~按位取反操作符
~按位取反操作符也是对二进制序列进行操作,我们前边学了数据在内存中是通过补码的形式存储的,这个操作符就是对二进制的每一位进行取反操作,0改为1,1改为0。
例如:
-1的补码为1111 1111 1111 1111 1111 1111 1111 1111
取反后 0000 0000 0000 0000 0000 0000 0000 0000
由于正数原码和补码相同,所以-1按位取反后得到的数为0
int main() {
int a = -1;
int b = ~a;
printf("%d", b);
return 0;
}
6.--减减和++加加操作符
通过--和++操作符我们可以完成自减或者自加的目的,自减或者自加也分为前置和后置,前置代表先自减或者自加后使用,而后置代表自减或者自加前就使用。
int main() {
int a = 0;
printf("%d\n", a);
printf("%d\n",a++);
printf("%d\n", ++a);
return;
}
可以看到,前置是先加后使用,而后置是先使用后加。
7.强制类型转换()
在我们的代码中,有时候会有类型改变的情况,当我们需要进行数据类型的改变时,我们可以通过强制类型转换来实现。
例如:
#include<stdio.h>
int main() {
float a = 0;
a = 3.14;
printf("%d", (int)a);
return 0;
}
当我们有一个浮点型的变量,我们需要让他变为整型时,我们可以通过强制类型转换来操作,但是当我们由浮点型转换为整型时,可能存在数据的丢失,编译器会对我们发出警告。
三、关系操作符
>>=<<=!= 用于测试 “ 不相等 ”== 用于测试 “ 相等 ”
关系操作符可以用于判断语句,它与赋值操作符不同,当我们使用if语句时,判断一个数是否大于0,可以写成if(a>0),判断一个数是否等于0,必须写成if(a==0),而不是if(a=0),当写成这样时,if语句判断为假,永远不会执行。
四、逻辑操作符
&& 逻辑与|| 逻辑或
区分 逻辑与 和 按位与区分 逻辑或 和 按位或1 & 2 -----> 01 && 2 ----> 11 | 2 -----> 31 || 2 ----> 1按位与和按位或时对二进制序列某一位进行操作,而逻辑与与逻辑或则是对数字进行操作,结果只为0或1,0为假,1为真。
我们通过判断闰年的例子可以更好地掌握逻辑与和逻辑或的知识。
int main() {
int year = 2022;
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)){
printf("%d是闰年\n", year);
}
else {
printf("%d不是闰年\n", year);
}
return 0;
}
我们再来看下面一个题目,大家先看看结果应该是什么
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
i = a++ && ++b && d++;
//i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
//程序输出的结果是什么?
我们看到变量i的值由一串逻辑与操作符复合而成,所以我们要判断a,b,c的值来判断真假,但是我们从左向右计算时,a++的值为0,先使用为0,所以不管后边的数是什么都没有影响,i的值都为0,所以后边的数计算没有了意义,这在C语言中被叫做短路,当我们后边的计算结果对前边的计算结果不产生影响时,我们就不用去计算后边的表达式。
同理在表达式2中,前边的表达式都为真,在逻辑或中,有真就为真,所以d的值就不用计算了。
通过代码验证我们的结果也是正确的。
五、条件操作符
exp1 ? exp2 : exp3
条件操作符,也被称作三目表达式,有三个语句复合而成,当语句1成立时,执行语句2,反之执行语句3。
我们要找出两个数中最大的数时,我们就可以使用条件操作符。
int main() {
int a = 3;
int b = 5;
int max=a > b ? a : b;
printf("%d", max);
return 0;
}
六、逗号表达式
exp1 , exp2 , exp3 , …expN
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?
我们从左向右依次执行,a=12,b=13,故c=b=13。
总结
今天讲解了操作符的第二部分,希望大家能通过操作符来简化代码,以及在使用操作符的过程中注意到一些细节,本文中肯定有很多不足,希望能和大家一起进步。