注:本文以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
}