GoLang之取地址符&、指针

注:本文以Windos系统上Go SDK1.8进行讲解

1.int取地址符&

变量是一种使用方便的占位符,用于引用计算机内存地址。
Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。
以下实例演示了变量在内存中地址:

func main() {
	var a int
	fmt.Printf("变量的地址: %x\n", &a) //变量的地址: c000016098
	a = 4
	fmt.Printf("变量的地址: %x\n", &a)//变量的地址:  c000016098
}

2.指针声明

一个指针变量指向了一个值的内存地址。
类似于变量和常量,在使用指针前你需要声明指针。指针声明格式如下:
*var-type 为指针类型,var_name 为指针变量名

var var_name *var-type
var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮点型 */

3.int指针使用

指针使用流程:
定义指针变量。
为指针变量赋变量。
访问指针变量中指向地址的值。


func main() {
	var a int = 20 /* 声明实际变量 */
	var ip *int    /* 声明指针变量 */

	ip = &a /* 指针变量的存储地址 */

	/* 使用指针访问变量 */
	fmt.Printf("*ip 变量的值: %d\n", *ip) //*ip 变量的值: 20

	/* 值的地址 */
	fmt.Printf("a 变量的地址是: %p\n", &a) //a 变量的地址是: 0xc000102058

	/* 指针变量里存的地址 */
	fmt.Printf("ip 变量里储存的地址: %p\n", ip) //ip 变量里储存的地址: 0xc000102058

	/* 指针变量的地址 */
	fmt.Printf("ip 变量的地址: %p\n", &ip) //ip 变量的地址: 0xc00012e018

}

4.空指针

当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。


func main() {
	var ptr *int
	if ptr == nil {
		fmt.Println("ptr==nil")
	} else if ptr != nil {
		fmt.Println("ptr!=nil")
	}
	fmt.Println(ptr)
	fmt.Printf("ptr 的值为 : %x\n", ptr)
	/*输出以下:
	ptr==nil
	<nil>
	ptr 的值为 : 0
	*/
}

5.指向指针的指针

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。
当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:
指向指针的指针变量声明格式如下:

var ptr **int;
package main

import "fmt"

func main() {

   var a int
   var ptr *int
   var pptr **int

   a = 3000

   /* 指针 ptr 地址 */
   ptr = &a

   /* 指向指针 ptr 地址 */
   pptr = &ptr

   /* 获取 pptr 的值 */
   fmt.Printf("变量 a = %d\n", a )//输出:变量 a = 3000
   fmt.Printf("指针变量 *ptr = %d\n", *ptr )//输出:指针变量 *ptr = 3000
   fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)//输出:指向指针的指针变量 **pptr = 3000
}

6.三重指针

pt3 - > pto - > ptr - >变量a

package main

import "fmt"
func main(){
    var a int = 5
    //把ptr指针 指向ss所在地址
    var ptr *int = &a
    //开辟一个新的指针,指向ptr指针指向的地方
    var pts *int = ptr 
    //二级指针,指向一个地址,这个地址存储的是一级指针的地址
    var pto **int = &ptr
    //三级指针,指向一个地址,这个地址存储的是二级指针的地址,二级指针同上
    var pt3 ***int = &pto
    fmt.Println("a的地址:",&a,
                "\n 值", a, "\n\n",

                "ptr指针所在地址:",&ptr,
                "\n ptr指向的地址:",ptr,
                "\n ptr指针指向地址对应的值",*ptr,"\n\n", 

                "pts指针所在地址:",&pts,
                "\n pts指向的地址:", pts,
                "\n pts指针指向地址对应的值:",*pts,"\n\n", 

                "pto指针所在地址:",&pto,
                "\n pto指向的指针(ptr)的存储地址:",pto, 
                "\n pto指向的指针(ptr)所指向的地址: " ,*pto, 
                "\n pto最终指向的地址对应的值(a)",**pto,"\n\n",

                "pt3指针所在的地址:",&pt3,
                "\n pt3指向的指针(pto)的地址:",pt3,//等于&*pt3,
                "\n pt3指向的指针(pto)所指向的指针的(ptr)地址", *pt3, //等于&**pt3,
                "\n pt3指向的指针(pto)所指向的指针(ptr)所指向的地址(a):",**pt3, //等于&***pt3,
                "\n pt3最终指向的地址对应的值(a)", ***pt3)


}
/*
执行结果:

a的地址: 0xc00009a008 
 值 5 

 ptr指针所在地址: 0xc000092010 
 ptr指向的地址: 0xc00009a008 
 ptr指针指向地址对应的值 5 

 pts指针所在地址: 0xc000092018 
 pts指向的地址: 0xc00009a008 
 pts指针指向地址对应的值: 5 

 pto指针所在地址: 0xc000092020 
 pto指向的指针(ptr)的存储地址: 0xc000092010 
 pto指向的指针(ptr)所指向的地址:  0xc00009a008 
 pto最终指向的地址对应的值(a) 5 

 pt3指针所在的地址: 0xc000092028 
 pt3指向的指针(pto)的地址: 0xc000092020 
 pt3指向的指针(pto)所指向的指针的(ptr)地址 0xc000092010 
 pt3指向的指针(pto)所指向的指针(ptr)所指向的地址(a): 0xc00009a008 
 pt3最终指向的地址对应的值(a) 5
 */

7.引用变量

在一些开发语言中(比如 C++),对已存在的变量可以声明别名,这种别名称为引用变量。
可以看到 a、b 和 c 都指向相同的内存位置。对 a 的写操作会影响 b 和 c。

include <stdio.h>
 
 int main() {
         int a = 10;
         int &b = a;
         int &c = b;
 
         printf("%p %p %p\n", &a, &b, &c); // 0x7ffe114f0b14 0x7ffe114f0b14 0x7ffe114f0b14
         return 0;
}

8.Go语言没有引用变量

与 C++ 不同,Go 程序中定义的每个变量都占用一个惟一的内存位置。

func main() {
     var a, b, c int
     fmt.Println(&a, &b, &c) // 0x1040a124 0x1040a128 0x1040a12c
}

创建两个共享同一内存位置的变量是不可能的。但是可以创建两个指向同一内存位置的变量,不过这与两个变量共享同一内存位置是不同的。
下面这段代码,b 和 c 都具有相同的值 ,即变量 a 的地址,但 a、c 存储在内存中不同的位置。改变 b 的内容不会影响到 c。

func main() {
         var a int
        var b, c = &a, &a
        fmt.Println(b, c)   // 0x1040a124 0x1040a124
        fmt.Println(&b, &c) // 0x1040c108 0x1040c110
}

9.&使用注意事项

9.1常量不可寻址

在这里插入图片描述

9.2字符串变量可寻址


func main() {
	var s string = "qqqq"
	fmt.Println(&s) //0xc00005a250
}

9.3函数或方法不可寻址

在这里插入图片描述

9.4基本类型字面量不可寻址

在这里插入图片描述