// //2.
// a >>= 1;
//
// //1.
// a = a + 10;
// //2.
// a += 10;
// return 0;
//}
//单目操作符(unary operator)
//#include<stdio.h>
//int main()
//{
// // ! 逻辑反操作
// int a = 5;
// int b = !a;
// printf(“%d\n”, b);//a=非零为真,!a0 把真变为假,反之 a = 0 !a 1
// if (a != 0)//a为真,打印hehe
// {
// printf(“hehe\n”);
// }
// if (!a)//a为假,打印haha
// {
// printf(“haha\n”);
// }
// return 0;
//}
// &取地址 *解引用符 sizeof:
//#include<stdio.h>
//#include<string.h>
//int main()
//{
//
// char array[10] = “abc”;// 10个字节的内存
// printf(“%d\n”,sizeof(array));// 10
// printf(“%d\n”, sizeof array);//两者等价,因为sizeof操作符不是函数,所以可去括号
// //如果括号里是类型:sizeof(int),此处括号不可省略
// //计算变量或者类型创建变量的内存大小,单位字节,和内存中存放什么没有关系
// printf(“%d\n”, strlen(array)); // 3
// // strlen(arr) 遇到’\0’,就定制计算
// // 且不能省略().
//
// int arr[10] = { 0 };
// // arr //数组首元素地址
// // &arr //取数组地址 == sizeof(arr) 中的 arr 都是代表整个数组
// // &arr[0]//数组首元素地址
// // &arr[9]//数组第10个元素地址
// int a = 10;
// int* p = &a;
// *p = 20;//*p仿作左边代表的是用来存放数值的空间
// printf(“%d\n”, a);// 20
// int b = *p;// *p放在右边代表的是存储的空间里存储的数值
// printf(“%d\n”,b);// 20
// return 0;
//}
//#include<stdio.h>
//int main()
//{
// int a = 5;
// short s = 10;
// printf(“%d\n”, sizeof(s = a + 1));// 2 s是短整型,a+1=6,把这个整形放进短整型,放不下,发生截断
// //最终的结果,归s负责,为short类型,算变量或者类型创建变量的内存大小,和内存中存放什么没有关系
// //即为 2
//
// printf(“%d\n”,s);// 10 sizeof不参与计算,直接计算出sizeof(short)拿走了,所以后面 a+1;根本就没机会运行,所以s还是10.
// return 0;
//}
// ~ 按位取反(包括符号)
//#include<stdio.h>
//int main()
//{
// int a = 0;
// //00000000000000000000000000000000
// int b = ~a;
// //11111111111111111111111111111111 //补码
// printf(“%d”,b);// 原码= (补码 - 1)取反 (不包括符号位)
// //10000000000000000000000000000001
// // 值为 -1
// return 0;
//}
//#include<stdio.h>
//int main()
//{
// int a = 13;
// //00000000000000000000000000001101 // a为正整数 三码一样,这是补码
//
// // 1的补码
// //00000000000000000000000000000001
//
// //1 << 1(1的补码向左移动一位)
// //即:00000000000000000000000000000010
// a |= (1 << 1);//00000000000000000000000000001111//经由上两式子逻辑或之后,把 1101中的0改成了 1 ,即1111
// printf(“%d\n”, a);// 值为 15
// // 00000000000000000000000000001111
//
// //00000000000000000000000000000010 1 << 1
// //按位取反
// // 11111111111111111111111111111101 & 00000000000000000000000000001111
// a &= (~(1 << 1));//00000000000000000000000000001101
// printf(“%d\n”, a); //13
//
//
// return 0;
//}
//前置加加/减减 后置加加/减减
//#include<stdio.h>
//int main()
//{
// int a = 10;
// int b = a++;//后置加加,先赋值,后加加
// printf(“%d\n”,b);//10
// printf(“%d\n”, a);//11
// return 0;
//}
//
//#include<stdio.h>
//int main()
//{
// int a = 10;
// int b = ++a;//前置加加,先加加,后赋值
// printf(“%d\n”,b);//11
// printf(“%d\n”, a);//11
// return 0;
//}
//#include<stdio.h>
//int main()
//{
// int a = 10;
// int b = a–;//后置减减,先赋值,后减减
// printf(“%d\n”, b);//10
// printf(“%d\n”, a);//9
// return 0;
//}
//#include<stdio.h>
//int main()
//{
// int a = 10;
// int b = --a;//前置减减,先减减,后赋值
// printf(“%d\n”, b);//9
// printf(“%d\n”, a);//9
// return 0;
//}
// ()强制转换符
//#include<stdio.h>
//int main()
//{
// int a = (int)3.14;
// printf(“%d\n”,a);// 3
// return 0;
//}
// && 逻辑与 只关注真假
//#include<stdio.h>
//int main()
//{
// int a = 1;
// int b = 2;
// int c=a&&b;
// printf(“%d\n”,c);// a 和 b 都是非零,所以c为真 c == 1
// return 0;
//}
// && 逻辑或,有1出1,双零出零
//#include<stdio.h>
//int main()
//{
// int a = 1;
// int b = 0;
// int c = a||b;
// printf(“%d\n”, c);// a 是非零,所以c为真 c == 1
// return 0;
//}
// >= <=
//#include<stdio.h>
//int main()
//{
// int age = 0;
// scanf(“%d”,&age);
// if ((age >= 10) && (age <= 30))
// {
// ;
// }
// if ((age >= 10) || (age <= 30))
// {
// ;
// }
// return 0;
//}
// 360 笔试题
//#include<stdio.h>
//int main()
//{
// int i = 0, a = 0, b = 2, c = 3, d = 4;
// i = a++ && ++b && d++; // a++ 先赋值再加加,a=0;所以为假,与任何数相与都为假。 所以 && ++b && d++ 没有执行
// //用完之后 a加加等于 1
// printf(“a = %d b = %d c = %d d = %d\n”,a,b,c,d);//即输出位 1,2,3,4
// return 0;
//}
//#include<stdio.h>
//int main()
//{
// int i = 0, a = 1, b = 2, c = 3, d = 4;
// i = a++ && ++b && d++; // a=1;所以为真, ++b先加后赋值,即b==3, d++先加后赋值,此时d=4
// //用完之后 a=2,b= 3,c=3,d=5
// printf(“a = %d b = %d c = %d d = %d\n”, a, b, c, d);//即输出位 2335
// return 0;
//}
//#include<stdio.h>
//int main()
//{
// int i = 0, a = 1, b = 2, c = 3, d = 4;
// i = a++ || ++b || d++; // a=1;所以为真, 或逻辑 只要一个为真,就是真,所以后面的|| ++b || d++ 都不执行
// //用完之后 a=2,b= 3,c=3,d=4
// printf(“a = %d b = %d c = %d d = %d\n”, a, b, c, d);//即输出位 2234
// return 0;
//}
//#include<stdio.h>
//int main()
//{
// int i = 0, a = 0, b = 2, c = 3, d = 4;
// i = a++ || ++b || d++; // a=0;所以为假,++b,先加后赋,b==3, 因为或逻辑只要一个为真,就是真,所以后面的 || d++ 都不执行
// //用完之后 a=1,b= 3,c=3,d=4
// printf(“a = %d b = %d c = %d d = %d\n”, a, b, c, d);//即输出位 1334
// return 0;
//}
//条件操作符 ()?()😦) 又称 三目操作符
//#include<stdio.h>
//int main()
//{
// int a = 10;
// int b = 20;
// int c = (a > b) ? (a) : (b);// 如果a>b为真, 就返回a,否则返回 b
// printf(“%d\n”,c);//a > b 为假,所以返回 b
// return 0;
//}
//逗号表达式
//#include<stdio.h>
//int main()
//{
// int a = 1;
// int b = 2;
// int c = (a > b/*只是执行一下*/, a = b + 10/* a == 12 */, a/* 12 */, b = a + 1/* 13 */);//从左往右计算,以为 最右边的式子 的 结果 为 整个式子的结果
// printf(“%d\n”,c);// 13
// return 0;
//}
//#include<stdio.h>
//int main()
//{
// int a = get_val();
// count_val(a);
// while (a > 0)//while (a = get_val(),count_val(a);a > 0) //逗号表达式可以运用到循环中,从左往右计算
// {
// ;
// }
//
// return 0;
//}
//下标引用操作符[],函数调用操作符(),结构访问操作符
//下标引用操作符
//#include<stdio.h>
//int main()
//{
// int arr[] = { 1, 2, 3, 4, 5 };
// int i = 0;
// //arr[4]// 代表的是数组中第五个元素 5,等价于 *(arr+4)== *(4+arr) 和 4[arr].,说明这些式子支持交换律
// // []是一个操作符,而 4 和 arr 是操作数
//
// // *(arr+4) == *(4+arr) 意思是用 arr 的 起始地址 加上 4 ,找到下标为4 的元素
// //该式子支持交换律
// for (i = 0; i < 5; i++)
// {
// printf(“%p\n”,&arr[i],arr+i);//输出的数列arr中第 i+1 个元素的地址
// //printf(“%p\n”,arr+i);//与上式子完全等价
// }
// return 0;
//}
//函数调用操作符
// 能接受一个或者多个操作数;第一个操作数是函数名,其余操作数就是专递函数的参数
//
//#include<stdio.h>
//#include<string.h>
//
//void test()
//{
// printf(“hehe\n”);
//}
//
//int main()
//{
// char arr[] = “hello world1”;
// strlen(arr);// 这里的小圆括号,是函数调用操作符,不可省略(strlen arr // error)
// //strlen 函数的返回值是 size_t == unsigned int 无符号整形
//
// printf(“%u\n”,strlen(arr));// %u,表示打印无符号整形,%d 表示打印有符号整形
// printf(“%u\n”, strlen(“hello”));//函数调用操作符() ,不可省略
//
//
// test();//函数调用操作符() ,不可省略.即使不传参,也是一样。
//
// return 0;
//}
//结构访问操作符 . 例:结构体.c成员名 -> 指针型 : 结构体指针 -> 成员名
//#include<stdio.h>
自定义类型
//struct book
//{
// char name[20];
// float price;
// char id[20];
//};
//void print(struct book* pb)
//{
// //常用后者表示
// printf(“%s\n”, (*pb).name);//printf(“%s\n”, pb->name);
// printf(“%f\n”, (*pb).price);//printf(“%f\n”, pb->price);
// printf(“%s\n”, (*pb).id);//printf(“%s\n”, pb->id);
//}
//int main()
//{
// struct book b = { “z语言”,48.5f, “ab12345” };
//
// printf(“%s\n”,b.name);//printf(“%s\n”,b.name);
//
// strcpy(b.name,“c”);//改变 或 赋值 数据结构,需要通过 strcpy 函数
// //因为数组名是地址,数据结构需要放在储存空间里
// b.price = 50; // 但变量可以直接赋值
//
// print(&b);
//
// printf(“%s\n”, b.name);
// printf(“%f\n”, b.price);
// printf(“%s\n”, b.id);
// return 0;
//}
//表达式求值的顺序
// 一部分有操作符的优先级和结合性决定。
//同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。
//隐式类型转换 :偷偷的进行类型转换
//c的整形算术运算总是至少以缺省整形类型的精度来进行的
//为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整形,这种转换称为 整形提升。
//#include<stdio.h>
//int main()
//{
// char a = 3;//char 1 byte 只能存放 8 bit
// //000000000000000000000000 00000011 //补码 。 a 是正整数 三码相同
// //00000011 //数据截断(最低位)后的数据,也就是存入a的数据
// char b = 127;
// //000000000000000000000000 01111111 // 127的二进制位
// //01111111 这是真正存入b的二进制位
//
//
// // b 和 a 的值都被提升为普通整形,再进行加法运算,
// //加法运算完以后,结果将被截断(整形存入字符类型),然后存储于c中
// char c = a + b;
// // a 和 b 如何相加 表达式中的字符和短整型操作数在使用之前被转换为普通整形,这种转换称为 整形提升。
// //00000011 整形提升是按照变量的数据类型的符号位来提升的。
// //01111111 因为截断后的数据第一位是0,即为正,根据变量类型的符号位,来进行整形提升
// 无符号整形直接补0
//
// //整形提升后
// //000000000000000000000000 00000011
// //000000000000000000000000 01111111
// //000000000000000000000000 10000010 // 加法运算完后,a+b
// //再进行截断 10000010(补码) 这就是放进c的二进制位
// //11111111111111111111111110000010(补码) //整形提升:按照变量的数据类型的符号位(10000010)来提升的,所以补1,
// printf(“%d\n”,c);// 打印原码 :100000000000000000000000 01111110 -126
//
// //整形提升的意义
// //表达式的整形运算要在CPU的相应运算器件内执行,CPU内整形运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU通用的寄存器的长度。
//
// // 因此,即是两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整形操作数的标准长度。
//
// //通过CPU(general-purpose CPU)是难以直接实现两个8字节直接相加运算(虽然机器指令中可能有这种字节相加的指令)。
// //所以,表达式中各种长度可能小于 int 长度的整型值,都必须先转换为 int 或 unsigned int ,然后才能送入CPU执行运算
// return 0;
//}
//案例 1
//#include<stdio.h>
//int main()
//{
// char a = 0xb6;// 0xb6 二进制码 1011 0110 存入 a ;然后 0xb6 == a要进行比较,所以 a 要整形提升,按照变量的数据类型的符号位,即 1。所以补 1
// //111111111111111111111111 1011 0110 //整形提升后,很明显 a 与 0xb6 不相等,所以不打印 a
// short b = 0xb6000; // 与上式子同理,所以 b 也不打印
// int c = 0xb6000000;//因为 c 本来就是整形,所以不用整形提升,即if (0xb6000000 == c)条件成立,所以可以打印 c
// if (0xb6 == a)
// {
// printf(“a”);
// }
// if (0xb6000 == b)
// {
// printf(“b”);
// }
// if (0xb6000000 == c)
// {
// printf(“c”);
// }
// return 0;
//}
//案例 2
//#include<stdio.h>
//int main()
//{
// char c = 1;//char 1 byte
// printf(“%u\n”,sizeof©); // 1
// printf(“%u\n”, sizeof(+c));// 4 要进行整形计算了,所整形提升,故32 bit,即4字节。也就说sizeof计算的是一个整形的大小
// printf(“%u\n”, sizeof(!c));// 1
// return 0;
//}
//算术转换
//如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换 为另一个操作数的类型,否则操作就无法进行。
//寻常算术转换
// long double
// double
// float
// unsigned long int
// long int
// unsigned int
// int
//如果程序中出现上面其中2个类型,下面的要向上面的进行 算术转换
// 比如 出现 int 和 unsigned int, int 要转换成 unsigned int 进行运算——算术转换
//操作符的属性
//复杂表达式的求值有三个影响的因素
// 1. 操作符的优先级
// 2. 操作符的结合性
// 3. 是否控制求值顺序
// 两个相邻的操作符执行哪一个?取决于它们的优先级,如果两者的优先级相同,取决于它们的结合性。
//#include<stdio.h>
//int main()
//{
// int a = 10;
// int b = 20;
// // 1. 优先级
// int c = a + b*3;// *(乘) 的优先级比 + 的优先级要高,所以要先计算 a*3,在计算 + a
// printf(“%d\n”,c);// 20*3+10= 70
// // 2, 结合性
// int d = a + b + 3; // + 的结合性 LR 从左往右计算
// printf(“%d\n”, d);
// // 3. 是否控制求值顺序
// int e = a && b + 3;// 逻辑与 && 结合性 LR,如果 a为假的话,后面的式子,他就不会计算了,这就是控制求值顺序
// // 逻辑或 || 条件操作符(三目操作符)()?()😦) 逗号表达式 , 也是一样的。
// //结果为最后一个表达式的结果
// printf(“%d\n”, e);
// return 0;
//}
//一些问题表达式 (重点: 最好能确定唯一的计算路径,如果不能,说明这个表达式就是存在问题的)
// 代码1. a * b + c * d + e * f 绝对不能写出这种的表达式,如果非要写,写好()因为它的优先级最高,
// 比如 ,我想先计算a * b ,后c * d,再e * f
//即((a * b )+ c * d )+ e * f
//代码在计算的时候由于*的优先级高,只能保证比+早,但是优先级并不能决定 三个*中哪一个早执行。
// 代码2. c + --c; // --优先级高,先–c,再加 c
// 但是 + 操作符的 左操作数的 获取,在 右操作数 之前 还是 之后 求值,我们不能确定,所以结果不可预测,是有歧义的
//左操作数的 获取,在 右操作数 之前 比如说 c = 1 表达式为 c(1)±-c(0)=1