Welcome to tutorial no. 15 in Golang tutorial series.

In this tutorial we will learn how pointers work in Go and we will also understand how Go pointers differ from pointers in other languages such as C and C++.

This tutorial has the following sections.

What is a pointer?

Declaring pointers

Zero value of a pointer

Creating pointers using new function

Dereferencing a pointer

Passing pointer to a function

Returning pointer from a function

Do not pass a pointer to an array as a argument to a function. Use slice instead.

Go does not support pointer arithmetic

What is a pointer?

A pointer is a variable which stores the memory address of another variable.

In the above illustration, variable b has value 156 and is stored at memory address 0x1040a124 . The variable a holds the address of b . Now a is said to point to b .

Declaring pointers

*T is the type of the pointer variable which points to a value of type T.

Lets write a program which declares a pointer.

package main import ( "fmt" ) func main() { b := 255 var a *int = &b fmt.Printf("Type of a is %T

", a) fmt.Println("address of b is", a) }

Run in playground

The & operator is used to get the address of a variable. In line no. 9 of the above program we are assigning the address of b to a whose type is *int . Now a is said to point to b. When we print the value in a , the address of b will be printed. This program outputs

Type of a is *int address of b is 0x1040a124

You might get a different address for b since the location of b can be anywhere in memory.





Zero value of a pointer

The zero value of a pointer is nil .

package main import ( "fmt" ) func main() { a := 25 var b *int if b == nil { fmt.Println("b is", b) b = &a fmt.Println("b after initialization is", b) } }

Run in playground

b is initially nil in the above program and then later it is assigned to the address of a. This program outputs

b is <nil> b after initialisation is 0x1040a124

Creating pointers using the new function

Go also provides a handy function new to create pointers. The new function takes a type as argument and returns a pointer to a newly allocated zero value of the type passed as argument.

The following example will make things more clear.

package main import ( "fmt" ) func main() { size := new(int) fmt.Printf("Size value is %d, type is %T, address is %v

", *size, size, size) *size = 85 fmt.Println("New size value is", *size) }

Run in playground

In the above program, in line no. 8 we use the new function to create a pointer of type int . This function will return a pointer to a newly allocated zero value of the type int . The zero value of type int is 0 . Hence size will be of type *int and will point to 0 i.e *size will be 0 .

The above program will print

Size value is 0, type is *int, address is 0x414020 New size value is 85

Dereferencing a pointer

Dereferencing a pointer means accessing the value of the variable which the pointer points to. *a is the syntax to deference a.

Lets see how this works in a program.

package main import ( "fmt" ) func main() { b := 255 a := &b fmt.Println("address of b is", a) fmt.Println("value of b is", *a) }

Run in playground

In line no 10 of the above program, we deference a and print the value of it. As expected it prints the value of b. The output of the program is

address of b is 0x1040a124 value of b is 255

Lets write one more program where we change the value in b using the pointer.

package main import ( "fmt" ) func main() { b := 255 a := &b fmt.Println("address of b is", a) fmt.Println("value of b is", *a) *a++ fmt.Println("new value of b is", b) }

Run in playground

In line no. 12 of the above program, we increment the value pointed by a by 1 which changes the value of b since a points to b. Hence the value of b becomes 256. The output of the program is

address of b is 0x1040a124 value of b is 255 new value of b is 256

Passing pointer to a function

package main import ( "fmt" ) func change(val *int) { *val = 55 } func main() { a := 58 fmt.Println("value of a before function call is",a) b := &a change(b) fmt.Println("value of a after function call is", a) }

Run in playground

In the above program, in line no. 14 we are passing the pointer variable b which holds the address of a to the function change . Inside change function, value of a is changed using dereference in line no 8. This program outputs,

value of a before function call is 58 value of a after function call is 55

Returning pointer from a function

It is perfectly legal for a function to return a pointer of a local variable. The Go compiler is intelligent enough and it will allocate this variable on the heap.

package main import ( "fmt" ) func hello() *int { i := 5 return &i } func main() { d := hello() fmt.Println("Value of d", *d) }

Run in playground

In line no. 9 of the program above, we return the address of the local variable i from the function hello . The behavior of this code is undefined in programming languages such as C and C++ as the variable i goes out of scope once the function hello returns. But in the case of Go, the compiler does a escape analysis and allocates i on the heap as the address escapes the local scope. Hence this program will work and it will print,

Value of d 5

Do not pass a pointer to an array as a argument to a function. Use slice instead.

Lets assume that we want to make some modifications to an array inside the function and the changes made to that array inside the function should be visible to the caller. One way of doing this is to pass a pointer to an array as an argument to the function.

package main import ( "fmt" ) func modify(arr *[3]int) { (*arr)[0] = 90 } func main() { a := [3]int{89, 90, 91} modify(&a) fmt.Println(a) }

Run in playground

In line no. 13 of the above program, we are passing the address of the array a to the modify function. In line no.8 in the modify function we are dereferencing arr and assigning 90 to the first element of the array. This program outputs [90 90 91]

a[x] is shorthand for (*a)[x]. So (*arr)[0] in the above program can be replaced by arr[0]. Lets rewrite the above program using this shorthand syntax.

package main import ( "fmt" ) func modify(arr *[3]int) { arr[0] = 90 } func main() { a := [3]int{89, 90, 91} modify(&a) fmt.Println(a) }

Run in playground

This program also outputs [90 90 91]

Although this way of passing a pointer to an array as a argument to a function and making modification to it works, it is not the idiomatic way of achieving this in Go. We have slices for this.

Lets rewrite the same program using slices.

package main import ( "fmt" ) func modify(sls []int) { sls[0] = 90 } func main() { a := [3]int{89, 90, 91} modify(a[:]) fmt.Println(a) }

Run in playground

In line no.13 of the program above, we pass a slice to the modify function. The first element of the slice is changed to 90 inside the modify function. This program also outputs [90 90 91] . So forget about passing pointers to arrays around and use slices instead :). This code is much more clean and is idiomatic Go :).

Go does not support pointer arithmetic

Go does not support pointer arithmetic which is present in other languages like C and C++.

package main func main() { b := [...]int{109, 110, 111} p := &b p++ }

Run in playground

The above program will throw compilation error main.go:6: invalid operation: p++ (non-numeric type *[3]int)

I have created a single program in github which covers everything we have discussed.

Thats it for pointers in Go. Have a good day.

Next tutorial - Structs



