go内存地址

go内存地址

  • 内存地址
    在go中获得该变量的内存地址 用&a
func main() {
    a := 43
    b := &a
    fmt.Println("a - ", a)
    fmt.Println("b - ", b)
}

首先声明了一个int类型的变量a,它的值为0,然后又声明了一个a的引用b,b只是a的一个别名而已,并没有占用内存空间。实际上他们是同一个同西,在内存中占用同样的一个存储单元。

  • 变量名是个什么东西 赋的值又是个什么东西
    char a;
    1 变量
    用来标识(identify)一块内存区域,这块区域的值一般是可以更改的,这就是它“变”的由来,但是我们可以通过使用如
    const等一些修饰符号来限定这一内存区域的操作特性(characteristic),即变量的操作特性。用const修饰的使变量不能更改
    的就和常量一样的变量叫做常变量。
    2 变量名
    是一个标识符(identifier),用来指代一块内存区域,即变量,使用变量使我们操作内存以区域(area),以块(block)为单位,
    提高了方便性。
    3 变量名不会出现在机器中
    你的机器代码中,是不会出现变量名的;变量名是给我们程序员操作内存来使用的。
    想想在汇编年代,没有变量名,我们操作内存,都是用地址来直接操作的,还要控制区域大小;当然汇编语言已经有了简·
    单的变量。
    4 赋值操作过程
    对于编译器,它会搜集我们的变量名,比如我们定义了一个全局的int a;那么编译器都为我们做了什么呢?
    它会为程序预留4个字节的空间(假设在32位平台),并把我们的变量名“a”保存进符号表,并用这个符号表的索引对应实
    际的空间
    如果下面出现b = a;那么它就会根据符号表找到变量的真正的物理位置,取得它的值,赋给b。
    这是写编译器需要做的,我们需要建立符号表。
    但是实际在汇编层次上,操作的都是地址而已,不存在任何名称了。
    1、a 表示一块内存空间 表示本身的值
    2、&a 表示当前内存空间的地址 值所对应的地址
    那么指针变量就具有3种形态:
    1、a 表示指针a对应的内存空间(可以说就是指针本身的值)
    2、&a 表示当前指针对应的内存空间的首地址(存放指针的地址) 指针就是一个地址
    3、*a 表示指针a所指向的变量对应的整个内存空间。(指针指向的空间)

  • 指针变量 普通变量 内存 和地址的全面对比
    1 内存
    是什么,内存是实实在在的硬件,可以存数据,运行时的数据全放在里面
    想想一点,内存就像一个个的小个子,每个格子的带下是一个一个字节,可以存放一个字节的数据
    2 地址
    地址是内训的一个表标识,每一个地址度对应一个内训,所以内存和地址一一对相应
    3 普通变量
    如 char a; 就是一个普通变量。普通变量a其实是语言本身创造了,是为了更方便的表示内存。我们对a进行访问其实就
    是直接对内存进行访问。至于a表示的内存的地址是多少,程序员一般不用关心。编译器会自动分配地址,也就是常说的
    为a分配一个地址。如果想知道a的地址也可以通过&a得知。
    4 指针变量
    他和普通变量的区别在于,普通变量是和一块内存空间关联。而指针变量却是和两块内存空间想关联:

5 go中所有的都是按值传递,对于复杂类型,传的是指针的拷贝

     func main() {
    var m map[int]string = map[int]string{
        0: "0",
        1: "1",
    }
    mm := m
    fmt.Printf("%p\n", &m)  //0xc42002a028
    fmt.Printf("%p\n", &mm) //0xc42002a030
    fmt.Println(m)          // map[0:0 1:1]
    fmt.Println(mm)         //map[1:1 0:0]
    changeMap(m)
    fmt.Printf("%p\n", &m)  //0xc42002a028
    fmt.Printf("%p\n", &mm) //0xc42002a030
    fmt.Println(m)          //map[2:2 0:0 1:1]
    fmt.Println(mm)         //map[0:0 1:1 2:2]
    }
    func changeMap(mmm map[int]string) {
    mmm[2] = "2"
    fmt.Printf("changeMap func %p\n", mmm) //changeMap func 0xc420014150
   }

直接传指针 也是传指针的拷贝

func main() {
    var m map[int]string = map[int]string{
        0: "0",
        1: "1",
    }
    mm := m
    fmt.Printf("%p\n", &m)  //0xc42002a028
    fmt.Printf("%p\n", &mm) //0xc42002a030
    fmt.Println(m)          // map[0:0 1:1]
    fmt.Println(mm)         //map[1:1 0:0]
    changeMap(&mm)
    fmt.Printf("%p\n", &m)  //0xc42002a028
    fmt.Printf("%p\n", &mm) //0xc42002a030
    fmt.Println(m)          //map[2:2 0:0 1:1]
    fmt.Println(mm)         //map[0:0 1:1 2:2]
}
func changeMap(mmm *map[int]string) {
    mmm = nil
    fmt.Printf("changeMap func %p\n", mmm) //changeMap func 0xc420014150
}

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 2,565评论 3 44
  • 多线程、特别是NSOperation 和 GCD 的内部原理。运行时机制的原理和运用场景。SDWebImage的原...
    LZM轮回阅读 1,490评论 0 12
  • __block和__weak修饰符的区别其实是挺明显的:1.__block不管是ARC还是MRC模式下都可以使用,...
    LZM轮回阅读 2,414评论 0 6
  • 因为《我的职业是小说家》而关注村上春树的作品,尤为好奇他的长篇小说。于是,我翻开了《1Q84》。 每次开始读一本新...
    史妍阅读 118评论 0 0
  • 如何让我原谅,穷凶极恶的你。 你甚至没给我机会让我原谅你包容你再次接受你。 我把快乐都分给了你,悲伤全都留给我自己...
    顾凯风阅读 260评论 12 5