Mike 发表于 2021-7-18 10:34:03

初识C语言(二)

C语言学习笔记(二)
初识C语言(一)
主要内容:运算符的相关知识
 
一、位运算符
位运算符用来对二进制位进行操作
包括:按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、按位左移(<<)、按位右移(>>)

[*]0 表示假
[*]1 表示真
在讲解之前先把十进制数对应的二进制数给一一列出来
十进制数二进制数100012001030011401005010160110701118100091001 

[*]  & :按位与
int a = 3;
int b = 5;
int c = a & b;
printf("%d\n",c);

运行结果:1
按位与:当上下两位同为真时结果为真,否则结果为假
 

[*]  |   :按位或
int a = 3;
int b = 5;
int c = a | b;
printf("%d\n",c);

运行结果:7
按位或:上下两位只要有一位为真,结果就为真
 

[*]  ^  :按位异或
int a = 3;
int b = 5;
int c = a ^ b;

printf("%d\n",c);

运行结果:6
按位异或:上下两位都为真时结果为假,相异时结果为真
 
二、复合赋值符
包括:=、+=、-=、*=、/=、&=、^=、|=、>>=、<<=

a = a + 10;
a + = 10;上述两句代码是完全等价的,其他的复合赋值符也是同样的用法。
 
三、运算符
包括:单目运算符、双目运算符、三目运算符
(1)单目运算符:
单目运算符是指运算所需变量为一个的运算符,即在运算当中只有一个操作数,又叫一元运算符。
具体有哪些呢?下面就来一一讲解

[*]逻辑非运算符(!)
代码一
int a = 10;
printf("%d\n",a);
printf("%d\n",!a);

运行结果:
10
0代码二
int a = 0;
printf("%d\n",a);
printf("%d\n",!a);

运行结果:
0
1为什么会是这样呢?
前面我们说过了,在C语言中 0 表示假, 1 表示真(实际上所有非0的数都表示真,包括负数)
在代码一中 a 的值是 10 表示真,!a 逻辑取反,所以就为假,因为假对应的是 0 ,故输出结果为 0
在代码二中 a 的值是 0 表示假,!a 逻辑取反,所以就为真,因为真对应的是 1 ,故输出结果为 1 (这里不会是其它的值,就是1,不要误以为它还会是 10 或者其它的数)

[*]符号(-)
[*]正号(+)----这个正号无实际价值啊!
[*]取地址运算符(&)----这个后面再补充
[*]指针运算符(*)----这个后面再补充
[*]长度运算符(sizeof)
sizeof 是运算符,可用于任何变量名、类型名或常量值,当用于变量名(不是数组名)或常量时,它不需要用圆括号。它在编译时起作用,而不是运行时起作用。
何为不需要圆括号?举个栗子
int a = 10;
printf("%d\n",sizeof(a));
printf("%d\n",sizeof a );这就是不需要圆括号,因为a是一个变量名
printf("%d\n",sizeof(int));

运行结果:4当然,这种情况下就不能去圆括号了,否则就报错了
用sizeof来计算数组的长度,(单位:字节)
int arr = {0};
printf("%d\n",sizeof(arr));

运行结果:40       为什么是40呢?
先来了解一下数组吧:


[*]一个数组中的所有元素具有相同的数据类型
[*]将有限个类型相同的变量的集合命名,那么这个名称为数组名
我们把 arr 这个数组定义为 int 类型,我们知道 一个 int 类型大小为 4 个字节,arr 数组里一共有 10 个元素,都为 int 类型,那么整个数组大小就为:4 × 10 = 40,(单位:字节)

所以sizeof(arr)计算的就是数组的总大小,举一反三,我们是不是可以由总大小算出数组元素的个数,上代码:
int sz = 0;//保存元素个数
int arr = {0};
sz = sizeof(arr)/sizeof(arr);
printf("sz = %d\n",sz);

运行结果:sz = 10

[*]按位取反运算符(~)
对一个数的二进制按位取反
int a = 0;
int b = ~a;
printf("%d\n",b);

运行结果:-1什么叫取反,就是:我是 1 他就是 0 ;我是 0 他就偏是 1 

那么现在来解释一下为什么 b 的结果是 -1 ,这里涉及到原码、反码、补码、的知识点(不理解没关系,后面还会讲)
我们定义 0 是一个整型数字,大小为 4 个字节,一个字节 8 个位,4个字节就 32 个位
故a:00000000000000000000000000000000  (32个0,不用去数,我已经数过了!)
取反:11111111111111111111111111111111  (32个1,这个是补码)
负数在内存中存储的时候,存储的是二进制补码
二进制里最高位表示符号位
最高位为0表示正数,最高位为1表示负数

11111111111111111111111111111111  最高位为 1 所以为负数,这里就解决了 -1 中负号的来源
算法:
原码求补码:符号位不变,其它位按位取反,得到反码,反码加 1 得到补码
补码求原码:符号位不变,补码减 1 得到反码,反码按位取反得到原码
 
因为负数在内存中是以二进制补码的形式存储的,所以 11111111111111111111111111111111  是补码,我们要把他转成原码
符号位不变 ,其他按位取反得到反码,所以反码:10000000000000000000000000000000
反码加 1 得到原码,所以原码: 10000000000000000000000000000001
拆解一下就更清楚了:
最高位 1 对应负号 - 
后面 0000000000000000000000000000001 对应的十进制是1,所以 10000000000000000000000000000001 的结果是 -1
这里要补充一点:printf()函数打印一个数时,打印的是这个数的原码

[*]自增运算符(++)
int a = 10;
int b = a++;
printf("a = %d,b = %d\n",a,b);

运行结果:a = 11 ,b = 10这个 a ++ 叫做 后置加加 作用是先使用 a 的值,即先把 a 的值赋给 b ,使 b 的值为 10 ,然后 a 再自增加 1 ,此时 a 的值为 11
int a = 10;
int b = ++a;
printf("a = %d,b = %d\n",a,b);

运行结果:a = 11 , b = 11 这个 ++ a  叫做 前置加加 作用是先让 a 自增加 1 ,此时 a 的值为 11 ,再把 a 的值赋值给 b ,此时 b 的值为 11

[*]自减运算符(--)
int a = 10;
int b = a--;
printf("a = %d,b = %d\n",a,b);

运行结果:a = 9 , b = 10这个 a -- 叫做 后置减减 作用是先使用 a 的值,即先把 a 的值赋给 b ,使 b 的值为 10 ,然后 a 再自减 1 ,此时 a 的值为 9
int a = 10;
int b = --a;
printf("a = %d,b = %d\n",a,b);

运行结果:a = 9 , b = 9这个 -- a  叫做 前置减减 作用是先让 a 自减 1 ,此时 a 的值为 9 ,再把 a 的值赋值给 b ,此时 b 的值为 9

[*](类型):强制类型转换
int a = 3.14;
int a = (int)3.14;   //强制类型转换作用:让某一类型转成另一种类型(一般不建议去写强制转换)
 
 

博文如果有什么错误的地方,大家在评论区给我留言,我会及时纠正,谢谢!


文档来源:51CTO技术博客https://blog.51cto.com/u_15304931/3119176
页: [1]
查看完整版本: 初识C语言(二)