[指针类型]:内存地址 和 指针变量


golang 中 的 内存地址 和 指针变量。
内存中的每一个具体的区域,均有属于一个它的唯一地址 (编号) 。我们可以通过内存地址,来唯一地定位到一个内存区域,而这个内存区域中本身又是存着某些数据的。这就像我们通过门牌号找到一栋房子,而这个房子里又住着某一家人。

  • 内存地址
package main

import "fmt"

func main() {

	// 定义几个通常意义上的变量
	myInt, myString, myBool := 33, "hello", true
	// 使用普通变量,实际上使用的是"房子里的人",也就是变量存储的值
	fmt.Println(myInt)
	fmt.Println(myString)
	fmt.Println(myBool)
	// 使用取地址符号& , 获取普通变量在内存中的 "门牌号" : 内存地址
	fmt.Println(&myInt)
	fmt.Println(&myString)
	fmt.Println(&myBool)

}


/* [运行结果如下]:########################
33
hello
true        
0xc0000aa058
0xc000088220
0xc0000aa070
####################################### */

  • 指针变量

所谓的指针变量,是一种特殊的变量,它用于存储 "内存地址" 。golang 中定义指针变量,与定义普通变量一样,我们需要指明这个变量对应到的那个数据的数据类型;不同点在于,golang 使用 指针符号 * 来表示这个变量是一个指针变量,它是用来存储地址的。

注意:区分指针变量本身的内存地址(它的门牌号),以及它所保存的内存地址(它存储的值)

package main

import "fmt"

func main() {

	// 定义并赋值几个普通变量
	myInt, myString := 68, "ok"

	// 定义几个指针变量
	var myIntP *int
	var myStringP *string
	// 打印指针变量,就是打印指针变量存储的值。此时没有存储值,故结果为nil
	fmt.Println(myIntP)
	fmt.Println(myStringP)
	fmt.Println()
    
	// 打印指针变量本身的"门牌号",也就是指针变量本身被存储在哪个内存地址中
	fmt.Println(&myIntP)
	fmt.Println(&myStringP)
	fmt.Println()

	// 使用 指针变量 存储 普通变量 的 内存地址,也就是让 指针变量的 "房子" 里 住下一组 "其它人的门牌号" 
	myIntP = &myInt
	myStringP = &myString
        // 打印指针变量,就是打印它存储的值。此时打印的结果是"其它人的门牌号",不再是nil
	fmt.Println(myIntP)
	fmt.Println(myStringP)
	fmt.Println()

}


/* [运行结果如下]:########################

       

0xc000006028
0xc000006030

0xc0000120a8
0xc00004e230
####################################### */

  • 取地址运算[&] 和 取值运算[*]

在golang中,& 是取地址运算符,对某个变量使用 & ,表示获得这个变量的内存地址 (求门牌号) 。* 是取值运算符,对某个内存地址使用 * ,那么就会读取那个内存地址中所存储的数据值 (访问房子里住的人) 。

值得注意的是,由前述2个例子可知,使用变量名,实际上使用的是变量中所存储的值。也就是说:var_nam 等价于 * &var_nam,效果均为访问 var_name 中存储的数据。

  • 使用 指针变量 存储 普通变量的内存地址
package main

import "fmt"

func main() {

	// 定义并赋值2个普通变量
	var a float64 = 123.45
	var b bool = false

	// 定义并赋值2个指针变量
	var myFloatP *float64 = &a // myFloatP 中 存储了 a 的地址值
	var myBoolP *bool = &b     // myBoolP 中 存储了 b 的地址值

	// 通过指针变量访问它所指向的普通变量
	fmt.Println(*myFloatP) // 访问 a地址值 中存储的数据,等价于直接调用a
	fmt.Println(a)
	fmt.Println()
	fmt.Println(*myBoolP) // 访问 b地址值 中存储的数据,等价于直接调用b
	fmt.Println(b)
	fmt.Println()

	// 通过指针变量修改它所指向的普通变量的值
	*myFloatP = 999.999
	*myBoolP = true

	// a和b 的值 确实发生了改变
	fmt.Println(*myFloatP)
	fmt.Println(a)
	fmt.Println()
	fmt.Println(*myBoolP)
	fmt.Println(b)
	fmt.Println()

}



/* [运行结果如下]:########################
123.45
123.45 
       
false  
false  
       
999.999
999.999
       
true   
true  
####################################### */

---to be continue---