2.1 اشاره گر (Pointer)

2.1 اشاره گر (Pointer)

اشاره گر در واقع متغیری است که آدرس حافظه متغیر دیگری را نگه می دارد.

1var ex *T

در بالا ما یک متغیری تعریف کردیم که مقدار داخل آدرس حافظه متغیری T را با استفاده از * را نگه می دارد.

در اشاره گر ۲ تا اپراتور داریم که هر کدام از این ها را در کنار یک متغیر بزاریم به آدرس حافظه یا مقدار داخل خانه حافظه متغیر قبلی دسترسی پیدا می کنیم :

  • & با استفاده از این می توانیم آدرس حافظه متغیر فرضا x را به متغیر دیگری بدهیم (y := &x)
  • * با استفاده از این می توانیم به مقدار داخل خانه حافظه متغیر فرضا x دسترسی پیدا کنیم (x*)

برای اینکه یک اشاره گر تعریف کنیم ۲ روش وجود دارد :

  1. استفاده از تابع new
  2. استفاده از اپراتور & (آمپرسند)

2.1.1 استفاده از تابع new #

یک اشاره گر با استفاده از تابع new بصورت زیر راه اندازی می شود :

1a := new(int)
2*a = 10
3fmt.Println(*a) //Output will be 10

در بالا ما متغیر a را از نوع int اشاره گر تعریف کردیم و سپس داخل آدرس حافظه a مقدار ۱۰ را قرار دادیم.

توجه کنید مقدار پیش فرض یک متغیر از نوع اشاره گر nil می باشد. و اگر جایی شما متغیر از نوع اشاره گر بصورت nil بفرستید ممکن است panic از نوع nil pointer بر بخورید و پروژه کاملا متوقف شود.

2.1.2 استفاده از اپراتور ‘&’ #

برای دریافت آدرس حافظه یک متغیر از & استفاده می شود :

1a := 2
2b := &a
3fmt.Println(*b) //Output will be 2

در زیر یک نمونه کد مثال زدیم توجه کنید :

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6    var b *int
 7    a := 2
 8    b = &a
 9    
10    fmt.Println(b)
11    fmt.Println(*b)
12    b = new(int)
13    *b = 10
14    fmt.Println(*b) 
15}
1$ go run main.go
20xc0000b0018
32
410

در خروجی بالا 0xc0000b0018 آدرس حافظه متغیر a می باشد.

2.1.3 اپراتور * اشاره گر #

اپراتور * برای می توانیم برای عملیات زیر استفاده کنیم :

  • گرفتن مقدار یک آدرس حافظه که با استفاده از اشاره گر ذخیره شده است.
  • تغییر مقدار یک آدرس حافظه
 1package main
 2
 3import "fmt"
 4
 5func main() {
 6	a := 2
 7	b := &a
 8	fmt.Println(a)
 9	fmt.Println(*b)
10
11	*b = 3
12	fmt.Println(a)
13	fmt.Println(*b)
14
15	a = 4
16	fmt.Println(a)
17	fmt.Println(*b)
18}
1$ go run main.go
22
32
43
53
64
74

در بالا a و b* هر دور به یک متغیر دارند اشاره می کنند. بنابرین تغییر مقدار داخل خانه حافظه روی هر دو متغیر تاثیر میگذارد.

2.1.4 اشاره گر به یک اشاره گر #

شما می توانید یک متغیر اشاره گر تعریف کنید و متغیر اشاره گر دیگری را بهش اختصاص دهید.

1a := 2
2b := &a
3c := &b

array

در بالا متغیر a مقدارش ۲ می باشد و آدرسش در حافظه 0xXXXXXX است و در مقدار متغیر b ما اشاره کردیم به آدرس حافظه متغیر a و در ادامه در متغیر c به آدرس حافظه متغیر b اشاره کردیم که آدرسش در حافظه 0xYYYYYY است.

زمانیکه شما بخواهید مقدار c را چاپ کنید کافیه c** را استفاده کنید تا مقدار را ۲ را که داخل خانه حافظه متغیر a قرار دارد را چاپ کند.

به مثال زیر توجه کنید :

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6	a := 2
 7	b := &a
 8	c := &b
 9
10	fmt.Printf("a: %d\n", a)
11	fmt.Printf("b: %x\n", b)
12	fmt.Printf("c: %x\n", c)
13
14	fmt.Println()
15	fmt.Printf("a: %d\n", a)
16	fmt.Printf("*&a: %d\n", *&a)
17	fmt.Printf("*b: %d\n", *b)
18	fmt.Printf("**c: %d\n", **c)
19
20	fmt.Println()
21	fmt.Printf("&a: %d\n", &a)
22	fmt.Printf("b: %d\n", b)
23	fmt.Printf("&*b: %d\n", &*b)
24	fmt.Printf("*&b: %d\n", *&b)
25	fmt.Printf("*c: %d\n", *c)
26
27	fmt.Println()
28	fmt.Printf("&b: %d\n", &b)
29	fmt.Printf("c: %d\n", c)
30	fmt.Printf("*c: %d\n", *c)
31	fmt.Printf("**c: %d\n", **c)
32	
33}
 1$ go run main.go
 2a: 2
 3b: c000018078
 4c: c00000e028
 5
 6a: 2
 7*&a: 2
 8*b: 2
 9**c: 2
10
11&a: 824633819256
12b: 824633819256
13&*b: 824633819256
14*&b: 824633819256
15*c: 824633819256
16
17&b: 824633778216
18c: 824633778216
19*c:824633819256
20**c:2

توجه کنید زبان گو همانند زبان c استفاده از اشاره گر حسابی (Pointer Arithmetic) امکان پذیر نمی باشد و با خطای زیر مواجه خواهید شد :

1package main
2func main() {
3    a := 1
4    b := &a
5    b = b + 1
6}
1$ go run main.go
2invalid operation: b + 1 (mismatched types *int and int)