编程语言操作符小结引入: 操作符是一个表示特定的数学或逻辑操作的符号,如数学中的加法,在c语言中也有+,而c语言中不止有加减乘除,通过本小节来学习并了解和学习这些操作符。 一、操作符分类 算数操作符 移位操作符 位操作符 赋值操作符 单目操作符 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用、函数调用和结构成员 二、详细介绍操作符 1.算数操作符 + - * / % 加减乘和数学中的运算符用法一样,这里重点介绍 / 和 %(取模) 1)对于 / 操作符,如果两个操作数都为整数,执行整数除法;而只要有浮点数,执行的就是浮点数除法。这句话理解如下: int main() { int a = 10 / 3; double b = 10.0 / 3; double c = 10 / 3.0; printf("a=%d\n", a); //结果为3,因为10和3都是int型 printf("b=%lf\n", b); //结果为3.333333,因为10.0是double型 printf("a=%lf\n", c); //结果为3.333333,因为3.0是double型 return 0; } 2)% 的意思是求余,如10%3的结果为1,因为10除以3的余数是1。 %操作符的两个操作数必须为整数,如10.0%3这样的写法就是错误的。%返回的是整除后的余数 2.移位操作符 1)引入:在介绍移位操作符之前,我们先介绍整数在内存中如何存储的 整数有三种二进制表示形式:原码、补码、反码。 整数在内存中存储的是补码 正数的原码、反码、补码 如 int a = 5,a是整型,占内存的4个字节,即32bit。5用二进制表示是101,因为占32个bit,所以将它补全即为 00000000 00000000 00000000 00000101 ,这个就是5的原码 正数的原码、反码、补码都是这个 负数的原码、反码、补码 如 int a = -5, 5的原码是00000000 00000000 00000000 00000101 -5的原码就是将它的第一位0变成1,即10000000 00000000 00000000 00000101 -5的反码就是将原码的符号位不变,就是第一位不变,其余的0变成1,1变成0 即11111111 11111111 11111111 11111010 -5的补码就是反码的二进制+1 即11111111 111111111 11111111 11111011 2) 左移操作符 规则:左边抛弃,右边补0 对于正数的左移操作,因为正数的原、反、补码都一样,所以直接将原码左移就可以了。 int main() { int a = 5; int b = a << 2;//把a在内存中存储的二进制位向左移动两位 printf("a=%d b=%d\n",a, b);//a=5,b=20 return 0; } 下面画图进行解释,二进制位向左移动两位。 对于负数的左移操作,需要求出其补码,将补码移位,再将移位后的补码转化为原码,求出其值。因为打印或使用的时候,用的是原码的值。 int b = a<<2; 11111111 111111111 11111111 11111011 -5的补码 11111111 111111111 11111111 11101100 将-5的补码左移两位 11111111 111111111 11111111 11101011 反码:补码减一 10000000 00000000 00000000 00010100 原码:结果是-20 3)右移操作符 规则:算数右移:右边丢弃,左边补原来的符号位 逻辑右移:右边丢弃,左边补0 到底是算数右移还是逻辑右移,取决于编译器,我们常见的编译器都是算数右移 对于正数的右移,直接将原码右移,补符号位时补0 int main() { int a = 5; int b = a >> 1; printf("%d\n", b);//结果是2 return 0; } 对于负数的右移和左移相似,也是将其补码右移,唯一区别的就是左边补位的时候,不是补0,而是补符号位1 3.位操作符 1)& 按位与:按(2进制)位与-----两个数的补码对应位只要有0就是0,两个同时为1才为1 int main() { int a = 3; int b = -5; int c = a & b; printf("%d\n", c);//结果是3 return 0; } 解释:00000000 00000000 00000000 00000011 3的补码 11111111 11111111 11111111 11111011 -5的补码 00000000 00000000 00000000 00000011 按位与后的补码 因为符号位是0,所以这是一个正数的补码,原码和补码相同,所以结果是3 2)| 按位或:按(2进制)位或---两个数的补码对应位只要有1就是1,两个同时为0才为0 int main() { int a = 3; int b = -5; int c = a | b; printf("%d\n", c);//结果是-5 return 0; } 解释: 00000000 00000000 00000000 00000011 3的补码 11111111 11111111 11111111 11111011 -5的补码 11111111 11111111 11111111 11111011 按位或后的补码,符号位是1,所以是个负数,需要求它的原码 11111111 11111111 11111111 11111010 按位或后的反码 10000000 00000000 00000000 00000101 按位或后的原码,即为-5 3)^ 按位异或:按(2进制)位异或:两个对应位相同为0,相异为1 int main() { int a = 3; int b = -5; int c = a ^ b; printf("%d\n", c); //结果是-8 return 0; } 解释:00000000 00000000 00000000 00000011 3的补码 11111111 11111111 11111111 11111011 -5的补码 11111111 11111111 11111111 11111000 按位异或后的补码,这是个负数,要求出它的原码 11111111 11111111 11111111 11110111 按位异或后的反码 10000000 00000000 00000000 00001000 按位异或后的原码,即为-8 4.赋值操作符 = 用来给变量赋值,如 int a = 10; 符合赋值操作符 += -= *= /= %= >>= <<= &= |= ^= 复合操作符的使用用法如下: 这里用'+=’为例 int main() { int a = 0; a += 10; //等价于a = a+10 printf("a=%d\n",a);//结果为10 return 0; } 5.单目操作符 1)! 逻辑反操作 :作用是把假的变成真的,把真的变成假的 int main() { int flag = 0; if (!flag) //因为flag为0是假,!flag为真,进入if语句 { printf("我爱c语言\n"); } return 0; //打印我爱c语言 } 2)- 负值 例:在屏幕上打印 0 -1 2 -3 4 -5 6 -7 8 -9 int main() { int i = 0; int flag = 1; for (i = 0; i < 10; i++) { printf("%d ", i * flag); flag = -flag; } return 0; } 3)+ 正值 4)& 取地址:拿取在内存中的地址 5)sizeof 操作数的类型长度(以字节为单位) int main() { int a = 10; printf("%d\n", sizeof(a));//结果是4,因为int是整型,整型占四个字节 printf("%d\n", sizeof(int));//结果是4 int arr[10] = { 1,2,3,4,5,6 }; printf("%d\n", sizeof(arr)); //结果是40 计算整个数组的大小 printf("%d\n", sizeof(int [10]));//结果是40,数组里有10个int型,所以是40 return 0; } 6)~ 对一个数的二进制按位取反 int main() { int a = 0; //00000000 00000000 00000000 00000000 这是0的补码 //11111111 11111111 11111111 11111111 这是按位取反后的结果,这个依然是补码 //11111111 11111111 11111111 11111110 这是反码 //10000000 00000000 00000000 00000000 这是原码,是~a最后的结果,即是-1 printf("%d\n", ~a);//结果是4,因为int是整型,整型占四个字节 return 0; } 7)++ 前置、后置++ int main() { int a = 10; int b = ++a; //前置++,先++,后使用。即先把a+1,再赋值给b int c = 10; int d = c++; //后置++,先使用,后++。即先把c的值赋给d,c再+1 printf("a=%d b=%d\n",a, b); //a = 11 b = 11 printf("c=%d d=%d\n",c, d);//c = 11 d = 10 return 0; } 8)-- 前置、后置-- :和上面相似,就不多做介绍了。 9)* 间接访问操作符(解引用操作符):对地址进行解引用操作 int main() { int a = 0; int* pa = &a; //pa里面放的是a的地址,*pa找到a的空间 *pa=20; //找到a的空间,将a的值改为20 printf("%d\n", a); //打印20 return 0; } 10)(类型) 强制类型转换 int main() { //int a = 3.14;//3.14是double类型的数据,把它放在int型里会丢失数据,并且会报警告 int a = (int)3.14;//强制类型转换,将3.14强制转换成int型 printf("%d\n", a);//结果是3,不会报警告 return 0; } 强制类型转化不建议经常使用。 6.关系操作符 1) > 2) >= 3) < 4) <= 5) != 6) == 7.逻辑操作符 逻辑操作符只关注真假 1) && 逻辑与:表示并且 例:写一个代码,当从键盘输入一个大于0小于18的数时打印未成年 int main() { int age = 0; //if (0 < age < 18)//这种写法是错误的。例如输入20,而20是大于0的,是真,也会进入if中 //{ // printf("未成年"); //} scanf("%d", &age); if (age > 0 && age < 18) { printf("未成年"); } return 0; } 2)|| 逻辑或:表示或者 例:几个练习 && 左操作数为假,右边不计算。为真的时候才计算右边 || 左操作数为真,右边不计算。为假的时候才计算右边 int main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++;//a=0是假,后面就不需要计算了,b、d的值保持不变 printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);//a,b,c,d的值分别为1,2,3,4 return 0; } int main() { int i = 0, a = 1, b = 2, c = 3, d = 4; i = a++ && ++b && d++;//a++是真,右边的++b,d++计算 printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);//a,b,c,d的值为2,3,3,5 return 0; } int main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ || ++b || d++;//因为++b是真,右边的d++不计算 printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);//a,b,c,d的结果是1,3,3,4 return 0; } 8.条件操作符(三目操作符) 表达式1 ? 表达式2 : 表达式3:表达式1结果为真,就执行表达式2;为假就执行表达式3 例:利用三目操作符来判断两个数的较大值 int main() { int a = 10; int b = 20; int max = 0; max = (a > b ? a : b); printf("%d\n", max); return 0; } 9.逗号表达式 表达式1,表达式2,..... ,表达式n 逗号表达式就是用逗号隔开的多个表达式。 逗号表达式从左向右依次执行。整个表达式的结果是最后一个表达式的结果。 int main() { int a = 3; int b = 5; int c = 6; int d = (a += 2, b = a - c, c = a + 2 * b); printf("%d\n", d);//结果是3 return 0; } 10.下标引用 、函数调用和结构成员 1) [ ] 下标引用操作符 int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; printf("%d\n", arr[6]);//操作数是arr和6,结果是7 printf("%d\n", 6[arr]);//arr[7] ——->*(arr+6)-->*(6+arr)-->6[arr],结果也是7 return 0; } 2)函数调用操作符 接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数 int Add(int x, int y) { return x + y; } int main() { int ret = Add(2, 3); printf("%d\n", ret); return 0; } 3.访问一个结构体成员 . 结构体变量.结构体成员 -> 结构体指针->结构体成员 struct Stu { char name[20]; int age; double score; }; int main() { // . struct Stu s = {"xiaohong", 19, 95.5}; printf("%s %d %.1lf\n", s.name, s.age, s.score); // -> struct Stu* ps = &s; printf("%s %d %.1lf\n", (*ps).name, (*ps).age, (*ps).score); printf("%s %d %.1lf\n", ps->name, ps->age, ps->score); return 0; |
|