---------------------- Java培训、.Net培训、Android培训、IOS培训、期待与您交流! ----------------------
进制是一种表示数值的的形式,电脑存储数据都是以 0 和 1 来存储数据的,因此我们必须了解进制概念。
(1) 十进制 :
1) 用0 - 9 来表示数值,如 5 ,17 ,107 等等
2) 特点 : 数值由0 - 9 之间数字组成,逢九进一
3) 书写格式 : 直接写出十进制数值
(2) 二进制 :
1) 用 0 和 1 来表示数值,如 0b0101 ,0b111 等
2) 特点 : 只有0和1,逢2进1
3) 书写格式:以0b开头
(3) 八进制 :
1) 用 0 - 7 来表示数值,如 07 ,010 等
2) 特点 : 数值由0 - 7 之间数字组成,逢八进一
3) 书写格式:以0开头
(4) 十六进制 :
1) 用 0 - F 来表示数值,如 0x9 ,0xA ,0xFF 等
2) 特点 : 数值由0 - F 之间数字组成,逢十六进一
3) 书写格式:以0x开头
格式符 | 功能 |
%d |
以带符号的十进制形式输出整数 ( 正数不输出正号+ ) |
%o | 以不带符号的八进制形式输出整数 |
%x | 以不带符号的十六进制形式输出整数 |
%u | 以不带符号的十进制形式输出整数 |
%c | 输出一个字符 |
%s | 输出一个或多个字符 |
%f | 以小数形式输出单、双精度,默认输出6位小数 |
%e | 以标准指数形式输出单、双精度数,数字部分小数位数为6位 |
(1) 内存都是以"字节"为存储单位
(2) 每个"字节"都有相应的存储地址(如下图)
(3) 变量的存储地址为该变量的存储空间的首地址
(4) 变量的类型是指针访问内存的寻址方式(比如 : int 类型告诉指针从改变量地址开始一次寻址4个字节)
(5) 复杂变量内存分配符合内存对齐算法
(1) 变量类型分配空间的大小跟编译器有关
16位编译器 | 32位编译器 | 64位编译器 | |
char | 1 |
1 | 1 |
int | 2 | 4 | 4 |
float | 4 | 4 | 4 |
double | 8 | 8 | 8 |
(2) 变量内存分配存储特点
1) 内存寻址方式由大到小
2) 内存中存储的都是二进制形式
3) 变量的地址是该变量的首地址
#include <stdio.h> /* 变量内存分配原则: 从高地址向低地址分配空间给变量 */ int main(){ int a; int b; printf("a address = %p\n",&a); // 打印结果 : a address = 0028FF44 printf("b address = %p\n",&b); // 打印结果 : b address = 0028FF40 system("pause"); return 0; }
(1) 了解负数存储形式前,先学习原码,反码,补码的概念
1) 原码 : 最高位为符号位, 0代表正数,1代表负数,其余位数用来表示数值大小。
如 1 的原码 : 0000 0000 0000 0000 0000 0000 0000 0001
-1的原码 : 1111 1111 1111 1111 1111 1111 1111 1111
2) 反码 : 正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外.
如 1 的反码 : 0000 0000 0000 0000 0000 0000 0000 0001
-1的反码 : 1000 0000 0000 0000 0000 0000 0000 0000
3) 补码 : 原码符号位不变,先将原码减去1,最后数值各位取反
如 1 的补码 : 0111 1111 1111 1111 1111 1111 1111 1111
-1 的补码 : 1000 0000 0000 0000 0000 0000 0000 0001
(2) 十进制正整数求负整数方式:
首先了解二进制加减法运算法则 :
0-0=1-1=0
1-0=1
0-1=1(向高位借位)
十进制运算 : 0 - 1 = -1;
把这条等式转化为二进制来运算 :
0000 0000 0000 0000 0000 0000 0000 0000 // 0
- 0000 0000 0000 0000 0000 0000 0000 0001 // 1
-----------------------------------------------------------------
1 1111 1111 1111 1111 1111 1111 1111 1111
由于整数在内存中只存储32为因此上述结果会舍弃第33位 , 那么 -1 二进制 表示方式 : 1111 1111 1111 1111 1111 1111 1111 1111
(3) 为了方便我们可以把正负整数转化转化为以下规律 :
求一个二进制的相反数 : 符号位+1,数值位为取该数的补码数值位
short == short int
long == long int
long long == long long int
不同编译器对这些类型分配空间规则不一样 :
由于编译器众多,因此需要一个约定来规范 :
short跟int至少为16位(2字节)
long至少为32位(4字节)
short的长度不能大于int,int的长度不能大于long
char一定为为8位(1字节),毕竟char是我们编程能用的最小数据类型
由于这些数据类型都是有符号的,因此它们的取值范围可以根据它们内存中存储的二进制形式进行推敲 :
如 : short 占用 2 个byte ,16位 最高位为符号位,取值范围可以这样表示 : -2^15 ~ (2^15 ) - 1
其它类型以此类推
signed 和 unsigned 主要用来描述该类型的最高位是否用来充当符号位,当然如果不用来充当符号位那么该类型就没有负数部分;
signed : 表示有符号,就是说最高位充当符号位 // signed int == int 取值范围 : -2^31 ~ (2^31 ) - 1
unsigned : 表示没有符号,也就是说最高位不用来充当符号位 // unsigned int 取值范围 : 0~2^32 -1
学习位运算前首先得了解数值而二进制表示方式。
运算法则 : 两个数的二进制位对齐,逐位比较,两个二进位均为1时,结果位才为1,否则为0。
如 9 & 5 = 1
0000 0000 0000 0000 0000 0000 0000 1001
& 0000 0000 0000 0000 0000 0000 0000 0101
-----------------------------------------------------------------
0000 0000 0000 0000 0000 0000 0000 0001
规律 : 二进制中,与1相&就保持原位,与0相&就为0
运算法则 : 两个数的二进制位对齐,逐位比较,二进位有一个为1时,结果位就为1,否则为0。
如 9 | 5 = 13
0000 0000 0000 0000 0000 0000 0000 1001
| 0000 0000 0000 0000 0000 0000 0000 0101
-----------------------------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1101
运算法则 : 两个数的二进制位对齐,逐位比较,(不相同)时,结果为1,否则为0
如 9 ^ 5 = 12
0000 0000 0000 0000 0000 0000 0000 1001
^ 0000 0000 0000 0000 0000 0000 0000 0101
-----------------------------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1100
规律 :
相同整数相^的结果是0。比如5^5=0
多个整数相^的结果跟顺序无关。比如5^6^7=5^7^6
因此得出结论:a^b^a = b
/* 利用^交换两个变量的值 */ int main(){ int a =10; int b =100; a = a ^ b; // a--> a ^ b b = a ^ b; // b--> a ^ b ^b == 10 b = a ^ b; // b--> a ^ b ^ a ^ b ^b ==100 }
运算法则 : 对整数的各二进位进行取反,符号位也取反(0变1,1变0)
如 ~9 = -10
~ 0000 0000 0000 0000 0000 0000 0000 1001
-----------------------------------------------------------------
1111 1111 1111 1111 1111 1111 1111 0110
运算法则 : 把整数a的各二进位全部左移n位,高位丢弃,低位补0。左移n位其实就是乘以2的n次方。
注意 : 由于左移是丢弃最高位,0补最低位,所以符号位也会被丢弃,左移出来的结果值可能会改变正负性
运算法则 :
把整数a的各二进位全部右移n位,保持符号位不变。右移n位其实就是除以2的n次方
为正数时, 符号位为0,最高位补0
为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定
/* 把一个整数打印出它的二进制字符串 num : 所要打印的整数 */ void printBinary(int num){ // 总共要打印多少位数字 int size = sizeof(num) * 8; printf("size = %d\n",size); while ( size > 0 ) { // 每打印4位数字输出一个空格 if ( size % 4 ==0 ) { printf(" "); } size --; printf("%d",(num >> size) & 1); } printf("\n"); }
/* 计算一个二进制字符串的整数值 例如 : 0000 0000 0000 0000 0000 0000 0000 0110 --> 6 参数 : const char *s 所要计算的二进制字符串,字符必须为32位自能包含空格(可选),或则0 和1 返回计算结果 */ int strToInt(const char *s){ // 最总计算的值 int num = 0; int i = 0; unsigned long size = strlen(s); // printf("size = %ld\n",size); char c = 'a'; // 遍历该字符串 while ( size > 0 ) { // 从最后一个字符取出字符来进行检查 c = s[size-1]; if ( c == '0' || c == '1' ){ // 如果是0 和 1 num += ( c == '1' ? 1 << i : 0 ); i++; size--; } else if ( c == ' ' ){ size--; continue; } else { return -1; } } return num; }
---------------------- Java培训、.Net培训、Android培训、IOS培训、期待与您交流! ----------------------
详情请查看:http://edu.csdn.net/heima