算术操作符
+ | - | * | / | % |
除法操作符(/),有浮点数除法与整数除法之分。浮点数除法,其结果是浮点数,除数与被除数中至少有一个为浮点数。而对于整数除法而言,其结果是整数,除数与被除数两个都必须是整数。
printf("5/2=%d\n", 5 / 2);
printf("5/2.0=%f\n", 5 / 2.0);
printf("5.0/2=%f\n", 5.0 / 2);
printf("5.0/2.0=%f\n", 5.0 / 2.0);
在5除以2的整数除法中,小数部分被丢弃,这一过程被称为截断(truncation)。而在后两个整数与浮点数混合的除法中,由于计算机是不能用整数除以浮点数或浮点数除以整数的,编译器会把这两个运算对象换成相同类型来计算。因此在进行除法时,整数会转换成浮点数来计算。
示例:
计算 的和
#include <stdio.h>
int main() {
int i;
double sum = 0.0;
int flag = 1;
for (i = 1; i <= 100; i++) {
sum += flag * 1.0 / i;//使用浮点数除法
flag = -flag;
}
printf("%lf", sum);
return 0;
}
在求和那里,使用了浮点数除法。
求模操作符(%,modulus operator),只能用于整数,不能用于浮点数,给出其左侧整数除以右侧整数的余数(remainder)。
示例
将输入数转化成6进制,不要只是打印
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int n = 0;
int arr[40] = {0};
int i = 0;
scanf("%d", &n);
while(n)
{
arr[i++] = n%6;
n/=6;
}
for(i--; i>=0; i--)
{
printf("%d", arr[i]);
}
return 0;
}
输入 77
输出 205
单目操作符
++ | 递增操作符(increment operator),前置或后置 |
-- | 递减操作符(decrement operator),前置或后置 |
sizeof | 操作数的类型长度(以字节为单位) |
(类型) | 强制类型转换 |
& | 取地址 |
* | 间接访问操作符(解引用操作符) |
递增操作符(++)
int a=5;
int b=a++;//++后置,等同于先b=a,再a=a+1
int c=++a;//++前置,等同于先a=a+1,再c=a
printf("a=%d,b=%d,c=%d\n",a,b,c);
输出:a=7,b=5, c=7
递减操作符(--)
--前置,--后置与递增操作符同,下面多举几个例子感受一下。
int x=103;
while(x-->98)//--后置,先x与98作比较,之后再x=x-1
printf("%d\n",x);
printf("%d\n",x);
输出:
102
101
100
99
98
97
由于while循环条件表达式将会比循环体多执行一次,在x为98时,再一次比较x-->98,条件为假,x--,x为97,跳出循环。
递增操作符和递减操作符有很高的优先级,只有圆括号的优先级比他们高。
int x=10;
int y=17;
printf("%d,y=%d\n",x*y++,y);//等价于x*(y++)
printf("%d,y=%d\n",x*++y,y);//等价于x*(++y)
sizeof操作符
可以利用sizeof操作符求得整型数组的长度。
int arr[] = { 1,53,32,3,4,2,42,12,8,76,56 };
int sz = sizeof(arr) / sizeof(arr[0]);//整个数组的大小,除以一个数组元素的大小,结果等于个数
printf("%d\n",sz);
输出:11
但是对于字符串而言,求字符多少,还是利用strlen这个库函数更好一点(添加头文件string.h)。因为每个字符串的结尾都有一个隐藏的\0,也是有空间大小的。如果利用sizeof上面的计算方法,字符个数可能会多1个。而利用strlen,它读取到\0结束,不会把\0计算入内。
char arr[]={"sahdsdjjtjskskas"};
int sz=sizeof(arr)/sizeof(arr[0]);
printf("%d %d\n",sz,strlen(arr));
输出:17 16
此外,sizeof的返回类型为无符号整型。
#include <stdio.h>
int i;
int main()
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
输出:>
在全局变量中,如果没有初始化,系统默认为0。当i--之后,i为-1。sizeof的返回值为无符号整型,与有符号整型作比较,编译器会自动将i转化成无符号整型,而-1对应的无符号整型是一个很大的数字,超过4或8,因此才会输出>。
关系操作符
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
!= | 不等于 |
== | 等于 |
关系操作符比较简单,需要注意的是,在编程过程中,可能会不小心把==写成=,从而造成错误。
赋值操作符
在c语言中,=并不意味着“相等”,而是一个赋值运算符,赋值行为从右往左,=的左侧一定是一个变量名。c语言不允许给常量赋值,因此下面的代码就会报错。
int bmw;
2002=bmw;//=左侧是个常量,这样会报错。
但写成2002==bmw却是可行的,与bmw==2002是一样的,都是在检查bmw的值是否为5。
因此建议在构建比较是否相等的表达式时,把常量放在左侧,这样一旦写成=,编译器就会报错。
示例:
下面的代码结果如何??
#include<stdio.h>
int main(){
int i=0;
for(i=0;i<10;i++){
if(i=6)
printf("%d\n",i);
}
return 0;
}
死循环打印6。得把i=6改成i==6或者6==i。
复合赋值操作符
+= |
-= |
*= |
/= |
%= |
>>= |
<<= |
&= |
|= |
^= |
下面给一些使用的案例:
int scores=10;
scores+=60;//等价于scores=scores+60;
int x=2;
int y=3;
x*=35*y+12;//等价于x=x*(35*y+12)
上述复合赋值操作符与=的优先级相同,即比+或*优先级低。
并不是一定要用这些操作符,只是它们让代码更紧凑,而且与一般新式相比较,复合赋值操作符生成的机器代码更高效。
逻辑操作符
&& | 逻辑与 |
|| | 逻辑或 |
逻辑表达式的求值顺序都是从左往右的,&&操作符的优先级比||操作符的高,但两者的优先级都比关系操作符低,比赋值操作符高。表达式a>b&&b>c||b>d相当于((a>b)&&(b>c))||b>d,即b要么介于a,c之间,要么b大于d。
示例:
1.打印1000~2000年之间的闰年
#include<stdio.h>
int main(){
int year = 0;
for(year>=1000;year<=2000;year++){
if(year%4==0&&year%100!=0||year%400==0)
printf("%d",year);
}
return 0;
}
2.下面的代码输出结果是什么?
#include<stdio.h>
int main()
{
int i=0,a=0,b=2,c=3,d=4;
i=a++&&++b&&d++;
printf("a=%d,b=%d,c=%d,d=%d,i=%d\n",a,b,c,d,i);
return 0;
}
输出:
a=1,b=2,c=3,d=4,i=0
对于&&来说,从左到右有一项为假,结果就为假,不会继续往后执行。
#include<stdio.h>
int main()
{
int i=0,a=0,b=2,c=3,d=4;
i=a++||++b||d++;
printf("a=%d,b=%d,c=%d,d=%d,i=%d\n",a,b,c,d,i);
return 0;
}
输出:
a=1,b=3,c=3,d=4,i=1
对于||来说,从左到右有一项为真,结果即为真,后面的也不再执行。
#include<stdio.h>
int main()
{
int i=0,a=1,b=2,c=3,d=4;
i=a++||++b||d++;
printf("a=%d,b=%d,c=%d,d=%d,i=%d\n",a,b,c,d,i);
return 0;
}
输出:
a=2,b=2,c=3,d=4,i=1
逗号表达式
逗号表达式有两个性质,一是保证了被分隔的表达式从左到右求值;二是整个逗号表达式的值是最右侧表达式的值。
条件操作符
在c语言中,条件表达式(conditional expression)是作为if else 语句的另一种表达方式。它的通用形式为:
如果exp1的值为真,那么整个条件表达式的值就与exp2的值相同,如果为假,那么整个条件表达式的值就与exp3的值相同。
示例:
(a>b)?a:b,将得到a与b之间的最大值。
带3个运算对象的操作符被称为三元操作符,条件操作符是c语言中唯一的三元操作符。
此外,条件操作符还可以进行赋值运算,请看下面的例子。
#include<stdio.h>
int main(){
int a = 3;
int b = 0;
b = a > b ? 3 : -3;
printf("b=%d\n",b);
return 0;
}
输出:
b=3
移位操作符
<< | 左移操作符 |
>> | 右移操作符 |
需要注意的是,移位操作符的操作数只能是整数。
左移操作符
移位规则:左边抛弃,右边补0
int x=23;
printf("%d\n",x<<1);
printf("%d\n",x);
输出 46 23
可见移位操作符不会改变原本x的值。
右移操作符
右移规则分为两种:
1.逻辑移位——左边用0填充,右边丢弃
2.算术移位——左边用该值的原符号位填充,右边丢弃
int x=-1;
printf("%d\n",x>>1);
printf("%d\n",x);
输出 -1 -1
对于移位操作符,最好不要移动负数位,这是未经定义的。
位操作符
& | 按位与 |
| | 按位或 |
^ | 异或 |
它们的操作数也必须是整数。
按位与(&),二进制当中,两个相应位同时为1才是1。
按位或(|),二进制中,两个相应位同时为0才是0。
异或(^),二进制中,两个相应位相同为0,不同为1。
示例
1.不创建临时变量,交换两个数
//异或^相同为0,相异为1,因此3^3=0,即相同数异或的结果为0
//异或满足交换律
#include<stdio.h>
int main(){
int a=5;
int b=78;
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;
}
2.写一个函数,返回参数一个整数的二进制中1的个数
//方法一:
//每一个int类型的数据,对应的二进制一共有32个比特位,采用位运算,一位一位地与1按位与(&,相同为1)
int count_ont_bit(unsigned int n){
int count=0;
int i=0;
for(i=0;i<32;i++){
if(((n>>i)&1)==1)//由于关系操作符的优先级比按位操作符的要高,因此要将多写一个()
count++;
}
return count;
}
此方法中,不管该数二进制有多少个1,它都会进行32次循环。
//方法二
//采用相邻的两个数据进行按位与运算
int count_one_bit(unsigned int n)
{
int count = 0;
while(n){
n=n&(n-1);
count++;
}
return count;
}
此方法中,该数据n中对应的二进制中有几个1,就进行几次的循环,较方法一更高效。
3.写一个函数,比较输入的两个整数其二进制不同位的个数
int different_bit(int m, int n){
int temp = m ^ n;
int count = 0;
while(temp){
temp = temp & (temp-1);
count++;
}
}
例题
1. 下面代码的结果是:( )
#include <stdio.h>
int main()
{
int a, b, c;
a = 5;
c = ++a;
b = ++c, c++, ++a, a++;
b += a++ + c;
printf("a = %d b = %d c = %d\n:", a, b, c);
return 0;
}
输出:a=9 b=23 c=8
解析:对于 b = ++c, c++, ++a, a++; 这一语句,逗号表达式的优先级最低,这里先算b=++c, b得到的是++c后的结果,b是7。b=++c 和后边的构成逗号表达式,依次从左向右计算的。
对于b += a++ + c; 这一语句,复合赋值操作符的优先级最低,先算a++ +c 。