目录
操作符分类:
1、算术操作符
2、位操作符
3、赋值操作符
4、单目操作符
5、关系操作符
6、逻辑操作符
7、条件操作符
8、逗号操作符
9、下标引用、函数调用和结构成员
1、算术操作符
?+? ? ? ? -? ? ? ? *? ? ? ? /? ? ? ? %
? ? ? ?%? 是取模操作符,意思就是 求余数。
int ret = 10 % 3; //求10 % 3的余数,得出的余数是1
printf("%d\n", ret);
? ? ? 注意的是:% 操作符不能用于浮点数,只能作用于整数,如果作用于浮点数将会报错。
? ? ? 对于 /(除法)操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。什么意思呢?请看下面的代码
int ret = 10 / 3; // / 两边的操作都是整数,执行的就是整数除法,结果为3
printf("%d\n", ret);
???????如果 / 两边的操作数有一个数为浮点数的话,执行的是浮点数除法
double ret = 10 /3.0; // 得出的结果是 3.333333
printf("%lf\n", ret);
2、位操作符
<<? ? ? ? ? 左移操作符
>>? ? ? ? ? 右移操作符
注:移位操作符的操作数只能是整数,不能是浮点数。
讲之前先了解一下原码、反码、补码是什么? 一个正整数的原,反,补码都是一样的,负整数则不同,需要计算。
?为什么要讲这些呢,因为一个整数在内存中存储的是补码!!!
接下来回归主题:
? ? ? ? << ????????左移操作符规则:左边抛弃,右边补0
如果a是负数的呢?
?????????>>????????? 右移操作符可以分为:
????????????????????????1、算术右移? ? (右边丢弃,左边补原来的符号位数)
??????????????????????? 2、逻辑右移? ? (右边丢弃,左边不用考虑符号位数,直接用0补充)
????????到底是 算术右移还是 逻辑右移,取决于编译器
? ? ? ? 我们常见的编译器大多都是算术右移
算术右移:
int a= 5;
int b= a>> -2; //标准未定义的
对于移位运算符还需要注意的一点是:不要移动负位数,这是标准未定义的,什么意思呢,就是c语言并没有规定负移位数该怎么做,所以不能写成负数
?3、位操作符:
????????&? ? ? 按(二进制)位 与
? ? ? ? ?|? ? ? ?按(二进制)位 或
? ? ? ? ?^? ? ? ?按(二进制)位 异或??
& 按位与: 两个条件同时为真(1)的情况下,运算结果为真,说人话就是两个条件都是1才为1,否则为0。
?|? 按位或 :任意一个条件为真(1)的情况下,运算结果为1,就是只要有一个1则为1,否则为0。
?^ 按位异或 :两个条件中只有一个条件为真(1)的情况下,运算结果为真。也就是说,相异才为 真,相同则为假。
?这里有道关于异或的题目:不能创建临时变量(第三个变量),实现两个数的交换。
了解之前要先知道:两个相同的数进行异或的话为0; 0跟其他数进行异或都是这个数的本身。
#include<stdio.h>
int main()
{
int a = 5;
int b = 3;
printf("交换前:a=%d b=%d\n", a, b);
a = a ^ b;
b = a ^ b; //相当于 a^( b ^ b),所以b等于5
a = a ^ b; //相当于 a^ b,等于3
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
结果? :
?3.赋值操作符?
=
这个没什么好讲的,相信大家都会。
nt weight = 120;? // 体重 weight = 89;????????//? 不满意就重新赋值 double salary = 10000.0; salary = 20000.0;????????//使用赋值操作符赋值
赋值操作符可以连续使用,比如: int a = 10; int x = 0; int y = 20; a = x = y+1;????????//连续赋值 这样的代码看着感觉如何?是不是没那么容易一眼看懂了,这种写法是不推荐的。 换个写法,你看看: ?x = y+1; ?a = x; 这样的写法是不是更加易懂了。
?4.复合赋值符
+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
这可是懒人的福音了,怎么说呢?
int x= 10;
x= x + 10;
x+=10; // 可以写成这样,等价于x= x + 10;
//其他的运算符也是一样的操作
5.单目操作符
!? ? ????????? ????????? 逻辑反操作符
-? ? ? ? ????????????????? 负值
+? ? ? ? ? ? ? ? ? ? ? ???正值
&? ? ? ? ? ? ? ? ? ?? ?? 取地址
sizeof?????????????? ? 查询对象或类型的大小
~? ? ? ? ? ? ? ? ? ? ? ? 对一个数的二进制位 按位取反
--? ? ? ? ? ? ? ? ? ? ? ? 前置、后置减减
++? ? ? ? ? ? ? ? ? ? ? 前置、后置加加
*? ? ? ? ? ? ? ? ? ? ? ? ?间接访问操作符(解引用操作符)
(类型)? ? ? ? ? ? ? ? 强制类型转换
!? 逻辑反操作符是什么呢?下面代码演示:
int flag = 0;
//当flag为假的时候如何打印haha?
if (!flag) //只需用上逻辑反操作符 ! 就能打印了
{
printf("haha\n");
}
逻辑反操作符就是把 真变成假,假变成真。把flag变成真,不会是别的数字,只会是1。
sizeof? 是一个关键字,可以用来求一个变量或类型所占内存空间的大小(单位:字节)。
int a = 10;
printf("%d\n", sizeof(a)); //计算a所占内存空间的大小为4个字节
printf("%d\n", sizeof(int)); //计算int类型为4个字节
int arr[5] = { 1,2,3,4,5};
printf("%d\n", sizeof(arr)); // 数组名 arr 单独放在sizeof代表的是整个数组,
//因为arr数组是int型且里面有5个元素,
//int型大小是4个字节,所以总大小为20个字节
关于sizeof? ? 有些写法会比较怪
int a = 6;
printf("%d\n", sizeof a); //这种写法没有问题,以此证明sizeof不是库函数而是一个关键字,
//括号可以省略,如果sizeof是库函数的话括号是不能省略的
~ :按(内存中补码的2进制)位取反
int a=0;
printf("%d\n",~a);
// 0000 0000 0000 0000 0000 0000 0000 0000 -因为0是正数,原反补相同
// 1111 1111 1111 1111 1111 1111 1111 1111 - 把0的补码每一位进行取反
//又因为要打印出来,得把补码转换成原码
// 1111 1111 1111 1111 1111 1111 1111 1111 - 补码
// 1111 1111 1111 1111 1111 1111 1111 1110 - 反码
// 1000 0000 0000 0000 0000 0000 0000 0001 - 原码
// 打印出来的结果为 -1
--? ? ? ? ?前置、后置减减
++? ? ? ?前置、后置加加
int a=9;
int b= ++a; // 前置++ :先++,再使用,意思就是:a先++,然后再赋值给b
printf("a=%d b=%d\n",a,b); // a的结果为10 , b的结果也为10
//如果换种写法呢?
int a=9;
int b= a++; //后置++ :先使用,再++。意思就是:先把a赋值给b,然后a再++
printf("a=%d b=%d\n",a,b); // 因此结果就跟上面的不一样了。 a的结果为10,b则为9
相信大家遇到过这种题
这种写法其实是非常有问题的,不同 的编译器结果是不一样的。
vs2019的结果为:4,12。? ? ?????? gcc: 4,10。大家要避免写出这样的代码。
* 解引用操作符
int a=10;
int *p=&a;
*p=20; // p是指针变量存的是a的地址,*p 解引用操作符通过p存放的地址找到a,并重新给a赋值成20;
printf("%d\n",a); // 因此a最终的结果为20
?(类型)? ? ? ? ? ? ??强制类型转换
int a=3.14 // 3.14是double型,如果要把3.14强制放到int型的a里面的话会有警告。
//换种写法
int a= (int)3.14; 把3.14强制转换成int型
printf("%d\n",a); //a的结果为3。
6.关系操作符
> >= < <= != ????????用于测试“不相等” == ???????用于测试“相等”
这些关系运算符比较简单,没什么可讲的,但是我们要注意一些运算符使用时候的陷阱。
int a = 10;
// a如果等于10 的话打印 您好 ,不等于10的打印 再见
if (a == 10)
{
printf("您好\n");
}
else
{
printf("再见\n");
}
//有些人会把 == 误打成 = 如果写成这样,是把10赋值给a,a是真,就会直接打印成您好
if (a = 10)
{
printf("您好\n");
}
else
{
printf("再见\n");
}
7.逻辑操作符
&&? ? ? ? ? ? ? ? 逻辑与(可以理解成:并且、与的意思)
?||? ? ? ? ? ? ? ? ? 逻辑或(可以理解成:或 的意思)
这两个操作符是用于表示逻辑上的真假。到底是什么东西呢?
//如果要想表示输入的年龄 0到18 之间打印未成年,如何表示呢? 0 < age < 18 ?
int age = 0;
scanf("%d", &age);
if (0 < age < 18)
{
printf("未成年\n");
}
//这种写法是错误的,假设输入的年龄是23,0小于23,结果为真则 1,1小于18,就会打印出未成年了
//23岁了不应该是成年了吗?怎么打印出的结果会是未成年呢,所以这样的写法是错误的
?到底要该如何表示呢?这时候逻辑与操作符就派上用场了。
int age = 0;
scanf("%d", &age);
if (age> 0 && age <18) //可以这样理解:age > 0 并且 age <18 两个条件同时为真才会打印未成
{ //年,其中只要有一个条件不为真就不会执行该语句
printf("未成年\n");
}
那如果要检测输入的数值是不是1到7的范围呢?可以使用逻辑或操作符。
int num = 0;
scanf("%d", &num);
if (num < 0 || num > 7) //可以这样理解:num< 0 或者 num> 7,只要有一个条件为真就会执行语句
{ //假设输入的num是-1,num小于0,结果为真,就会打印出:不是1到7的范围
printf("不是1到7的范围\n"); // 要是输入的num是8,num>0了,是假,就会继续执行后面的判断语句,num>7,还是会打印出:不是1到7的范围
}
else
{ //要是输入的是1到7之间的数值,则会打印:是1到7的范围
printf("是1到7的范围\n");
}
如果还不明白的话,举个例子:如果要去约会,是不是得同时2个人进行才能算是约会,要是只有一个人能算约会吗? &&逻辑与操作符就是这个道理,缺一不可,都为真才可以。
那 || 逻辑或该怎么理解呢?有一天,你暗恋许久的女神突然跟你说:只要你考上了大学或者能多财多亿的话我就做你女朋友。只要满足一个条件就能抱得女神归,逻辑或操作符就是这样的道理,只要有一个条件为真就可以。?
8.条件操作符
表达式1 ? 表达式2:表达式3
?求两个数的较大值,条件操作符就可以派上用场了。
int a = 5;
int b = 8;
int max = (a > b ? a : b); //a如果大于b的话会把a赋值给max,如果a不大于b 的话则会把b赋值给max
printf("%d\n", max);
?9.逗号表达式
exp1, exp2, exp3, …expN
逗号表达式,就是用逗号隔开的多个表达式。 逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
int a = (1, 2, 3, 5); //逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
//整个表达式的最后是5,5最终赋值给a
printf("%d\n", a);
?10.下标引用、函数调用和结构成员
1. [ ]? 下标引用操作符(就是数组使用的下标引用符) 操作数:一个数组名 + 一个索引值
int arr[10] = { 1,2,3,4,5,6,7,8,9,10}; //创建数组
printf("%d\n", arr[5]); //打印数组下标为5的元素
2.访问一个结构的成员
.? ? ? ? ? ??结构体.成员名 -> ?????????结构体指针->成员名
struct stu
{
char name[20];
int age;
};
int main()
{
struct stu s1 = { "李四", 19 };
printf("%s %d\n", s1.name, s1.age); // .是用来访问结构体成员的
return 0;
}
?
struct stu
{
char name[20];
int age;
};
int main()
{
struct stu s1 = { "李四", 19 };
struct stu* p = &s1;
printf("%s %d", p->name, p->age); //打印结构体指针指向的成员
return 0;
}
?
|