进制转换
1. 十进制转换为n进制:
- 整数部分:短除取余法:
将十进制4563转换为八进制
4563/8...3
570/8...2
71/8...7
8/8...0
1/8...1
0
将十进制数除以要转换的进制数,得数继续除,余数做记录,直到得数为零,取记录的余数的反顺序便是该进制得数;
10723
- 小数部分:短乘取整法:
将十进制数0.3转换为八进制:
0.3
* 8
2.4(取0.4)
8
3.2
8
1.6
8
4.8
8
6.4
8
3.2
显然,该得数在3.2处为死循环,所以取[3.2,3.2)为八进制数部分,即:
0.23146
一般而言,二进制的转换较为漫长,而十六进制的转换较为复杂,所以八进制的存在填补了这个不足,用十进制先过度为八进制,然后再向二,十六进制转换,是常用方法!!
2. n进制转换为十进制:
2047(Q)转换为十进制:
2047Q
= 2*8^3 + 0*8^2 + 4*8^1 + 7*8^0
= 1063
3. 二进制,八进制,十六进制的相互转换:
- 二进制转换为八进制和十六进制:
将10110101.01101转换为八进制:
010 110 101 . 011 010
2 6 5 . 3 2
即:265.32
将1011010101.1001101转换为十六进制:
0010 1101 0101 . 1001 1010
2 D 5 . 9 A
即2D5.9A
以二进制的小数点为中心,分别向左右两侧,逢3(4)位划为一组,不够3(4)位的,以0补足(补零原则:左左右右);再将每一组二进制数转换为与其对应二的八(十六)进制数.
- 八进制,十六进制向二进制数转换:
将263AD转换为二进制:
2 6 3 A D
0010 0110 0011 1010 1101
略…
内存
1. 内存基本概念:
- 计算机表达信息的最小物理单位: 位(二进制单位)比特(bit)
- 字节:1B= 8b
- 1KB = 1024B = 2^10B
- 1MB = 1024KB = 2^20B
- 1GB = 1024MB = 2^30B
- 1TB = 1024GB = 2^40B
- 1PB = 1024TB = 2^50B
- 内存
- 内存是由多个字节组成的一堆,线性,连续的存储空间;
- 字节是内(外)存分配存储空间的基本单位;
- 对内存中的众多字节,计算机系统是通过对字节进行唯一性编号来管理的,编号与字节之间是一一对应关系;
- 一个计算机系统能够管理的内存大小,取决于参与内存中的字节编号的二进制位数;
- 对字节的编号,有三个原则:
(1). 从零开始;
(2). 连续编号;
(3). 二进制编号; - DOS系统采用20位二进制对每一个字节进行编号;即能够管理的内存空间(字节数)为2^20B = 1MB;
- 80386/486采用3个字节对每一个字节进行编号(即采用3*8=24位二进制对每一个字节进行编号);能够管理的内存空间(字节数)为2^24B = 16MB;
- 奔腾计算机的地址总线有32根(即编址空间为4B),能够访问的空间为2^32B = 4GB
M: 内存;
Data Bus: 数据总线,即数据通信信道,用来在CPU与内存之间传送数据,是双向的;
Address Bus: 地址总线,用来对内存中的每一个字节编号,该总线不在内存中!!
2. 软件运行过程与内存管理:
- 操作系统是计算机资源的管理者,即包括内存在内的所有计算机软硬件设备,都是在OS(操作系统)的统一管理下运行的;
- 软件运行前,需先向操作系统申请存储空间;再有足够空间的情况下,OS将分配给该软件一段内存空间供该软件运行;
- 软件分配得到的内存空间,在其运行过程中不在被OS分配给其他软件运行;
- 软件运行完毕后,将提请OS收回其所占用的内存空间,以便再次分配给其他软件使用(这意味着内存是重复使用方式);
- 由上述可知,一个软件运行所被分配到的内存空间,其内存基本上不可能是一无所有的,而是存在着曾经使用过这段空间的软件的残留数据,即垃圾数据;
3. 内存映像图:
理解:
- 在32位系统中,每一个字节由32位的二进制存储,即32个0/1,但是人们为了方便表示,便引入了十六进制的表示方法,而四个位的二进制为一位的十六进制,所以32位的二进制便简化成了32/4 = 8位的十六进制表示,一位十六进制表示四位二进制,而八位的二进制等于一个字节大小,所以两位的十六进制占一个字节大小,所以八位十六进制占四个字节大小;
- 结论:32位的二进制 = 8位的十六进制 = 4个字节!!!
指针
理解:
- 当我们存储一些数据时,这些数据随机的在内存中获得一串地址,例如:
short 12901;这个数据是short类,占两个字节大小,在32位系统中就需要八个字节来存储它(给它的编号),如上图3A 2B 65 32//3A 2B 65 33,开头的四个字节称为首地址; - 而当我们需要把这个数据从内存中读取出来时,就需要这个数据的首地址了,可是首地址又保存在哪里呢;
- 这时便引入了指针,该首地址也保存在内存中,且显然该首地址占用了四个字节(3A 2B 65 32),指针在内存中的地址(编号)也需要保存,所以指针也有指针!!!( * )
- 而指针所指向的空间只是声明了该空间的首地址,完全不清楚该空间所保存的数据的类型这时便引入了指类,即在指针前声明该指针所指空间的数据类型:( int * );指针的指针的数据类型和指针的数据类型一致
1. 指针的两个要素:
- 首地址: 内存中多个(连续)字节中的第一字节编号;
32位系统下每个字节的编号都是32位二进制(即,4B),任何类型的指针都只占用4B存储空间;
- 指类: 指针所指向的空间数据类型;
short ** b; b变量本身的类型是: short **
其指类是: short *
将指针定义中的最后一个*去掉,剩余部分就是该指针变量的"指类".
2. 指针的基本运算(& 和 *):
- & : 取地址运算符:(即,获得某数据的首地址)
-
单目运算符,优先级在单目运算符中比较低,低于++ , - -;
-
语法 —> 左值: “&常量” 和 "&表达式"是语法错误.
-
&&n //错误! &&是逻辑与运算符
-
&(&n) // 错误! ()表达的是表达式或者函数调用
short i, j, *p, *q, **r;
两个值类变量: i 和 j; 三个指针类变量: p, q, r;
p 是指针变量,其指类是 short;
q 的指类是short; r 的指类是short *;
eg : r = &j 是错误的,因为 = 两侧的指类不同,r 的指类是 short * ;而 &j 的指类是 short 类 即: 指针的指类不同, 不能相互运算!
5. 指针类 (常量, 变量, 表达式) 的相互运算, 必须保证指类相同!
int i, j, *p, *q, **r;
p = &i ; // 取出 i 空间的首地址, 赋值给p空间 . 这称为"p 指向 i"
q = &j ; // q 指向 j
r = &p ; // r 指向 p
- *: 运算符:
-
单目运算符, 且与&优先级相同,且与&互为逆运算(连续两个&和 * 运算在一起,相互抵消) eg: *&n < = > n;
-
语法:
short i, j, *p, *q, **r;
p = &i
q = &j
r = &p
- p = 30; //将30赋值给"p所指向的空间".i = 30;
- q = * p + 15; // 将p所指向的空间的值,与十五求和,将和赋值给q所指向的空间;
-
*某的念法:
a .其作为左值,应念成“某所指向的空间”;
b .其在表达式中,应念成:“某所指向的空间值”。 -
若说 “α 指向 β”,就意味着:
a. α 的值,就是β 空间(变量)的首地址(反之亦然)。
b. α 至少是指针类,且其指类一定是β的类型。 -
定义语句中的 * ,不是“指向运算符”,它只是“指针身份”的声明。
char i,j,*p ;
double *p;
*p = 3.14;
- 上述语句会引起所谓的“运行时致命错误”。
- 变量p定义为指针变量,占用4B,但是没有赋初值,其为垃圾数据(其数值不可预料);
- *p = 3.14应念作:将3.14赋值给p所指向的空间,即将3.14赋值给“以p作为首地址,该首地址所指向的空间”
- 总的来说:将3.14赋值给以垃圾值为首地址,所指向的空间!可是这个空间在哪里?没人知道!
- 这个垃圾值的取值范围在0到40亿之间,若落在当前软件所申请的空间范围内,则相安无事,反之,这个操作(*p = 3.14)将对不属于本软件所申请的空间进行操作,会被操作系统认为是“非法访问”,操作系统将强行终止这个软件的执行!
*r = q;
//将q的值赋值给r所指向的空间,而r指向的空间为p的首地址,所以p空间的内容被修改为&j;
*r = &j;
//将j空间的首地址赋值给r所指向的空间;等同于*r = q;
p = q;
//同上;
3. 指针的其他运算:
- p + / - int => p’
- 指针加(减)整型值,其结果是一个指针,且指类不变。
- p + 1 所得到的指针 p‘ 将指向 p 所指向的空间的下一个指类元素空间;
short a[10], *p, *q = &a[7];
// 将a[7]的首地址赋值给q(这里q是定义语句中的,所以只是指针类的声明)
p = &a[0];
// 将 a[0] 赋值给p所指向的空间;
- 指针 + 1所得到的 “字节编号” 的值,与指针原值(原字节编号)相差sizeof(指类)
- 指针 + n 的值与指针原值相差 n 倍的sizeof(指类)。
void main(void)
{
char str[80] = "abcdefghijk", *p;
int *q;
p = &str[3]; //把str[3]的首地址赋值给p;
q = (int *)p; //想要把p的值赋值给q,但p为char类型,q为int类型,所以需要强转,规则为“以左边类型为基准”。现在q, p都指向d
++q; //把q所指向的位置向后加一位,而q的指类为int,占四个字节,所以向后加四位
p = (char *)q;
- p - p’ = > int
- 指针减指针,其结果的绝对值是:两指针所指向的空间之间的指类元素个数。
如图,p,q都是int类型,q* - p* 为 18 - 10 = 8;但是这两个数据的类型为int,一个int类型的数据占4个字节,所以q,p间的数据个数为8 / 4 = 2个,即 q* - p* = 2;