网站开发的一般步骤,公司简介内容,全网营销思路,潍坊科技网站建设操作符详解1. 操作符分类2. 算术操作符3. 移位操作符3.1 整数的二进制是怎么形成的3.2 左移操作符3.3 右移操作符4. 位操作符5. 赋值操作符6. 单目操作符6.1 单目操作符介绍6.2 sizeof 和 数组7. 关系操作符8. 逻辑操作符9. 条件操作符9.1 练习19.2 练习210. 逗号表达式11. 下标… 操作符详解1. 操作符分类2. 算术操作符3. 移位操作符3.1 整数的二进制是怎么形成的3.2 左移操作符3.3 右移操作符4. 位操作符5. 赋值操作符6. 单目操作符6.1 单目操作符介绍6.2 sizeof 和 数组7. 关系操作符8. 逻辑操作符9. 条件操作符9.1 练习19.2 练习210. 逗号表达式11. 下标引用、函数调用和结构成员11.1 [ ] 下标引用操作符11.2 ( ) 函数调用操作符11.3 访问一个结构的成员12. 表达式求值12.1 隐式类型转换12.2 算术转换12.3 操作符的属性1. 操作符分类
算术操作符移位操作符位操作符赋值操作符单目操作符关系操作符逻辑操作符条件操作符逗号表达式下标引用、函数调用和结构成员
2. 算术操作符 - * / % 除了 % 操作符之外其他的几个操作符可以作用于整数和浮点数。对于 / 操作符如果两个操作数都为整数执行整数除法。而只要有浮点数执行的就是浮点数除法。% 操作符的两个操作数必须为整数。返回的是整除之后的余数。
#include stdio.hint main()
{// / 除法 - 得到的是商// 除法操作符的两个操作数都是整数的话执行的是整数除法// 除法操作符的两个操作数只要有一个浮点数执行的是小数除法// // % 取模 取余得到的是余数// 取模操作符的操作数必须是整数printf(%lf\n, 10 / 3.0);//5printf(%d\n, 10 % 2);//0return 0;
}3. 移位操作符
左移操作符右移操作符
注移位操作符的操作数只能是整数。
3.1 整数的二进制是怎么形成的
整数的二进制表示形式有三种原码反码补码 原码把一个数按照正负直接翻译成二进制就是原码 反码原码的符号位不变其他位按位取反就是反码 补码反码1 注意
正整数的原码反码补码是相同的负整数的原码反码补码是要计算的最高的一位表示符号位0表示正数1表示负数整数在内存中储存的是补码二进制 原码到补码是取反1补码到原码是取反1或-1取反。 3.2 左移操作符
移位规则 左边抛弃、右边补0 int main()
{int a -3;//10000000000000000000000000000011//11111111111111111111111111111100//11111111111111111111111111111101 - 补码//int b a 1;//11111111111111111111111111111010//11111111111111111111111111111001//10000000000000000000000000000110//11111111111111111111111111111010//10000000000000000000000000000101//10000000000000000000000000000110printf(%d\n, b);//-6printf(%d\n, a);//-3return 0;
}3.3 右移操作符
移位规则 首先右移运算分两种
逻辑移位 左边用0填充右边丢弃算术移位 左边用原该值的符号位填充右边丢弃 右移的时候到底采用的是算数右移还是逻辑右移是取决于编译器的 // 右移操作符
//VS算术右移
int main()
{int a -5;//10000000000000000000000000000101//11111111111111111111111111111010//11111111111111111111111111111011//int b a 1;//11111111111111111111111111111101//11111111111111111111111111111100//10000000000000000000000000000011//-3printf(b %d\n, b);printf(a %d\n, a);//-5return 0;
}警告⚠ 对于移位运算符不要移动负数位这个是标准未定义的。 例如
int num 10;
num-1;//error4. 位操作符
位操作符有 按位与 | 按位或 ^ 按位异或 注他们的操作数必须是整数。 int main()
{int a 3;int b -5;int c a ^ b;//按位异或 - 对应的二进制位相同为0相异为1//11111111111111111111111111111011 - -5的补码//00000000000000000000000000000011 - 3的补码//11111111111111111111111111111000//11111111111111111111111111110111//10000000000000000000000000001000 - 结果为-8int c a | b;//按位或 - 有1则是1//11111111111111111111111111111011 - -5的补码//00000000000000000000000000000011 - 3的补码//11111111111111111111111111111011 - 结果为-5int c a b;//按位与 - 两个都是1结果才为1//00000000000000000000000000000011 - 3的补码//10000000000000000000000000000101 - 5的原码//11111111111111111111111111111010//11111111111111111111111111111011 - -5的补码//00000000000000000000000000000011 - 3的补码//00000000000000000000000000000011 - 结果为3printf(%d\n, c);return 0;
}一道变态的面试题 编写代码实现不能创建临时变量第三个变量实现两个数的交换。 int main() //三种方法其中第三种是不需要临时变量的
{int a 3;int b 5;//int tmp 0;printf(交换前a%d b%d\n, a, b);//3//a a ^ b;//b a ^ b;//a a ^ b;//2/*a a b;b a - b;a a - b;*///1//tmp a;//a b;//b tmp;printf(交换后a%d b%d\n, a, b);return 0;
}练习 编写代码实现求一个整数存储在内存中的二进制中1的个数。 int main() //思路
{int a 11;a 1;a a 1;//00000000000000000000000000001011//00000000000000000000000000000001//00000000000000000000000000000001return 0;
}
//方法1
#include stdio.h
int main()
{int num 10;int count 0;//计数while (num){if (num % 2 1)count;num num / 2;}printf(二进制中1的个数 %d\n, count);return 0;
}
//思考这样的实现方式有没有问题
//方法2
#include stdio.h
int main()
{int num -1;int i 0;int count 0;//计数for (i 0; i 32; i){if (num (1 i))count;}printf(二进制中1的个数 %d\n, count);return 0;
}
//思考还能不能更加优化这里必须循环32次的。
//方法3
#include stdio.h
int main()
{int num -1;int i 0;int count 0;//计数while (num){count;num num (num - 1);}printf(二进制中1的个数 %d\n, count);return 0;
}
//这种方式是不是很好达到了优化的效果但是难以想到。5. 赋值操作符
赋值操作符是一个很棒的操作符他可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。 int weight 120;//体重 weight 89;//不满意就赋值 double salary 10000.0; salary 20000.0;//使用赋值操作符赋值。 赋值操作符可以连续使用比如 int a 10; int x 0; int y 20; a x y1;//连续赋值 这样的代码感觉怎么样 那同样的语义你看看 x y1; a x; 这样的写法是不是更加清晰爽朗而且易于调试。 复合赋值符
-*/%右 左 |^
这些运算符都可以写成复合的效果。
int main()
{int a 3;a a 3;a 3;a a 3;a 3;a a ^ 5;a ^ 5;return 0;
}6. 单目操作符
6.1 单目操作符介绍 逻辑反操作 ! 负值 - 正值 取地址 sizeof 操作数的类型长度以字节为单位 对一个数的二进制按位取反 ~ – 前置、后置– 前置、后置 间接访问操作符(解引用操作符) (类型) 强制类型转换 * int main()
{int flag 5;if (flag)//flag为真做什么{}if (!flag)//flag为假做什么{}return 0;
}
int main()
{int a 10;int* p a;//取地址操作符*p 20;//解引用操作符(间接访问操作符)//int arr[10];//arr;//取出数组的地址return 0;
}int main()
{int a 10;printf(%d\n, sizeof a);printf(%d\n, sizeof(a));printf(%d\n, sizeof(int));int arr[10] { 0 };printf(%d\n, sizeof(arr));printf(%d\n, sizeof(arr[0]));int sz sizeof(arr) / sizeof(arr[0]);printf(%d\n, sz);return 0;
}int main()
{int a 3;a 10;a 3 15;//errreturn 0;
}int main()
{int a 0;//00000000000000000000000000000000//11111111111111111111111111111111//11111111111111111111111111111110//10000000000000000000000000000001//printf(%d\n, ~a);return 0;
}int main()
{int a 3;//00000000000000000000000000000011//00000000000000000000000000001000a | (1 3);printf(%d\n, a);//00000000000000000000000000001011//11111111111111111111111111110111a (~(1 3));printf(%d\n, a);return 0;
}int main()
{int a 10;//int b --a;//前置--先--后使用int b a--;//后置--先使用后--printf(a%d b%d\n, a, b);//printf(%d\n, a);//前置先后使用//printf(%d\n, a);//int b a;//后置先使用再//int b a,aa1;//printf(a%d b%d\n, a, b);return 0;
}问题代码
int main()
{int a 1;int b (a) (a) (a);printf(%d\n, b);return 0;
}int main()
{float a 3.14f;int b (int)a;//int b int(a);//errreturn 0;
}6.2 sizeof 和 数组
void test1(int arr[])
{printf(%d\n, sizeof(arr));//(2)
}
void test2(char ch[])
{printf(%d\n, sizeof(ch));//(4)
}
int main()
{int arr[10] { 0 };char ch[10] { 0 };printf(%d\n, sizeof(arr));//(1)printf(%d\n, sizeof(ch));//(3)test1(arr);test2(ch);return 0;
}问 1、2两个地方分别输出多少 404该环境为X86X64结果为8 3、4两个地方分别输出多少104该环境为X86X64结果为8 7. 关系操作符
关系操作符 1. 2. 3. 4. 5.! 用于测试“不相等” 6. 用于测试“相等” 这些关系运算符比较简单但要注意在编程的过程中 和不小心写错导致的错误。
8. 逻辑操作符
逻辑操作符有哪些 逻辑与 | | 逻辑或 区分逻辑与和按位与 区分逻辑或和按位或 12-----0 12----1 1|2-----3 1||2----1 int main()
{int a 3 0;// 0//printf(%d\n, a);int a 2 || 0;//1 printf(%d\n, a);return 0;
}逻辑与和或的特点
#include stdio.h
int main()
{int i 0, a 0, b 2, c 3, d 4;i a b d; //结果为1234i a || b || d; //结果为1234printf(a %d\nb %d\nc %d\nd %d\n, a, b, c, d);return 0;
}操作符左边为假右边不再计算 | |操作符左边为真右边不再计算 9. 条件操作符 exp1 ? exp2 : exp3 9.1 练习1
1.
if (a 5)
b 3;
else
b -3;转换成条件表达式是什么样
int main()
{int a 0;int b 0;scanf(%d, a);b ((a 5) ? 3 : -3);printf(%d\n, b);return 0;
}9.2 练习2
使用条件表达式实现找两个数中较大值
int main()
{int a 0;int b 0;scanf(%d %d, a, b);int m (a b ? a : b);printf(%d\n, m);return 0;10. 逗号表达式 exp1, exp2, exp3, …expN 逗号表达式就是用逗号隔开的多个表达式。 逗号表达式从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
int main()
{int a 1;int b 2;int c (a b, a b 10, a, b a 1);//逗号表达式printf(%d\n, c);return 0;
}逗号表达式的另一种好处
a get_val();
count_val(a);
while (a 0)
{a get_val();count_val(a);
}
如果使用逗号表达式改写
while (a get_val(), count_val(a), a 0)
{//业务处理
}11. 下标引用、函数调用和结构成员
11.1 [ ] 下标引用操作符
操作数一个数组名 一个索引值
int main()
{//3 4;int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf(%d\n, arr[5]); //结果为6return 0;
}int arr[10];//创建数组 arr[5] 6;//实用下标引用操作符。 [ ]的两个操作数是arr和5 11.2 ( ) 函数调用操作符
接受一个或者多个操作数第一个操作数是函数名剩余的操作数就是传递给函数的参数
#include string.h
int Add(int x, int y)
{return x y;
}
void test()
{}
int main()
{int len strlen(abc);//()函数调用操作符printf(%d\n, len);int c Add(3, 5);//Add,3,5 都是()的操作数test();return 0;
}11.3 访问一个结构的成员
. 结构体.成员名 - 结构体指针-成员名
//结构成员访问操作符struct S
{int num;char c;
};void test(struct S* ps)
{/*printf(%d\n, (*ps).num);printf(%c\n, (*ps).c);*///- 结构成员访问操作符//结构体指针-结构体成员printf(%d\n, ps-num);printf(%c\n, ps-c);
}
int main()
{struct S s {100, b};//结构体的初始化使用{}//打印结构中的成员数据//printf(%d\n, s.num);//printf(%c\n, s.c);//. 操作符 结构体变量.结构体成员名test(s);return 0;
}12. 表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性决定。 同样有些表达式的操作数在求值的过程中可能需要转换为其他类型。
12.1 隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的。 为了获得这个精度表达式中的字符和短整型操作数在使用之前被转换为普通整型这种转换称为整型提升。 整型提升的意义 表达式的整型运算要在CPU的相应运算器件内执行CPU内整型运算器(ALU)的操作数的字节长度 一般就是int的字节长度同时也是CPU的通用寄存器的长度。 因此即使两个char类型的相加在CPU执行时实际上也要先转换为CPU内整型操作数的标准长 度。 通用CPUgeneral-purpose CPU是难以直接实现两个8比特字节直接相加运算虽然机器指令 中可能有这种字节相加指令。所以表达式中各种长度可能小于int长度的整型值都必须先转 换为int或unsigned int然后才能送入CPU去执行运算。 举个例子
int main()
{char a 3;//00000000000000000000000000000011//00000011-截断char b 127;//00000000000000000000000001111111//01111111-截断char c a b;//00000000000000000000000000000011//00000000000000000000000001111111//00000000000000000000000010000010//10000010 - c//整型提升printf(%d\n, c);//11111111111111111111111110000010//11111111111111111111111110000001//10000000000000000000000001111110//-126return 0;
}b和c的值被提升为普通整型然后再执行加法运算。 加法运算完成之后结果将被截断然后再存储于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 -128~127//unsigned charchar 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;
}实例1中的a,b要进行整形提升,但是c不需要整形提升 a,b整形提升之后,变成了负数,所以表达式 a0xb6 , b0xb600 的结果是假,但是c不发生整形提升,则表 达式 c0xb6000000 的结果是真. 所程序输出的结果是:C 例子2
int main()
{char c 1;char d 2;printf(%u\n, sizeof(c));//1printf(%u\n, sizeof(c));//4printf(%u\n, sizeof(-c));//4printf(%u\n, sizeof(cd));//4return 0;
}例子2中的,c只要参与表达式运算,就会发生整形提升,表达式 c ,就会发生提升,所以 sizeof(c) 是4个字 节. 表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,但是 sizeof© ,就是1个字节. 12.2 算术转换
如果某个操作符的各个操作数属于不同的类型那么除非其中一个操作数的转换为另一个操作数的类型否则操作就无法进行。下面的层次体系称为寻常算术转换。
long doubledoublefloatunsigned long intlong intunsigned intint
如果某个操作数的类型在上面这个列表中排名较低那么首先要转换为另外一个操作数的类型后执行运算。 警告 但是算术转换要合理要不然会有一些潜在的问题。
float f 3.14;
int num f;//隐式转换会有精度丢失12.3 操作符的属性
复杂表达式的求值有三个影响的因素。
操作符的优先级操作符的结合性是否控制求值顺序。 两个相邻的操作符先执行哪个取决于他们的优先级。如果两者的优先级相同取决于他们的结合性。 操作符优先级 一些问题表达式
//表达式的求值部分由操作符的优先级决定。
//表达式1
a*b c*d e*f注释代码1在计算的时候由于比的优先级高只能保证 * 的计算是比早但是优先级并不能决定第三个比第一个早执行。 所以表达式的计算机顺序就可能是
*b
c*d
a*b c*d
e*f
a*b c*d e*f
或者
a*b
c*d
e*f
a*b c*d
a*b c*d e*fc
//表达式2
c --c;注释同上操作符的优先级只能决定自减–的运算在的运算的前面但是我们并没有办法得 知操作符的左操作数的获取在右操作数之前还是之后求值所以结果是不可预测的是有歧义 的。
//代码3-非法表达式
int main()
{
int i 10;
i i-- - --i * ( i -3 ) * i i;
printf(i %d\n, i);
return 0;
}表达式3在不同编译器中测试结果非法表达式程序的结果。
//代码4
int fun()
{static int count 1;return count;
}
int main()
{int answer;answer fun() - fun() * fun();printf(%d\n, answer);//输出多少return 0;
}这个代码有没有实际的问题 有问题 虽然在大多数的编译器上求得结果都是相同的。 但是上述代码 answer fun() - fun() * fun(); 中我们只能通过操作符的优先级得知先算乘法 再算减法。 函数的调用先后顺序无法通过操作符的优先级确定。
//代码5
#include stdio.h
int main()
{int i 1;int ret (i) (i) (i);printf(%d\n, ret);printf(%d\n, i);return 0;
}
//尝试在linux 环境gcc编译器VS环境下都执行看结果。linux 环境gcc编译器结果为10 VS环境下结果为12 所以该代码不可靠有问题 如果这份博客对大家有帮助希望各位给恒川一个免费的点赞作为鼓励并评论收藏一下谢谢大家 制作不易如果大家有什么疑问或给恒川的意见欢迎评论区留言。