操作符详解
分类
- 算数操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用,函数调用和结构成员
算数操作符
功能
/ 除
-
/除,求得的是商
-
整数
#include <stdio.h> #include<string.h> int main() { int a = 5 / 2; //商2余1 printf("a = %d\n", a); return 0; } //输出: 2
-
小数
#include <stdio.h> #include<string.h> int main() { double a = 5 / 2.0; printf("a = %lf\n", a); return 0; } //输出:a = 2.500000
要想输出是小数,两端必须有一个是小数
% 取模
- %取模,求得的是余数
注意事项
- 除了%操作符外,其他的几个操作符可以作用于整数和浮点数
- 两数都为整数就执行整数除法,只要有浮点数就是浮点数除法
- %操作符的两个操作数必须为整数,返回的是整除之后的余数
移位操作符
右移
算数右移
右边丢弃,左边补原符号位
#include <stdio.h>
#include<string.h>
int main()
{
int a = 16;
//>> -- 右移操作符
//移动的是二进制位
int b = a >> 2;
printf("%d\n", b);
return 0;
}
//输出:4
#include <stdio.h>
#include<string.h>
int main()
{
int a = -1;
//正数的二进制表示有:原码,反码,补码
//存储到内存的是补码
// 100000000000000000000000000000001 - 原码
// 111111111111111111111111111111110 - 反码
// 111111111111111111111111111111111 - 补码
int b = a >> 2;
printf("%d\n", b);
return 0;
}
//输出:-1
逻辑右移
右边丢弃,左边补0
左移
- 左边丢弃,右边补0
#include <stdio.h>
#include<string.h>
int main()
{
int a = 5;
//正数的二进制表示有:原码,反码,补码
//存储到内存的是补码
// 100000000000000000000000000000001 - 原码
// 111111111111111111111111111111110 - 反码
// 111111111111111111111111111111111 - 补码
int b = a << 1;
printf("%d\n", b);
return 0;
}
//输出:10
- 左移相当于x2
注意
- 对于移位操作符,不要移动负数位,这个是标准未定义的
num >> -1; //error
- 只能作用于整数
位操作符
类型
- & 按位与
- | 按位或
- ^ 按位异或
按位与
#include <stdio.h>
#include<string.h>
int main()
{
// - 按2进制位与
int a = 3; //011
int b = 5; //101
int c = a & b;
printf("%d\n", c);
return 0;
}
//有一个0就是0,都是1才为1
//输出1
按位或
- 与上相反,输出7
按位异或
- 对应二进制位相同为0,相异为1
练习
-
通过异或实现两个数值的交换
#include <stdio.h> #include<string.h> int main() { // - 按2进制位与 int a = 3; int b = 5; printf("before : a=%d b =%d\n",a,b); a = a ^ b; b = a ^ b; a = a ^ b; printf("after : a=%d b =%d\n", a, b); return 0; }
-
求一个整数存储在内存中的二进制中的1的个数
#include <stdio.h> #include<string.h> int main() { int num = 10; int count =0; scanf("%d", &num); //统计num的补码中有几个1 while (num) { if (num % 2 == 1) count++; num = num / 2; } printf("%d\n", count); return 0; } //问题:算负数就出现问题
针对上述负数出现问题,换一种算法
#include <stdio.h> #include<string.h> int main() { int num = 0; int count = 0; scanf("%d", &num); //-1 int i = 0; for (i = 0; i < 32; i++) { if (1 == ((num >> i) & 1)) count++; } printf("%d\n", count); } //输入:-1,输出:32 //用到了按位与,移位操作符
赋值操作符
复合赋值符
a = a+2;
a += 2;
a = a >> 1;
a >> =1;
单目操作符
类型
-
!逻辑反操作,真变假,假变真
#include <stdio.h> #include<string.h> int main() { int a = 0; if (!a) //a为假打印呵呵 { printf("呵呵\n"); } }
-
- 负值
-
+ 正值
-
& 取地址
-
sizeof操作数的类型长度(以字节为单位)
#include <stdio.h> #include<string.h> int main() { int a = 10; char c = 'r'; char* p = &c; int arr[10] = { 0 }; //sizeof计算的是变量所占内存空间的大小,包含数组,-单位是字节 printf("%d\n", sizeof(a)); //4 printf("%d\n", sizeof(c)); //1 printf("%d\n", sizeof(p)); //4或8 printf("%d\n", sizeof(arr)); //40 } //数组也是有类型的,去掉名字就是类型
小练习:判断输出的是几
#include <stdio.h>
#include<string.h>
int main()
{
short s = 0;
int a = 10;
printf("%d\n", sizeof(s = a + 5));
printf("%d\n",s);
}
//输出:2,0
//sizeof里面的值是不参与运算的,所以s的值是0
-
~ 对一个数的二进制按位取反
#include <stdio.h> #include<string.h> int main() { int a = 0; //~按(2进制)位取反 //00000000000000000000000000000000 //11111111111111111111111111111111 按位取反后的结果,也是补码,我们打印的是原码 //11111111111111111111111111111110 -反码 //10000000000000000000000000000001 -原码 //-1 printf("%d\n", ~a); return 0; }
-
– 前置,后置–
-
前置++,先++,再使用
#include <stdio.h> #include<string.h> int main() { int a = 10; printf("%d\n", ++a); return 0; } //输出:11
-
后置++,先使用,再++
#include <stdio.h> #include<string.h> int main() { int a = 10; printf("%d\n", a++); printf("%d\n", a); return 0; } //输出:10,11
-
-
间接访问操作符(解引用操作符)
int main() { int a = 0; int* p = &a; //取地址操作符 *p; //解引用操作符,通过p里面存的值,找到它所指向的对象,*p就是它指向的对象a }
-
(类型) 强制类型转换
#include <stdio.h> #include<string.h> int main() { int a = (int)3.14; return 0; }
关系操作符
- !=用于测试“不相等“
- == 用于测试相等
逻辑操作符
-
&&逻辑与
int main() { int a = 0; int b = 5; int c = a&&b; printf("%d\n",c); return 0; } //输出:1
-
||逻辑或
i = a++||++b||d++ //只要第一个为真了,后面就不用算了
这种行为是由 C 语言的语法规定和计算机底层实现机制决定的。当表达式的第一个操作数求值为真值时,计算机不需要再对后面的操作数进行求值,因为已经可以确定整个表达式的值了。这种行为可以减少计算机的计算量,提高程序的运行效率。
条件操作符
exp?exp2:exp3
练习
if (a>5)
b=3;
else
b=-3;
b = (a>5?3:-3);
return 0;
逗号表达式
定义
逗号表达式,就是用逗号隔开的多个表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果
"get_val" 函数的定义是一个计算机程序中的一段代码,用于获取一个特定的值或变量
get_val" 函数需要传递一个参数来告诉它需要获取什么值。然后,函数会在程序中找到并返回该值
形式
exp1,exp2,exp3,...expN
下标引用,函数调用,结构成员
[]下标引用操作符
操作数:一个数组名+一个索引值
int arr[10]; //创建数组
arr[9] = 10; //使用下标引用操作符
[]两个操作数是arr和9,一个是数组名,一个是下标值
()函数调用操作符
函数调用操作符接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数是传递给函数的参数
结构成员
-
访问一个结构的成员
. 结构体.成员名 -> 结构体指针->成员名
#include <stdio.h>
#include<string.h>
//创建一个结构体类型 - struct Stu
struct Stu
{
//成员变量
char name[20];
int age;
char id[20];
};
int main()
{
int a = 10;
struct Stu s1 = { "张三",20,"2019010305" };
printf("%s\n", s1.name);
printf("%d\n", s1.age);
printf("%s\n", s1.id);
//结构体变量.成员名
return 0;
}
//main函数里面也可以
int main()
{
int a = 10;
//使用struct Stu这个类型创建了一个学生对象s1
struct Stu s1 = { "张三",20,"2019010305" };
struct Stu* ps = &s1;
printf("%s\n", ps->name);
//结构体指针->成员名
return 0;
}
整型提升
隐式类型转换
C的整型算数运算总是至少以缺省整型类型的精度来进行的
为获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升
提升方法
整型提升是按照变量的数据类型的符号位来提升的
例子
#include <stdio.h>
#include<string.h>
int main()
{
char a = 1;
short b = 2;
int c = 3;
if (a == 1)
printf("a");
if (b == 2)
printf("b");
if (c == 3)
printf("c");
return 0;
}
//输出:只打印c的值