(1)算术操作符
+ - * / %
除了%操作符外,其他算术操作符可以作用于整形和浮点数;
对于/操作符,如果两个操作数都为整数,执行整数除法。操作数只要有浮点数,执行浮点数除法;
%操作符的两个操作数必须是整数,返回的是整除后的余数。
(2)移位操作符
<<左移操作数
>>右移操作数
a.左移操作符
移位规则:向左移一位,右边补0;
int num = 7;
num << 1;
00000000 00000000 00000000 000000111(num的二进制)
00000000 00000000 00000000 000001110(num左移一位的结果)
b.右移操作符
移位规则:
逻辑移位:左边用0填充,右边丢弃。
算术移位:左边用该原值的符号位填充,右边丢弃。
int num = -1;
num >> 1;
11111111 11111111 11111111 11111111(num的二进制)
01111111 11111111 11111111 11111111(num逻辑移位的结果)
11111111 11111111 11111111 11111111(num算术移位的结果)
注意:对于移位操作符,不要移动负数位。
int num = 10;
num >> -1; //error
(3)位操作符
& 按位与
| 按位或
^ 按位异或
他们的操作数必须是整数。
#include<stdio.h>
#include<stdlib.h>
int main()
{
int num1 = 1;
int num2 = 2;
printf("num1 & num2 = %d\n", num1 & num2);
printf("num1 | num2 = %d\n", num1 | num2);
printf("num1 ^ num2 = %d\n", num1 ^ num2);
system("pause");
return 0;
}
//num1 & num2 = 0
//num1 | num2 = 3
//num1 ^ num2 = 3
求平均数
average=(m&n)+((m^n)>>1);
//相同的加,不同的加
(4)赋值操作符
int i = 122;
i = 23;
int x = i = i+11;
复合赋值操作符
+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
(5)单目操作符
! //逻辑反操作符
- //负值
+ //正值
& //取地址
sizeof //操作数的类型长度
~ //对一个数的二进制数进行按位取反
—- //前置、后置—
++ //前置、后置++
* //间接访问操作符(解引用操作符)
(类型) //强制类型转换
a.sizeof用法
#include <stdio.h>
#include<stdlib.h>
int main()
{
int a = -10;
int *p = NULL;
printf("%d\n", !2);
printf("%d\n", !0);
a = -a;
p = &a;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof a);//说明sizeof不是函数
printf("%d\n", sizeof int);//出错。加类型必须有括号
system("pause");
return 0;
}
//输出:
//0
//1
//4
//4
//4
#include<stdio.h>
int main()
{
int a = 20;
short b = 3;
printf("%d\n", sizeof(b = a + 1));
printf("%d\n", b);
system("pause");
return 0;
}
//输出:2 3
//放在sizeof内部中的表达式不参与运算
#include <stdio.h>
#include<stdlib.h>
void test1(int arr[])
{
printf("%d\n",sizeof(arr));
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));
}
int main()
{
int arr[10] = { 0 };
char ch[10] = { 0 };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(ch));
test1(arr); //传的是数组首元素地址,即一个指针,大小为4字节
test2(ch);//传过去的是指针
system("pause");
return 0;
}
输出:40 10 4 4
b.~的应用
将15的二进制码倒数第三位取反:
00000000 00000000 00000000 00001111(反码)
11111111 11111111 11111111 11111011(&这个数字b得到所求结果)
00000000 00000000 00000000 00000100(该数字按位取反得到数字b)(该数字表达为1<<2)
c. 前置++(—)与后置++(—)的区别
#include<stdio.h>
int main()
{
int a = 1;
int b = a++;
printf("%d\n", b);//1
printf("%d\n", a);//2
return 0;
}
后置++先使用后作用表达式。
#include <stdio.h>
#include<stdlib.h>
int main()
{
int a = 3;
int b = (++a) + (++a) + (++a); //这种表达式不对。
printf("%d\n", b);
system("pause");
return 0;
}
//在VS2013中输出:18
d.间接访问操作符
#include<stdio.h>
int main()
{
int num = 10;
int *p = #
printf("%d\n", *p);
return 0;
}
//输出:10
(6)关系操作符
>
>=
<
<=
!=
==
(7)逻辑操作符
&&逻辑与
||逻辑或
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i = 0, j = 0, a = 0, b = 2, c = 3, d = 4;
i = a++&&++b&&d++; //1 2 3 4
//j = a++||++b||d++; //1 3 3 4
printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
system("pause");
return 0;
}
(8)条件操作符
表达式1?表达式2:表达式3
(9)逗号表达式
表达式1,表达式2,表达式3,…,表达式n
逗号表达式就是用逗号隔开的多个表达式。逗号表达式从左往右依次执行,整个表达式的结果是最后一个表达式的结果。
(10)下标引用操作符[ ]
操作数:一个数组名+一个索引值
#include<stdio.h>
#include<stdlib.h>
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
printf("%p\n", &arr[4]);
printf("%p\n", arr + 4);
printf("%d\n", *(arr+4));
printf("%d\n", *(4 + arr));
printf("%d\n", arr[4]);
printf("%d\n", 4[arr]);
system("pause");
return 0;
}
//输出:
//012FFD0C
//012FFD0C
//5
//5
//5
//5
(11)函数调用操作符
函数调用操作符,接受一个或多个操作数,第一个操作数是函数名(地址),剩余的是传给函数的参数。
(12)结构成员访问操作符
.结构体.成员名
->结构体指针->成员名
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Stu
{
char name[20];
int age;
char sex[5];
};
int main()
{
struct Stu s;
struct Stu *p = &s;
strcpy(s.name, "刘明");//将“刘明”放到name空间里
s.age = 19;
strcpy(s.sex, "男");
strcpy((*p).name, "小强");
(*p).age = 20;
strcpy((*p).sex, "男");
strcpy(p->name, "晓花");
p->age = 20;
strcpy(p->sex, "女");
system("pause");
return 0;
}
(13)表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性决定。
a.整形提升
C的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为“整型提升”。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char a = 2;
char b = 127;
char c = a + b;
printf("%d\n", c);
system("pause");
return 0;
}
//输出:129
//a:00000010
//b:01111111
//整型提升:
//00000000 00000000 00000000 00000010—--a
//00000000 00000000 00000000 01111111—--b
//00000000 00000000 00000000 10000001---a+b
//10000001——-c(c的类型为char型,带符号位)
//11111111 11111111 11111111 10000001——c(高位补符号位)
//数据以补码方式存储,c为-127.
b.算术转换
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则草走就无法进行。
寻常算术转换:
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上米娜列表中排名较低,那么首先要转换成另外一个操作数的类型后执行运算。
c.操作符的属性
两个相邻的操作符,先执行优先级高的。若优先级相同,则取决于他们的结合性。
操作符优先级:
选自《C和指针》
#include<stdio.h>
int main()
{
int i = 0;
int tmp = (++i)+(++i)+(++i);
printf("%d\n", tmp);
return 0;
}
//输出12或10,没有唯一的计算路径