制作网站赚钱吗,室内装饰设计培训机构,wordpress图片如何排版,仲恺企业网站建设目录
一、算数操作符 二、移位操作符
1.左移操作符
2.右移操作符
(1) 逻辑右移
(2) 算术右移 (3)小总结
三、位操作符
四、赋值操作符
五、单目操作符
六、关系操作符
七、逻辑操作符
八、 条件操作符
九、逗号表达式
十、下标引用、函数调用和结构成员
1. [ ]下…目录
一、算数操作符 二、移位操作符
1.左移操作符
2.右移操作符
(1) 逻辑右移
(2) 算术右移 (3)小总结
三、位操作符
四、赋值操作符
五、单目操作符
六、关系操作符
七、逻辑操作符
八、 条件操作符
九、逗号表达式
十、下标引用、函数调用和结构成员
1. [ ]下标引用操作符 2. ( )函数调用操作符
3. 访问一个结构的成员
十一、表达式求值
1.隐式类型转换
2.算术转换
3.操作符的属性
十二、操作符优先级 一、算数操作符 - * / % 除了 % 操作符之外其他的几个操作符可以作用于整数和浮点数对于 / 操作符如果两个操作数都为整数执行整数除法。但是只要有浮点数参与运算就是浮点数除法% 要求两个操作数必须为整数得到的是余数 二、移位操作符 右移操作符 左移操作符 注意移位操作符的操作数只能是整数 1.左移操作符
规则巧记左边抛弃右边补0 这里假设存的是 int n 15;的二进制 进行左移 n1; 如果n 在没有被左移赋值的情况下n自身的值是不会发生变化。这里与自增自减不一样
在深层次看一下一个数 n1 发现相当于该数 n * 2^1。n 2; 等于 n * 2^2
2.右移操作符
(1) 逻辑右移
移位规则右边舍弃左边补0 假设内存 存放的是 -1 补码的二进制
(2) 算术右移
移位规则右边舍弃左边用原值的符号位进行填充 (3)小总结
如果 算术右移与 逻辑右移 总是分不清。巧记算术右移可以想象成 算数既然算数肯定会有正负进而想到 左边填充的是原符号位
注意对于位操作符不存在移动负数位C语言标准并未规定 int num 10; num -1; //error不要多次一举 num 1; // ok 右移 -1 这不相当于 左移 1 嘛。 三、位操作符 //按位与 巧记有0则0其中 一个数 a1 可求 该数的每一个二进制位 | //按位或 巧记有1则1 ^ //按位异或 巧记相同为0相异为1 注操作数必须是整数 【例】1 #includestdio.hint main()
{int a 1;//0001int b 2;//0010/** a b;* 0001* 0010* 0000* * a|b* 0001* 0010* 0011* * a^b* 0001* 0010* 1100*/return 0;
} 接下来看一道面试题
【例】2 不能创建临时变量第三变量实现两个数的交换
解法一
两个数进行来回加减来进行两个数的交换通过调试的监视的窗口我们可以看到两个数的交换 解法二:
#includestdio.h
int main()
{int a 10;int b 20;a a ^ b;b a ^ b;a a ^ b;printf(%d %d,a,b);return 0;
} 从打印结果可以看到a 与 b的值进行了交换
【解析】^ 按位异或 相同为0相异为1可以理解为 相同假相异为真 前面提到 可以用a1 该数的每一个二进制位看下方例题
【例】编写代码求一个整数存储在内存中的二进制中1的个数
#includestdio.h
int main()
{int n 10;int count 0;// 0000 1010// 0000 0001int i 0;for (i 0; i 32;i){if (n 1 1){count;} n n1;}printf(%d,count);return 0;
} 这里用到了 和 ^
解法二
#includestdio.h
int main()
{int n 10;int count 0;while (n) {if (n%2 1){count;}n / 2;}return 0;
}
这里的思路是 因为计算机存储是二进制 0 和1 %2取余判断是否为1/2进行下一位 解法三
#includestdio.h
int main()
{int n -1;int i 0;int count 0;while (n){count;n n (n - 1);//1111 1111 1111 1111 1111 1111 1111 1111//1111 1111 1111 1111 1111 1111 1111 1110//1111 1111 1111 1111 1111 1111 1111 1110}printf(%d , count);return 0;
}
这里的优化 是借助 两个数差1 进行按位与一个一个位找1
四、赋值操作符 这是赋值符不是等于
赋值操作符 给一个变量进行赋值 注意赋值操作符的优先级比较低包括复合赋值符
int age 18;age 20; //对变量进行赋值
赋值操作符支持连续使用;
int a 0;
int b 10;
int c 1;
a b c1; //这里是连续赋值
虽然可以连续赋值但是代码的可读会下降
b c1;
a b;
//这样子是不是看着更用以理解
代码的可读性也是很重要的
接下来看复合赋值符都有哪些 、-、* 、/ 、% 、 、 、 、 | 、^ int a 10;
a a10;
//可以写成这样
a 10;
其他复合赋值符同上方用法一致
五、单目操作符
单目操作符就是操作数只有一个 sizeof 括号里面不是类型时可以省略说到sizeof 其中 size_t 是一种类型是一种无符号整型的size_t 就是为sizeof专门设计的一种类型打印时使用%zd,但是size_t 在不同平台下可能是 unsigned int 也有可能是 unsigned long long int
sizeof(数组名) 计算的是整个数组的大小
前置先对该数1然后再去使用这个数
后置相当于 先使用该数然后在对该数进行 1
-- 与上方的同理
六、关系操作符 、 、 、 、! 、 注意 这个是 等于 这个是 赋值
七、逻辑操作符 逻辑与 || 逻辑或 要区分 与 ; | 与 ||
12 --- 0
12 --- 1 (左边为假右边无需计算直接为假)
1 | 2 --- 3
1 || 2 --- 1 左边为真右边无需计算直接为真 【例】1笔试题求结果输出的值
#includestdio.h
int main()
{int i 0, a 0, b 2, c 3, d 4;i a b d;printf(a %d\n b %d\n c %d\nd %d\n, a, b, c, d);return 0;
} 【结果】a 1 b 2 c 3 d 4
解析 首先 a 0 a ,是先使用后 1又有 (左边为假右边无需计算直接为假)
打印的是 a 1,其他值正常打印 【例】2 对这个题进行改编 a 1
#includestdio.h
int main()
{int i 0, a 1, b 2, c 3, d 4;i a b d;printf(a %d\n b %d\n c %d\nd %d\n, a, b, c, d);return 0;
}
【结果】 a 2 b 3 c 3 d 5
解析 a 1时,左边为真后面表达式继续进行计算进而 a 2, b 3,c 3 ,d 5 【例】3 对这个题进行改编 改为 || 并求出i 的值
#includestdio.h
int main()
{int i 0, a 0, b 2, c 3, d 4;i a || b || d;printf(a %d\n b %d\n c %d\nd %d\n, a, b, c, d);return 0;
}
【结果】 a 1 b 3 c 3 d 4 i 1
解析 因为时逻辑或 左边为真右边无需计算直接为真虽然先使用 a 为假但接下来的操作数 b , b 3为真 进而后面无需计算。而 i 表达式里面有真 则 i 1, 为真 八、 条件操作符 表达式1 表达式2 表达式3; 唯一 一个三目操作符 在这里 看一个 求最大值的代码 ab?a:b; //中文解释 ab 吗大于就是a, 不大于就是b
【例】求三个数的最大值
#includestdio.h
int main()
{int a 1;int b 2;int c 3;int max 0;max a b ? a : b;max max c ? max : c;printf(%d,max);return 0;
} 这里是使用两次条件操作符进行计算三个数中的最大值
九、逗号表达式 表达式1 , 表达式2 ... , 表达式n 逗号表达式从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
//代码1
int a 1;
int b 2;
int c (ab, ab10, a, ba1);//逗号表达式
c 的结果是 13
逗号表达式可以对代码进行优化
a get_val();
count_val(a);
while (a 0)
{//业务处理a get_val();count_val(a);
}//使用逗号表达式可以改写为
while (a get_val(), count_val(a), a 0)
{//业务处理
}
十、下标引用、函数调用和结构成员
1. [ ]下标引用操作符
注意 操作数为 一个数组名 一个索引值
int arr[20]; //创建数组
// [ ] 的操作数 是 arr 和 20 2. ( )函数调用操作符
接受一个或者多个操作数第一个操作数是函数名剩余的操作数就是传递给函数的参数
#include stdio.h
void test1()
{printf(hehe\n);
}
void test2(const char* str)
{printf(%s\n, str);
}
int main()
{test1(); //作为函数调用操作符。test2(hello bit.);//作为函数调用操作符。return 0;
}
3. 访问一个结构的成员 . 结构体.成员名 - 结构体指针 - 成员名 #include stdio.h
struct Stu
{char name[10];int age;char sex[5];double score;
};
void set_age1(struct Stu stu)
{stu.age 18;
}
void set_age2(struct Stu* pStu)
{pStu-age 18;//结构成员访问
}
int main()
{struct Stu stu;struct Stu* pStu stu;//结构成员访问stu.age 20;//结构成员访问set_age1(stu);pStu-age 20;//结构成员访问set_age2(pStu);return 0;
}
十一、表达式求值
表达式求值的顺序一部分是由操作符的 优先级 和 结合性 决定。 同样有些表达式的操作数在求值的过程中可能需要转换为其他类型。
1.隐式类型转换
整型算术运算总是至少以缺省整型类型的精度来进行的。 为了获得这个精度表达式中的字符和短整型操作数在使用之前被转换为普通整型这种转换称为整型提升。
整型提升的意义
表达式的整型运算要在CPU的相应运算器件内执行CPU内整型运算器(ALU)的操作数的字节长度 一般就是int的字节长度同时也是CPU的通用寄存器的长度。因此即使两个char类型的相加在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。
通用CPUgeneral-purpose CPU是难以直接实现两个8bit字节直接相加运算虽然机器指令中可能有这种字节相加指令。所以表达式中各种长度可能小于int长度的整型值都必须先转 换为int或unsigned int然后才能送入CPU去执行运算。
//例
char a,b,c;
a b c;
在上述代码中b和c的值被提升为普通整型int然后再执行加法运算加法运算完成之后结果将被截断然后再存储于a中
整型提升
整形提升是按照变量的数据类型的符号位来提升的
char c1 -1;
变量c1的二进制位(补码)中只有8个比特位
1111111
因为 char 为有符号的 char
所以整形提升的时候高位补充符号位即为1
提升之后的结果是
11111111111111111111111111111111
//正数的整形提升
char c2 1;
变量c2的二进制位(补码)中只有8个比特位
00000001
因为 char 为有符号的 char
所以整形提升的时候高位补充符号位即为0
提升之后的结果是
00000000000000000000000000000001
无符号整形提升高位补0
【例】1
int main()
{char a 0xb6;short b 0xb600;int c 0xb6000000;if (a 0xb6)printf(a);if (b 0xb600)printf(b);if (c 0xb6000000)printf(c);return 0;
}
【结果】c
实例的a,b要进行整型提升,但是c不需要整形提升a,b整形提升之后,变成了负数,所以表达式 a0xb6 , b0xb600 的结果是假,但是c不发生整形提升,则表达式 c0xb6000000 的结果是真.
【a】1101 0110 整型提升1111 1111 1111 1111 1111 1111 1101 0110
【b】1101 0110 0000 0000 整型提升1111 1111 1111 1111 1101 0110 0000 0000
【例】2
int main()
{char c 1;printf(%u\n, sizeof(c));printf(%u\n, sizeof(c));printf(%u\n, sizeof(-c));return 0;
}
【结果】1 4 4
实例2中的,c只要参与表达式运算,就会发生整型提升,表达式 c ,就会发生提升,所以 sizeof(c) 是4个字节。表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,但是 sizeof(c) ,就是1个字节
2.算术转换
如果某个操作符的 各个操作数的类型不一样那么除非其中一个操作数的转换为另一个操作数的类型否则操作就无法进行。下面 寻常算术转换 long double double unsigned long int long int unsigned int int 向上转换 如果某个操作数的类型在上面这个列表中排名较低那么首先要转换为另外一个操作数的类型后执行运算。
注意 算数转换要合理否则可能会出现精度丢失
float pi 3.14;int num f;//num 3 精度丢失
3.操作符的属性
复杂表达式的求值有三个影响的因素。
操作符的优先级操作符的结合性是否控制求值顺序
两个相邻的操作符先执行哪个取决于他们的优先级。如果两者的优先级相同取决于他们的结合性。
十二、操作符优先级
点击下方链接查看
链接操作符优先级
注意我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径那这个表达式就是存在问题的。