摘要:操作符的两个操作数必须为整数。函数调用用作为函数调用操作符。访问一个结构的成员结构体成员名结构体指针成员名还是熟悉的栗子在之前的博客请回答语言初识语言下入门的结构体出现过的栗子名字图鉴编号身高重量属性类型
学习操作符之前我们先对操作符分类,还和之前的初始c语言中一样
+ - * / %
算数操作符本身很简单,不过有几个注意事项
%
操作符之外,其他的几个操作符可以作用于整数和浮点数。/
操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。%
操作符的两个操作数必须为整数。返回的是整除之后的余数。 int ret= 10 % 3;//% -- 取模(余) int ret = 10 / 3;//除法 -- 商 //当 /两端都是整数的时候,执行的都是整数的除法,两端只要有一个是浮点数,执行的就是浮点数的除法 double ret2 = 10 / 3.0;//想得到小数,必须保证除数或者被除数里面至少有一个是浮点数
移位操作符这里就涉及了把一个整数化为二进制位,每一位的权重相当于2的1次方,相当于假如有四个1,则1 1 1 1每个1都表示不同的权重
第4位 | 第3位 | 第2位 | 第1位 |
---|---|---|---|
8 | 4 | 2 | 1 |
此外我们还得搞清楚整数的三种二进制表达形式
原码
反码
补码
对于整数的3种形式我们有这样一个结论:
下面对一个整数5来举例
再对-5来举例
从这个例子我们可以看到
原码在第32位中的0和1用来表示符号位,0表示正数,1表示负数,反码同样
反码相当于原码的符号位不变,其他位按位取反得到的就是反码
补码就是反码最低位+1
用VS调试看内存我们就可以直观看到
这里的ffff
就是16进制的-1也就是二进制下32个1,因为16进制下一个f
相当于15,因此说明内存存储的方式是利用补码
总结一下:
- 一个整数在被存入内存时,存储方式是利用的补码
- 打印或者使用的时候,利用的是原码
为什么这么规定呢?这涉及到加法器和减法器的原理,后面再展开
移位规则:
- 左边抛弃、右边补0
int main(){ int a = 5; int b = a << 2; printf("%d/n",a); printf("%d/n", b); return 0;}
注:当然a是不会被改变的
再举个负数的例子:
int main(){ int a = -5; int b = a << 2; printf("%d/n",a); printf("%d/n", b); return 0;}
负数左移之后,打印出来是多少?
过程是先把-5补码左移2位,然后按照负数的规律转换成原码,打印的时候是打印原码结果
移位规则:
有点不同,稍微复杂
首先我们思考一下右移运算本身分两种:
左边用0填充,右边丢弃
左边用原该值的符号位填充,右边丢弃
到底如何移动,取决于编译器的不同,我们常用的编译器是算术右移
比如说VS2019
注:这里的前提是在VS2019中,也即算术移位的前提下
int main(){ int a = -5; int b = a >> 1; printf("%d/n",a); printf("%d/n", b); return 0;}
具体过程就不细给了,按照规则,和左移稍微有一点区别
注:
对于移位运算符,不要移动负数位,这个是标准未定义的。
int num = 10;num>>-1;//error
已知位操作符有:
& //按位与| //按位或^ //按位异或
注:他们的操作数必须是整数。
问:位操作符用哪种二进制位储存形式进行运算?
答:因为都是内存运算,所以都是用的补码
位操作符简单来说就是两个整数的每一位之间互相比较
输入a | 输入b | 结果 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 0 |
0 | 1 | 0 |
1 | 1 | 1 |
看示例
int main(){ int a = 3; int b = -5; int c = a & b; printf("%d", c); return 0;}
输入a | 输入b | 结果 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 1 |
int main(){ int a = 3; int b = -5; int c = a | b; printf("%d", c); return 0;}
两个整数的二进制位互相异或,其中二进制位
相同为0
相异为1
输入a | 输入b | 结果 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 0 |
int main(){ int a = 3; int b = -5; int c = a ^ b; printf("%d", c); return 0;}
int main(){ int num1 = 1; int num2 = 2; printf("%d/n",num1 & num2); printf("%d/n", num1 | num2); printf("%d/n", num1 ^ num2); return 0;}
不能创建临时变量(第三个变量),实现两个数的交换。
3个解法:
int main(){ int a = 3; int b = 5; //1 int c = 0;//临时变量 printf("交换前: a=%d b=%d/n", a, b); c = a; a = b; b = c; //2 a = a + b; b = a - b; a = a - b; //3 - 异或 a = a ^ b; b = a ^ b;//a ^ b ^ b a = a ^ b;//a ^ b ^ a printf("交换后: a=%d b=%d/n", a, b); return 0;}
可以发现第一个解法不符合要求,因为要创建临时变量,剩下两个方法可以巧妙解决,其中第三个方法最为巧妙,巧妙使用异或实现转换,可以尝试化成二进制举例验证一下
编写代码实现:求一个整数存储在内存中的二进制中1的个数。
想法:
我们说如果由一个数a
&
1,那么就能得出这个数字二进制最低位是0还是1那么如果我循环中不断<<1再&1就可以计算出一个整数有几个1
//方法1//解决不了负数#include 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 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;}//这个方法还能更加优化//方法3:#include int main(){ int num = 0; int i = 0; int count = 0;//计数 scanf("%d", &num); while (num) { count++; num = num & (num - 1); } printf("二进制中1的个数 = %d/n", count); return 0;}//这种方式很好,达到了优化的效果,但是难以想到。
赋值操作符可以改变之前的赋值
int weight = 120;//体重weight = 99;//不满意就赋值double salary = 10000.0;//工资salary = 20000.0;//使用赋值操作符赋值。
当然,赋值操作符可以连续赋值,但不是很建议这么写
a=x=y=100;
当然:常量不能赋值
##4.1 复合赋值符
+=-=*=/=%=>>=<<=&=|=^=
这些运算符都可以写成复合的效果
int x = 0;x = x+10;//普通x += 10;//复合赋值//其他运算符一样的道理。这样写更加简洁。
已知单目操作符有:
! //逻辑反操作- //负值+ //正值& //取地址sizeof //操作数的类型长度(以字节 为单位)~ //对一个数的二进制按位取反-- //前置、后置--++ //前置、后置++* //间接访问操作符(解引用操作符)(type) //强制类型转换
很多在之前的初识c语言中都已经讲过,这里挑几个记一下关键点
关于sizeof其实我们之前也已经见过了,可以求变量(类型)所占空间的大小。
常见的使用
有求数组的长度:
int sz=sizeof(arr)/sizeof(arr[0]);
有求数组的大小
int arr[10]= {1,2,3,4,5,6};printf("%d/n",sizeof(arr));//40字节---4*10
有求int类型数组或一个int的大小
printf("%d/n",sizeof(int [10]));//40字节---4*10printf("%d/n",sizeof(int));//4
小栗子:
void test1(int arr[]){ printf("%d/n", sizeof(arr));//(3)}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));//(2) test1(arr); test2(ch); return 0;}
注意从函数中传过来的是指针,所以
sizeof
测的是 指针变量的大小,而主函数里面测的是整个数组中的大小
~
按位取反int main(){ int a = 0; //~ 按(内存中补码的2进制)位取反 //00000000000000000000000000000000 //11111111111111111111111111111111 - 补码 //11111111111111111111111111111110 - 反码 //10000000000000000000000000000001 - 原码 --> -1 printf("%d/n", ~a); return 0;}
有多组输入的时候
while(~scanf("%d%d",&n,&m);
++ --
//++和--运算符//前置++和--int main(){ int a = 10; int x = ++a; //先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。 int y = --a; //先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10; return 0;}//后置++和--int main(){ int a = 10; int x = a++; //先对a先使用,再增加,这样x的值是10;之后a变成11; int y = a--; //先对a先使用,再自减,这样y的值是11;之后a变成10; return 0;}
注:注意值的变化
关系操作符:
>>=<<=!= ==
小结
还是不要搞错
=
和==
逻辑操作符有哪些:
&& 逻辑与|| 逻辑或
区分逻辑与和按位与
区分逻辑或和按位或
1&2----->01&&2---->11|2----->31||2---->1
举个栗子:
int main(){ int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++;//第一次结果 i = a++ || ++b || d++;//第二次结果 printf("a = %d/n b = %d/n c = %d/nd = %d/n", a, b, c, d); return 0;}
- 第一次的结果是:1 2 3 4
因为&&只要前面算出有0就不算后面的执行了,所以a后置加加->a为1,而b和d不执行
int main(){ int i = 0, a = 1, b = 2, c = 3, d = 4; i = a++ && ++b && d++; printf("a = %d/nb = %d/nc = %d/nd = %d/n", a, b, c, d); return 0;}
倘若这样一改就是2 3 3 5了
- 第二次的结果是:1 3 3 4
因为算到++b的时候已经是真了,所以d++就不算下去了,于是自增的只有a和b
小结:逻辑操作符只关注真与假
&&在遇到0(假)之后就不算后面的执行了
||肯定是遇到1(真)之后
exp1 ? exp2 : exp3
之前就写过两数之间的最大值
max = (a > b ? a : b);
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
小栗子
int a = 1;int b = 2;int c = (a>b, a=b+10, a, b=a+1);
应该从左到右依次执行,因为逗号表达式不只是算最后一个逗号里面的语句最后c应该是13
int arr[10];//创建数组arr[9] = 10;//实用下标引用操作符。
比如说我想要打印数组中下标为8的数
int main(){ int arr[10]={1,2,3,4,5,6,7,8,9,10}; printf("%d",arr[7]);//[]体现了下标引用操作符的作用 printf("%d",7[arr]);//一般不用,没用的小知识增加了 return 0;}
计算机在计算的时候是arr[7]->*(arr+7)->7[arr]
所以7[arr]也能符合要求
void test1(){ printf("函数调用test1()/n");}void test2(const char* str){ printf("%s/n", str);}int main(){ test1(); //用()作为函数调用操作符。 test2("Strength in Numbers");//用()作为函数调用操作符。 return 0;}
.
结构体.成员名
->
结构体指针->成员名
还是熟悉的栗子:
在之前的博客请回答c语言-初识c语言(下)【入门】的17.结构体出现过的栗子
struct Pokemon{ char name[20];//名字 int id;//图鉴编号 float height; //身高 float weight;//重量 char fighting_type[20]; //属性 char species[15]; //类型};int main(){ struct Pokemon pikachu = { "Pikachu",25
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/123362.html
摘要:尽管如此,还具有高级的数据类型和灵活性。它配备了大量的标准模块,可用于程序库。一些模块提供如下功能通过这些很赞的特性,瞬时化身为面向过程的语言。开发者可以便捷地将解释器连接到一个使用编写的应用程序,并能随时用作扩展。下一部分会继续分享。 【编者按】本文作者是 Abhishek Jaiswal ,擅长 .NET、C#、Python 等多种语言的技术控。本文中,作者通过活泼有趣的口吻向大家...
摘要:年月宣布支持时间延长到年。更详细的发布列表参阅官网的版本号分为三段,形如。其中表示大版本号,一般当整体重写,或出现不向后兼容的改变时,增加表示功能更新,出现新功能时增加表示小的改动如修复了某个,只要有修改就增加。年公司正式发布。 < 返回索引页 Python语言简介 Python介绍及发展 介绍 Python 官方网站:https://www.python.org/, 大家可以到此处下...
摘要:有超过亿用户,可谓是程序员解惑神站。问答小组允许成员提问并回答其它成员提出的问题,很像。是新手学习和编程的理想网站。目前有万多注册用户,帮助程序员度过关卡。是开发人员的社交网站,是一个适合查询各种编程语言和实战技术的网站。 ...
摘要:如果在学习过程中有什么问题可以关注我公众号琉忆编程库给我留言。有兴趣可以深入学习最后附上学习的知识结构图谱,可以按着下面的这个知识结构图进行学习不一定完整,更多资料,面试题,都可以关注公众号琉忆编程库获取。 你好,是我——琉忆。PHP程序员面试系列图书作者。 作为一名PHP开发者过来人,也是经历了菜鸟到老手的过程,在此给那些想学PHP的同学指条路,即使你是转行学PHP一样可以学会PHP...
阅读 2284·2021-11-15 11:38
阅读 2406·2021-11-15 11:37
阅读 2512·2021-08-24 10:00
阅读 2881·2019-08-30 15:56
阅读 1233·2019-08-30 15:53
阅读 3665·2019-08-29 18:43
阅读 2900·2019-08-29 17:01
阅读 3224·2019-08-29 16:25