Part 15: Pointers

Welcome to tutorial no. 15 in Golang tutorial series.

What is a pointer

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

Pointers in Go

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 some code.

package main

import (  
    "fmt"
)

func main() {  
    b := 255
    var a *int = &b
    fmt.Printf("Type of a is %T\n", a)
    fmt.Println("address of b is", a)
}

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)
    }
}

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

b is <nil>  
b after initialisation is 0x1040a124  

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)
}

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)
}

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)
}

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  

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 also 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)
}

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)
}

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)
}

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.

package main

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

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 - Structures