@@ -1,58 +0,0 @@ 09.指针(pointer) | 凤凰涅槃进阶之路

09.指针(pointer)

Abel sun2023年1月6日约 1252 字大约 4 分钟

09.指针(pointer)

1,指针

指针是一个代表着某个内存地址的值。

这个内存地址往往是在内存中存住的两一个变量的值的起始位置。Go语言对指针的支持介于Java语言和C/C++语言之间,它既没有像Java语言那样取消了代码对指针的直接操作的能力,也避免了C/C++语言中由于对指针的滥用而造成的安全和可靠性问题。

Go语言虽然保留了指针,但与其他编程语言不同的是:

  • 默认值nil,没有NULL常量。
  • 操作符"&"取变量地址,"*"通过指针访问目标对象。
  • 不支持指针运算,不支持"->"运算符,直接用"."访问目标成员。
package main

import "fmt"

func main() {
 var a int = 10
 //每个变量有2层含义,变量的内存和变量的地址
 fmt.Printf("a = %d\n", a)   //a,变量的内存,也就是存在内存当中的内容
 fmt.Printf("&a = %v\n", &a) //&a,变量的地址,也就是内存所在内存当中的位置,也叫指针
}

1,指针变量的基本使用

package main

import "fmt"

func main() {
 var a int = 10
 //每个变量有2层含义,变量的内存和变量的地址
 fmt.Printf("a = %d\n", a)   //a,变量的内存,也就是存在内存当中的内容
 fmt.Printf("&a = %v\n", &a) //&a,变量的地址,也就是内存所在内存当中的位置,也叫指针

 //保存某个变量的地址,需要指针类型 *int 保存int的地址, **int则保存*int的地址
 //定义一个变量p,类型为*int
 var p *int
 p = &a //指针变量指向谁,就把谁的地址赋给指针变量
 fmt.Printf("p = %v, &a = %v\n", p, &a)

 *p = 666 //*p操作的不是p的内存,是p所指向的内存(就是a)
 fmt.Printf("*p = %v, a = %v\n", *p, a)

}

以上是针对整形的一个测试,其实,在针对字符串的时候,也是一样的:

package main

import "fmt"

func main() {
 s := "good bay"
 var p *string = &s
 *p = "ciao"
 fmt.Printf("p = %v\n", p)
 fmt.Printf("*p = %v\n", *p)
 fmt.Printf("s = %v\n", s)
}

通过对 *p 赋另一个值来更改“对象”,这样 s 也会随之更改。

2,不要操作没有合法指向的内存

package main

import "fmt"

func main() {
 var p *int
 fmt.Println("p = ", p)

 //*p = 666 //err,因为p没有合法指向。
 var a int
 p = &a //p指向a的指针
 *p = 666
 fmt.Println("a = ", a)
}

上边举了一个没有初始化值的变量,它会被缺省为nil。

但是注意:还不能得到一个文字或常量的地址。

常量:

package main

import "fmt"

func main() {
 const i = 5
 fmt.Printf("&i = ", &i) //err: cannot take the address of i
}

文字:

package main

import "fmt"

func main() {
 fmt.Printf("test = ", &10) //err: cannot take the address of 10
}

所以说,Go 语言和 C、C++ 以及 D 语言这些低级(系统)语言一样,都有指针的概念。但是对于经常导致 C 语言内存泄漏继而程序崩溃的指针运算(所谓的指针算法,如:pointer+2,移动指针指向字符串的字节数或数组的某个位置)是不被允许的。Go 语言中的指针保证了内存安全,更像是 Java、C# 和 VB.NETopen in new window 中的引用。

因此 c = *p++ 在 Go 语言的代码中是不合法的。

2,new函数

函数new(T)将创建一个T类型的匿名变量,所做的是为T类型的新值分配并清零一块儿内存空间,然后将这块内存空间的地址作为结果返回,而这个结果就是指向这个新的T类型值的指针值,返回的指针类型为*T。

1,new函数的使用

package main

import "fmt"

func main() {
 /*之前的传统赋值方式
 a := 10
 var p *int
 p = &a //指向一个合法内存
 *p = 666
 fmt.Println("*p =", *p)
 */

 //p为*int类型,指向匿名int变量
 var p *int
 //new表示分配一个int类型的空间,给到变量p
 p = new(int)
 fmt.Println("*p =", *p) //*p=0

 //同样,也可以使用自动推导类型进行赋值
 q := new(int)
 *q = 777
 fmt.Println("*q =", *q)
}

我们只需要使用new()函数,无需担心其内存的生命周期或怎样将其删除,因为Go语言的内存管理系统会帮我们打理一切(相当于自动GC)。

2,普通变量做函数的参数

package main

import "fmt"

func swap(a, b int) {
 a, b = b, a
 fmt.Printf("swap : a= %d, b= %d\n", a, b)
}
func main() {
 a, b := 10, 20
 swap(a, b) //通过变量进行值的传递(站在变量的角度上)
 fmt.Printf("main : a= %d, b= %d\n", a, b)

}

m_a5a5b59ecd9291857e97028a15160cf8_r

3,指针做函数参数

package main

import "fmt"

func swap(p1, p2 *int) {
 *p1, *p2 = *p2, *p1
}
func main() {
 a, b := 10, 20
 //通过一个函数交换a和b的内容
 swap(&a, &b) //地址传递
 fmt.Printf("main : a= %d, b= %d\n", a, b)
}

m_f7fdd690cd0415d9ae16d73c02f18101_r

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.9.1