黑马程序员——C语言基础 内存剖析
(以下内容是对黑马苹果入学视频的个人知识点总结)
(一)进制
进制是一种计数的方式,数值的表示形式。有多种进制十进制、二进制、八进制、十六进制。也就是说,同一个整数,我们至少有4种表示方式。
1>二进制
①特点只有0和1,逢2进1
②以0b开头
③一般是二进制文件\指令,变量再内存中存储、
④可以与十进制相互转换
⑤数据范围为0-2的n次方-1
2>八进制
①0--7,逢8进1
②以0开头
③可以很快和二进制转换
3>十六进制
①0--F,逢16进1
②以0x或者大写的0X开头
③可以很好和二进制相互转换
以上是不同进制的输出占位符
1 #include <stdio.h> 2 3 int main() 4 { 5 // 默认情况下,就是十进制 6 int number = 12; 7 8 // 二进制(0b或者0B开头) 9 int number2 = 0B1100; 10 11 // 八进制(0开头) 12 int number3 = 014; 13 14 // 十六进制(0x或者0X开头) 15 int number4 = 0xc; 16 17 // %d以10进制整数的形式输出一个数值 18 printf("%x\n", number); 19 20 return 0; 21 }
(二)变量的内存分析
1>内存以字节为单位,不同的类型占用不同的字节
2>变量的存储
①不仅和类型有关,也和编译器环境有关
②内存由大到小寻址
③只存储二进制形式
④每个变量都有地址:第一个字节的地址就是变量的地址
⑤查看内存地址的两种方式:%x和%p
查看整数的二进制形式
1 #include <stdio.h> 2 3 4 /* 5 1.二进制转十进制 6 0b1100 = 0 * 2的0次方 + 0 * 2的1次方 + 1 * 2的2次方+ 1 * 2的3次方 7 = 0 + 0 + 4 + 8 = 12 8 0b1111 = 1 + 2 + 4 + 8 = 15 9 0b1010 = 10 10 11 2.十进制转二进制 12 67 = 64 + 2 + 1 = 2的6次方 + 2的1次方 + 2的0次方 13 = 0b1000000 + 0b10 + 0b1 14 = 0b1000011 15 16 3.n位二进制的取值范围 17 2位二进制位的取值范围:0~3 0~2的2次方-1 18 3位二进制位的取值范围:0~7 0~2的3次方-1 19 n位二进制位的取值范围:0~2的n次方-1 20 21 22 4个字节 -> 31bit 23 0 000 0000 0000 0000 0000 0000 0000 1100 24 0 ~ 2的31次方-1 25 */ 26 27 int main() 28 { 29 void putBinary(int); 30 31 putBinary(-12); 32 33 putBinary(13); 34 35 return 0; 36 } 37 38 // 输出一个整数的二进制存储形式 39 void putBinary(int n) 40 { 41 int bits = sizeof(n) * 8; 42 while (bits-->0) { 43 printf("%d", n>>bits&1); 44 if (bits%4==0) printf(" "); 45 } 46 printf("\n"); 47 }
3>负数的存储
① 一个字节的取值范围是,负数的表示形式一般以补码存储
不同类型的取值范围
(三)类型说明符
1>short和long
①short和long可以提供不同长度的整型数,也就是可以改变整型数的取值范围。
②如果使用的整数不是很大的话,可以使用short代替int,这样的话,更节省内存开销。
③short跟int至少为16位(2字节)但是long至少为32位(4字节),short的长度不能大于int,int的长度不能大于long,char一定为为8位(1字节),毕竟char是我们编程能用的最小数据类型
④long可以连续用两个在32位环境下一个long占4个字节,两个占8个。64位都占8个字节
2>signed和unsigned
它们的主要区别就是最高位是否要当做符号位,并不会像short和long那样改变数据的长度,即所占的字节数。
①表示有符号,也就是说最高位要当做符号位,所以包括正数、负数和0。其实int的最高位本来就是符号位,已经包括了正负数和0了,因此signed和int是一样的,signed等价于signed int,也等价于int。signed的取值范围是-231 ~ 231 - 1
②表示无符号,也就是说最高位并不当做符号位,所 以不包括负数。在64bit编译器环境下面,int占用4个字节(32bit),因此unsigned的取值范围是:0000 0000 0000 0000 0000 0000 0000 0000 ~ 1111 1111 1111 1111 1111 1111 1111 1111,也就是0 ~ 232 - 1
(四)位运算
1) & 按位与
1>功能是只有对应的两个二进位均为1时,结果位才为1,否则为0。
2> 二进制中,与1相&就保持原位,与0相&就为0
2) | 按位或
1>只要对应的二个二进位有一个为1时,结果位就为1,否则为0。
3) ^ 按位异或
1>当对应的二进位相异(不相同)时,结果为1,否则为0。
2>规律:
①相同整数相^的结果是0。比如5^5=0
②多个整数相^的结果跟顺序无关。比如5^6^7=5^7^6
③因此得出结论:a^b^a = b
4) ~ 取反
对整数a的各二进位进行取反,符号位也取反(0变1,1变0)
5) << 左移
把整数a的各二进位全部左移n位,高位丢弃,低位补0。左移n位其实就是乘以2的n次方。由于左移是丢弃最高位,0补最低位,所以符号位也会被丢弃,左移出来的结果值可能会改变正负性
6)>> 右移
①把整数a的各二进位全部右移n位,保持符号位不变。右移n位其实就是除以2的n次方
②为正数时, 符号位为0,最高位补0
③为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定
#include <stdio.h> int main() { /* 按位与 & 10101010000 00000100000 ------------- 00000000000 10111011 10101101 --------- 10101001 1001 0101 ----- 0001 */ /* 按位或 | 1001 0101 ----- 1101 */ /* 按位异或 ^ 1.相同数值进行异或,结果肯定是0,比如9^9 2.交换 9^5^6 == 9^6^5 3.任何数值跟0进行异或,结果还是原来的数值,9^0 == 9 4.a^b^a == a^a^b == 0^b == b 1001 0101 ----- 1100 1001 1001 ----- 00000 0101 0000 ---- 0101 9^5^9 == 9^9^5 = 0^5 = 5 a^b^a == b */ //printf("%d\n", 9^9); //printf("%d\n", 9 ^ 5); /* 按位取反 ~ ~0000 0000 0000 0000 0000 0000 0000 1001 1111 1111 1111 1111 1111 1111 1111 0110 */ //printf("%d\n", ~9); /* 左移 << 0000 0000 0000 0000 0000 0000 0000 0000 00 0000 0000 0000 0000 0000 0000 100100 9<<1 -> 9 * 2的1次方 == 18 9<<2 -> 9 * 2的2次方 ==36 9<<n -> 9 * 2的n次方 */ //printf("%d\n", 9<<1); /* 右移 >> 0000 0000 0000 0000 0000 0000 0000 0000 000000 0000 0000 0000 0000 0000 0000 10 111111 1111 1111 1111 1111 1111 1111 10 8>>1 -> 8/2 == 4 8>>2 -> 8/2的2次方 == 2 8>>n -> 8/2的n次方 */ printf("%d\n", 8>>3); return 0; }