关于编程语言中的内存分配,以及指针(引用)是比较重要的,这里对曾学过的知识结合工作经验做一些梳理。
从计算机底层基础语言到上层高级语言分析:
1.汇编
简要介绍一下汇编程序的 规则定义,编写和执行
DATA SEGMENT ;数据段开始 (变量定义)
word DW ? ;双字 (注意高低位)
str DB 'Hello world!' ;单字 串(数组)
DATA ENDS ;数据段结束
CODE SEGMENT ;代码段开始
ASSUME CS:CODE,DS:DATA ;,ES:EXTRA,SS:STACK 指定数据段 代码段
START: ;主程序起始地址定义
MOV AX,DATA ;寄存器 初始化 数据段
MOV DS,AX
MOV AX,EXTRA
Mov AX,1020H ;立即寻址 直接让AX里面放入数字1020H (ax = 1020)
Mov AX,[1020H] ;直接寻址 让AX里面存放 内存地址1020H 中存的值 指针?引用? (ax = *(1020))
... 数据处理 赋值 计算 编码
MOV,AH,4CH
INT 21H ;通过中断来调用设备接口 输入输出(IO)之类
CODE ENDS ;代码段结束
END START ;结束汇编
这里是些寄存器(固定存储单元,定死的变量空间?)定义了解一下:
AH(8位) AL(8位) AX(16位) (AX和AL又称累加器)
BH(8位) BL(8位) BX(16位) (BX又称基址寄存器,唯一作为存储器指针使用寄存器)
CH(8位) CL(8位) CX(16位) (计数器,CX用于字符串操作,控制循环的次数,CL用于移位)
DH(8位) DL(8位) DX(16位) (数据,DX一般用来做32位的乘除法时存放被除数或者保留余数)
这里主要了解代码段里面的变量寻址的七种方式中的两种
假设一个内存块,分为了两部分,一部分负责加载代码,一部分负责存储值,代码一段一段的加载和执行,代码中用到的变量可能是立即数(基本数据类型? 值本身就是所代表的值),也可能是一个地址(引用?指针?可以通过该地址去找到对应的其他值)
2.C
#include<stdio.h>
int ox = 6;//全局变量
int main(int argc, char **argv){
//赋值或者说复制符号‘=’是比较特殊的啊,=号左边必须是一个’容器‘,右边必须是一个值,
int ax = 1; //把值1复制到ax里,
int bx = ax; //把ax地址里的值复制到bx里,
int *cx = &bx;//变量cx(指针类型) (&取地址) 把bx的地址里的值复制到cx里,
char *st = "hello world";//变量str(指针类型) 定义常量区字符串 并且把常量串的地址复制到st里
chat *ht = (chat*)malloc(sizeof(char)*4);//分配的堆区块 并且把该块的地址复制到ht里
chat *ct = ht;//把ht本身的值复制到ct里,注意这里ht的值是存储的地址,也就是说赋值的是地址
int dx = *cx;//(*取地址里存的值) 把cx本身的值作为地址 去取到的值复制到dx里,所以dx=1
strcpy(ht, "heap");//赋值
/** 内存模型
* 栈(局部变量) 静态区(常量/全局) 堆(malloc)
* cx[1000] 6
* ax[0000] 1 [1020] 'h' [2000] 'h'
* bx[0020] 1 [1030] 'e' [2010] 'e'
* cx[0040] 0002 .'llo worl'.. [2020] 'a'
* st[0060] 1020 [10e0] 'd' [2030] 'p'
* ht[0080] 2000 [10f0] '\0' [2040] '\0'
* ct[00a0] 2000
* dx[00c0] 1
*/
printf(*str);
return 0;
}
有个概念,叫做索引(index),我们通过一个key(地址)去获取到实际的值,一个映射表,数学里的函数,y = f(x),通过x可以获取y,x的存储区域可能并不和y所存储的区域相同,可能是在同一个内存里,可能一个在内存一个在硬盘里,甚至在不同的计算机上,只是寻址有不同的实现方式
3.Java
public class Hello {
int ox = 0;
Hello(){
//Java中 基本数据类型 都有对应的封装对象类型
int ax = 1; //把值1复制到ax里,
int bx = ax; //把ax的值复制到bx里,
int[] ar = {2,3,4};//堆上创建数组块对象 并复制地址到ar里
//Java 会确保一个字符串常量只有一个拷贝!!!
String s1 = "str1";//栈分配引用,静态区分配字符串
String s2 = "str1";//栈分配引用,由于存在该静态串,出于优化指向相同串
String s3 = new String("str1");//栈分配引用,堆分配字符串
Map<String, Object> map = new HashMap<>();//创建一个int-map型变量,把新堆对象的地址复制到变量里
Map map2 = map;//把map的值(引用地址)复制到map2里
map.put("key0", "value0");//调用map地址指向的对象的方法
map2.put("key", "value");//调用map2地址指向的对象的方法 由于map map2的存储的值是相同的,所以操作的都是同一个对象
}
public static void main(String argc[]) {
new Hello();
}
}
/** 内存模型
* 栈(局部变量) 静态区(常量/全局) 堆(new)
* ox[1000] 0 [2000] {2,3,4}
* ax[0000] 1 [1020] 'str1' [2060] 'str1'
* bx[0020] 1 [20a0] HashMap{}
* ar[0040] 2020
* s1[0060] 1020
* s2[0080] 1020
* s3[00a0] 2060
* map[00c0] 20a0
* map2[00e0] 20a0
*/
Java中对于字符串是比较特殊的处理,保证常量池中唯一,字符串不可变(immutable),做了优化处理,
至于引用,个人看来和指针没有什么差别,可以认为是不可变指针