Skip to content

Commit a9e0c94

Browse files
committed
Pointer
1 parent 8be1762 commit a9e0c94

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

docs/golang/core/basic/pointer.md

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
---
2+
order : 8
3+
---
4+
# 8. 指针
5+
6+
在 C/C++ 中提供了指针这种类型,可以直接操作内存数据,在某些应用场景下非常实用。Golang 中也提供了指针,可以利用指针来简化一些任务的执行。虽然 Golang 提供了指针,但是由于操作指针的风险较大,考虑到这一点,Golang 同时也限制了指针的使用。
7+
8+
9+
::: danger 指针是什么?
10+
指针是一个特殊类型的变量,用来存储其他变量的内存地址。指针变量指向一个内存地址,通过这个地址可以间接访问对应的变量。
11+
:::
12+
13+
## 声明指针
14+
15+
在 Golang 中声明一个指针变量需要使用 * 符号,放在变量名前,表示这是一个指针类型的变量。
16+
17+
```go
18+
var pointer *int // 一个指向整数类型的指针变量
19+
```
20+
21+
## 获取变量地址
22+
23+
获取变量的地址需要使用 & 符号,放在变量名前,表示取该变量的地址。
24+
25+
```go
26+
var num = 10
27+
pointer := &num // pointer 指向变量 num 的内存地址
28+
```
29+
30+
## 访问指针的值
31+
32+
通过 * 操作符,可以访问指针变量所指向的值。
33+
34+
```go
35+
num := 10
36+
37+
ptr := &num
38+
39+
fmt.Println(ptr) // 输出 0x1400012a0b0
40+
fmt.Println(*ptr) // 输出 10
41+
```
42+
43+
## 作为参数
44+
45+
指针变量作为参数进行传递时,本质上还是传递的是指针的副本,只不过该副本中的内容和原指针变量的内容相同,所以通过地址来操作数据时,原数据也会发生改变。
46+
47+
```go
48+
// 交换两个数的值
49+
func swap(i *int, j *int) {
50+
var tmp = *i
51+
*i = *j
52+
*j = tmp
53+
}
54+
55+
func main() {
56+
x := 5
57+
y := 8
58+
59+
fmt.Printf("x : %d, y : %d", x, y) // 输出 x : 5, y : 8
60+
swap(&x, &y)
61+
fmt.Printf("x : %d, y : %d", x, y) // 输出 x : 8, y : 5
62+
}
63+
```
64+
65+
## 指针运算
66+
67+
在 C/C++ 中支持指针运算,可以通过一个指针,访问其指定偏移量的数据,自由度较高。虽然在 Golang 中也提供了指针,但是实际上是禁止了大部分指针运算的,原因是指针运算比较危险,很容易造成系统崩溃。
68+
69+
下面是一段 C语言 的指针运算案例:
70+
71+
```c
72+
#include <stdio.h>
73+
74+
int main() {
75+
int arr[] = {1, 2, 3, 4, 5};
76+
int* p = arr; // 指向数组的第一个元素
77+
78+
// 使用指针遍历数组
79+
for (int i = 0; i < 5; ++i) {
80+
printf("Element %d: %d\n", i, *p);
81+
++p; // 移动指针到下一个元素
82+
}
83+
84+
// 重置指针回到数组的第一个元素
85+
p = arr;
86+
87+
// 使用指针算术运算访问数组的特定元素
88+
p = p + 2;
89+
printf("Third element (using pointer arithmetic): %d\n", *p);
90+
91+
return 0;
92+
}
93+
```
94+
95+
在 C 语言中可以直接进行指针的运算,从而访问指定的数据,但这也就意味着,只要能够拿到对应的数据地址,即可访问,这是极度危险的。
96+
97+
::: danger 使用 unsafe 包进行指针运算
98+
如果你确实需要进行类似于 C/C++ 的指针算术运算,可以使用 unsafe 包。不过,这种方法应谨慎使用,因为它会绕过 Go 语言的内存安全检查,可能导致不可预知的行为。
99+
:::
100+
101+
## 空指针
102+
103+
当一个指针被定义后没有分配到任何变量的时候,它的值为 nil,即空指针
104+
105+
```go
106+
var pointer *int
107+
```
108+
109+
指针变量声明后,默认零值为 nil,即空指针。
110+
111+
**空指针判断**
112+
113+
```go
114+
if pointer == nil {
115+
// 空指针时执行
116+
}
117+
```
118+
119+
## 指针的指针
120+
121+
指针是指向变量内存地址的值,这个值同样也是存储在内存中,存储到内存中的值也必然会占用内存,也会有地址。故有指针的指针。
122+
123+
```go
124+
num := 10
125+
126+
var pointer1 = &num
127+
var pointer2 = &pointer1
128+
```
129+
130+
- pointer1 即为 num 的指针
131+
- pointer2 即为 pointer1 的指针,即指针的指针
132+
133+
::: tip 依次类推,可以有无限指针的循环嵌套
134+
:::
135+
136+
## 指针数组
137+
138+
指针数组本质上是一个数组,只不过数据类型从基本类型变成了指针类型,存储的内容都是指针。

0 commit comments

Comments
 (0)