传送门:C语言-第三章-加餐:static 关键字与函数递归、链式访问
目录
操作符之前我们其实已经见过并使用过了,比如+、-、*、=、>、<等,下面我们将详细介绍C语言中所有的常见操作符。
第一节:算数操作符
1-1.基本认识
+:加号,获得加号两边的数字之和;
-:减号,获得减号两边的数字之差;
*:乘号,获得乘号两边的数字之积;
/:除号,获得除号两边的数字之商;
%:取模符号,获得取模符号两边的数字相除的余数,所以两边的数字必须是整数
1-2.运算中的隐式类型转换
在进行除法运算时,相同类型的数字运算的得到的是相同类型的结果,下列两个int类型的变量运算:
#include <stdio.h> int main() { int a = 5; int b = 2; printf("%d\n", a / b); return 0; }
结果并不是2.5,因为 int 类型存储整数,小数部分就被直接丢弃了
但是如果是两个 float 类型进行运算,小数部分就会被保留:
#include <stdio.h> int main() { float a = 5; float b = 2; printf("%f\n", a / b); return 0; }
那么如果是一个 int 类型和一个 float 类型运算呢?
#include <stdio.h> int main() { float a = 5; int b = 2; printf("%f\n", a / b); return 0; }
这是因为不同类型的变量运算时,int 变量暂时转换为 float 类型,即5 -> 5.000000。
这种数据类型暂时改变的方式叫做 隐式类型转换
在运算中,不同类型相遇时转换的类型遵循下列优先级:
char < short < int < long < float < double
"<"左边的类型会自动去适应"<"右边的类型
第二节:位移操作符
位移操作符只能操作整型家族的成员:char、short、int 、long、long long
<<:获得整型的二进制位向左移动的结果
>>:获得整型的二进制位向右移动的结果
什么叫做整型的二进制位呢,这和它们的存储方式有关。
2-1.整型的存储
整型是以二进制的方式存储的,比如我们定义了一个整型:
int a;
计算机就会为它在内存中创建一块4字节的空间:
第一章我们知道1字节等于8比特,所以这块空间的大小就是32比特,接下来我们只看这块空间,当对 a 进行赋值时:
int a;
a = 2;
计算机会把 2 转换成二进制然后存储在这块空间中:
其他整型的存储方式也类似,只是二进制的位数不同。
所以位移操作符就是在操作二进制,比如:
#include <stdio.h>
int main()
{
int a = 2;
a = a << 1; // 二进制位向左移动1
printf("a = %d\n",a);
return 0;
}
结果的二进制位对应的十进制位的值就是4:
位移操作符用得并不多,但是要注意的时它本身并不能改变变量的值,需要使用位移操作符后再赋值,就像上面的代码一样。
第三节:位操作符
位操作符和位移操作符都是对整型二进制进行操作,但是它的用途更广泛。
&:按位与,按照两个整数对应的比特位,如果这个比特位都是1,那么获得的新数字的这个比特位就是1,否则就是0
|:按位或,按照两个整数对应的比特位,如果这个比特位至少有一个1,那么获得的新数字的这个比特位就是1,否则就是0
^:按位异或,按照两个整数对应的比特位,如果这个比特位相同(都是1或者都是0),那么获得的新数字的这个比特位就是0,否则就是1
光看文字可能不好理解,下面直接画图理解:
一个比特位一个比特位的对应起来看,| 与 ^ 的过程也相同,只是取0取1的逻辑不同,这里就不再画图了。
第四节:赋值操作符
它们的作用是给变量赋值,而我们之前使用的 = ,就属于赋值操作符。它们与上面的其他操作符相关性很强,我只列举所有赋值操作符并举少量例子即可。
赋值操作符:=、+=、-=、*=、/=、%=、>>=、<<=、&=、^=、|=
int a = 10;
a += 5; // 等价于 a = a + 5;
a /= 5; // 等价于 a = a / 5;
a <<= 1;// 等价于 a = a << 1;
a ^= 5; // 等价于 a = a ^ 5;
用法相似,这里不多赘述。
第五节:单目操作符
单目就是一个操作数的意思,操作数就是使用这个操作符需要的数据,比如 + 就需要两个操作数。
!:逻辑反,让真变成假,假变成真
#include <stdio.h> int main() { int a = 1; if (!(a > 0)) // 逻辑反 { printf("执行 if\n"); } else { printf("执行 else\n"); } return 0; }
a > 0 为真,那么 !(a > 0) 就是假
+、-:正负号,正号一般被忽略,数字前加负号表示负数
int a; a = +1; // 等价于 a = 1; a = -1; // 整型和浮点型都可以保存负数
&:取地址,获得一个变量的地址,以后在指针部分会讲到
sizeof:类型长度,单位是字节
#include <stdio.h> int main() { char a = 'A'; short b = 1; int c = 1; long d = 1; long long g = 1; float e = 1.0; double f = 1.0; printf("char的大小: %d\n", sizeof(a)); printf("short的大小: %d\n", sizeof(b)); printf("int的大小: %d\n", sizeof(c)); printf("long的大小: %d\n", sizeof(d)); printf("longlong的大小:%d\n", sizeof(g)); printf("float的大小: %d\n", sizeof(e)); printf("double的大小: %d\n", sizeof f); // sizeof f 等价于 sizeof(f) // 注意:获得的是这个变量的类型的大小,而不是变量的值 return 0; }
~ :二进制按位取反,比特位为1就取0,为0就取1
++:数据自增1,配合赋值操作符或 return 时需要区分前置++和后置++
前置++:先自增1再获得其值
#include <stdio.h> int fun(int x) { return ++x; } int main() { int a = 1; printf("return: %d\n", fun(a)); int b = ++a; printf("b: %d\n",b); printf("自增之后的a:%d\n",a); return 0; }
后置++:先获得其值再自增1
#include <stdio.h> int fun(int x) { return x++; } int main() { int a = 1; printf("return: %d\n", fun(a)); int b = a++; printf("b: %d\n",b); printf("自增之后的a: %d\n", a); return 0; }
--:数据自减1, 配合赋值操作符或 return 时需要区分前置--和后置--
与++使用方法类似,只是把自增1变成了自减1,这里不再赘述
*:解引用,根据地址找到变量的空间,以后在指针部分会讲到
(类型):显式类型转换,可以让某个变量或者数据的类型暂时转换成括号中的类型
int a = 10; float f = (float)a // 把a暂时转换成 float 类型赋值给f,a 只在这一行会被计算机认为是 float类型
第六节:关系操作符
关系操作符常用在条件表达式里面判断两个数据的关系,大部分我们在第二章就已经见过了。
==:相等,两边的值相等返回1,否则返回0
!=:不相等,两边的值不相等返回1,否则返回0
>:大于,左边比右边大返回1,否则返回0
>=:大于等于,左边不小于右边返回1,否则返回0
<:小于,右边比左边大返回1,否则返回0
<=:小于等于,右边不小于左边返回1,否则返回0
注意:上述四个符号比较大小的符号不能直接连用来表示一个数在两个数之间:
#include <stdio.h> int main() { int a = 0; if ( -1< a < 1) { printf("a在-1到1之间\n"); } else { printf("a不在-1到1之间\n"); } return 0; }
看起来它应该打印“a在-1到1之间”,实际上的执行结果为:
这是因为-1 < a < 1会先比较-1 < a,它为真返回1,此时就变成了:1 < 1,为假,就执行了 else 里的语句
那么我们要怎么实现判断a在-1到1之间的逻辑呢?把第七节讲了就知道了。
第七节:逻辑操作符
逻辑操作符是C语言(包括C++)中十分中的的操作符,它可以综合多个条件表达式的真假情况,然后返回1或者0。
&&:且,左右两边的条件表达式都为真才会返回1,否则返回0
//例子1 #include <stdio.h> int main() { int a = 10; if(a > 9 && a > 0) // 两个条件表达式都为真,整个式子才为真 { printf("a: %d\n",a); } return 0; }
------------------------------------------------------------
//例子2 #include <stdio.h> int main() { int a = 10; if (a > 11 && a == 10) // 第一个条件表达式为假,整个式子就为假 { printf("a: %d\n", a); } return 0; }
||:或,左右两边的条件表达式至少有一个真就会返回1,否则返回0
//例子3 #include <stdio.h> int main() { int a = 10; if (a > 11 || a == 10) // 第二个条件表达式为真,整个式子就为真 { printf("a: %d\n", a); } return 0; }
------------------------------------------------------------
//例子4 #include <stdio.h> int main() { int a = 10; if (a > 11 || a == 1) // 两个条件表达式都为假,整个式子才为假 { printf("a: %d\n", a); } return 0; }
我们现在就可以使用逻辑操作符完成第六节的遗留问题了:
实现判断a在-1到1之间的逻辑
#include <stdio.h>
int main()
{
int a = 0;
if (-1 < a && a < 1)
{
printf("a在-1到1之间\n");
}
else
{
printf("a不在-1到1之间\n");
}
return 0;
}
不但如此,逻辑操作符还允许连续使用:
条件表达式1 || 条件表达式2 && 条件表达式3
下面我们用一个例子来感悟这种用法。
7-1.打印闰年
闰年是公历中有366天的年份,年份能被4整除但是不能被100整除的年份是闰年,年份能被400整除的也是闰年。
请写一份代码打印0到2024年的所有闰年。
首先我们可以用for循环获得0到2024的所有年份:
#include <stdio.h> int main() { for (int year = 0; year < 2025; year++) // 获得所有年份 { } return 0; }
然后对些年份作筛选,即使用分支语句,先来看看有哪些条件:
1、可以被4整除 但是 不能被100整除
// 可以被4整除 year%4 == 0; // 不能被100整除 year%100 != 0; // 使用 && 组合上面两个条件表达式 year%4 == 0 && year%100 != 0; // %表示取余数,没有余数说明能被整除
2、可以被400整除
// 可以被400整除 year%400 == 0; // %表示取余数,没有余数说明能被整除
符合上述1、2其中一个条件就是闰年,所以条件1、2用 || 组合起来
(year%4 == 0 && year%100!=0) || (year%400 == 0); // %表示取余数,没有余数说明能被整除
在源代码中加入上述条件表达式:
#include <stdio.h> int main() { printf("闰年有:\n"); for (int year = 0; year < 2025; year++) { if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { printf("%-4d ",year); } } return 0; }
执行结果为:
第八节:三目操作符
又叫条件表达式,需要三个操作数,可以代替简单的 if else 语句。
条件表达式?式子1:式子2:如果条件表达式为真就执行式子1,为假就执行式子2
#include <stdio.h> int main() { int a = 1; a > 0 ? printf("真\n"): printf("假\n"); /* 等价于: if(a>0) { printf("真\n"); } else { printf("假\n"); } */ return 0; }
第九节:逗号表达式
用处少,了解即可。
(式子1,式子2......,式子n):从左向右一次执行式子,但是会返回最后一个式子的结果
第十节:操作符的优先级
就像数学中的加减乘除的运算顺序——先加减后乘除一样,操作符也有优先级的区分:
1、有括号先算括号里面的
2、然后再执行优先级高的操作符
运算符优先级如下表:
在同时使用多个运算符时需要注意它们的优先级,如果不确定可以包(),保证运算符的执行顺序符合预期。
运算符还有 下标[] 和 成员选择./-> 没有讲,将在下一章:数组与结构体 中呈现
下期预告:
下一章是第五章,主要内容如下:
1、数组、字符串的定义及存储
2、结构体的定义、使用和大小计算