目录

  • 一、指针介绍
  • 1.1 什么是指针?
  • 1.2 指针有什么用?
  • 二、指针的定义
  • 三、指针操作注意事项
  • 3.1 空指针
  • 3.2 操作没有合法指向的内存
  • 3.3 new()函数使用
  • 四、拓展
  • 4.1 指针变量作为函数参数
  • 4.2 切片数组(将数组指针作为函数参数)
  • 4.3 指针数组(数组元素是指针类型)
  • 4.4 切片与指针
  • 4.5 结构体与指针

一、指针介绍

1.1 什么是指针?

  • 指针是一种存储变量内存地址的变量。
  • Go 语言中的指针与 C/C++ 中的指针类似,但是 Go 语言中的指针不能进行指针运算,也不能进行指针类型转换。

1.2 指针有什么用?

在Go语言中,指针是一种特殊的变量,它存储了一个变量的内存地址。通过指针,我们可以直接访问和修改变量的值,而不需要拷贝变量本身,这样可以提高程序的效率。指针在Go语言中有以下几个作用:

  • 传递变量的地址:指针可以作为函数参数,将变量的地址传递给函数,这样函数就可以直接修改变量的值。
  • 动态分配内存:通过指针可以在运行时动态分配内存,这样程序就可以根据需要动态地创建和销毁变量。
  • 访问复杂数据结构:指针可以用于访问复杂的数据结构,如链表、树等,通过指针可以方便地遍历和修改这些数据结构。
  • 函数返回值:指针可以作为函数的返回值,这样函数就可以返回一个指向变量的指针,而不是变量本身,这样可以避免变量拷贝和内存分配的开销。

二、指针的定义

语法:

var 指针变量名称 *指针类型

如下案例:通过指针修改变量的值

package main

import "fmt"

func main() {
	var a int = 100
	var p *int = &a
	// 通过指针修改变量的值
	*p = 666

	fmt.Printf("a变量的值:%v\ta变量的内存地址:%v", a, p)
}

代码输出内容:

a变量的值:666	a变量的内存地址:0xc000018098

三、指针操作注意事项

3.1 空指针

定义完成指针变量后,没有声明任何内存地址,那么就是空指针。

var p *int
	fmt.Println(p)

3.2 操作没有合法指向的内存

没有指向内存地址,直接操作

var p *int
	*p = 666 // 没有指向内存地址,直接操作
	fmt.Println(p)

3.3 new()函数使用

开辟数据类型对应的内存空间,返回值为数据类型指针

var p *int
	p = new(int) //int占用4字节,也就是开辟4字节的内存空间,给p指针变量
	*p = 666
	fmt.Println(p)

四、拓展

4.1 指针变量作为函数参数

在函数内,修改变量的值

package main

import "fmt"

func main() {
	var num int = 100
	EditVariable(&num)
	fmt.Println(num)
}

func EditVariable(p *int) {
	*p = 666
}

代码输出内容:

666

4.2 切片数组(将数组指针作为函数参数)

首先先看下基本操作案例:

package main

import "fmt"

func main() {
	var nums = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	var p *[10]int = &nums // 指针指向nums数组

	fmt.Println(*p)
	fmt.Println((*p)[0]) // []优先级小于* 所以在前面要加()来先计算()内容
	fmt.Println(p[0])    // 等价于上面写法

	// 遍历数组
	fmt.Println("==============================")
	for i := 0; i < len(p); i++ {
		fmt.Println(p[i])
	}
}

代码输出内容:

[1 2 3 4 5 6 7 8 9 0]
1
1
==============================
1
2
3
4
5
6
7
8
9
0

再来看下 数组指针作为函数参数。

package main

import "fmt"

func main() {
	var nums = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	var p *[10]int = &nums // 指针变量指向nums数组
	UpdateArr(p)
	fmt.Println(nums)
}
func UpdateArr(p *[10]int) {
	p[5] += 10
}

代码输出内容:

[1 2 3 4 5 16 7 8 9 0]

4.3 指针数组(数组元素是指针类型)

指针数组指的是一个数组中存储的都是指针(就是内存地址),也就是一个存储了地址的数组。
定义语法:

var 数组名 [下标]*类型
package main

import "fmt"

func main() {
	var nums [2]*int
	a, b := 100, 200
	nums[0] = &a
	nums[1] = &b

	// 输出指针数组内容
	fmt.Println(nums)
	// 输出指针数据内存地址对应的值
	fmt.Println(*nums[0])

	// 循环变量指针数组
	for i := 0; i < len(nums); i++ {
		fmt.Println(*nums[i])
	}
}

代码输出内容:

[0xc000018098 0xc0000180b0]
100
100
200

4.4 切片与指针

定义指针,指向切片,也就是这个指针保存了切片的地址,可以通过地址修改切片中的值。

package main

import "fmt"

func main() {
	s := []int{100, 200, 300, 400}
	var p *[]int = &s

	// 输出下标为0的值,需要优先计算*p,所以这里添加了小括号
	fmt.Println((*p)[0])
	// 修改值
	(*p)[2] = 3666666
	fmt.Println((*p)[2])

	// 变量循环
	fmt.Println("====================")
	for i := 0; i < len(*p); i++ {
		fmt.Println((*p)[i])
	}
}

代码输出内容:

100
3666666
====================
100
200
3666666
400

4.5 结构体与指针

定义指针,指向结构体

package main

import "fmt"

type Class struct {
	id   int
	name string
	age  int
}

func main() {
	var zhangsan Class = Class{100, "zhangsan", 10}
	var p *Class = &zhangsan
	fmt.Println((*p).age)
	fmt.Println(p.age) // 等价于上面写法

	// 通过指针修改结构体成员内容
	p.age = 100
	fmt.Println(p.age)
}

代码输出内容:

10
10
100

结构体指针作为函数参数,在函数中修改结构体内容,会影响到原来的值。

package main

import "fmt"

type Class struct {
	id   int
	name string
	age  int
}

func main() {
	var zhangsan Class = Class{100, "zhangsan", 10}
	var p *Class = &zhangsan

	UpdateStr(p)

	fmt.Println(zhangsan)
}

func UpdateStr(str *Class) {
	str.name = "lisi"
	str.age = 666
}

代码输出内容:

{100 lisi 666}