When we call a function that takes an argument, that argument is copied to the function:

func zero(x int) {
  x = 0
func main() {
  x := 5
  fmt.Println(x) // x is still 5

In this program the zero function will not modify the original x variable in the main function. But what if we wanted to? One way to do this is to use a special data type known as a pointer:

func zero(xPtr *int) {
  *xPtr = 0
func main() {
  x := 5
  fmt.Println(x) // x is 0

Pointers reference a location in memory where a value is stored rather than the value itself. (They point to something else) By using a pointer (*int) the zero function is able to modify the original variable.

The * and & operators

In Go a pointer is represented using the * (asterisk) character followed by the type of the stored value. In the zero function xPtr is a pointer to an int.

* is also used to “dereference” pointer variables. Dereferencing a pointer gives us access to the value the pointer points to. When we write *xPtr = 0 we are saying “store the int 0 in the memory location xPtr refers to”. If we try xPtr = 0 instead we will get a compiler error because xPtr is not an int it's a *int, which can only be given another *int.

Finally we use the & operator to find the address of a variable. &x returns a *int (pointer to an int) because x is an int. This is what allows us to modify the original variable. &x in main and xPtr in zero refer to the same memory location.


Another way to get a pointer is to use the built-in new function:

func one(xPtr *int) {
  *xPtr = 1
func main() {
  xPtr := new(int)
  fmt.Println(*xPtr) // x is 1

new takes a type as an argument, allocates enough memory to fit a value of that type and returns a pointer to it.

In some programming languages there is a significant difference between using new and &, with great care being needed to eventually delete anything created with new. Go is not like this, it's a garbage collected programming language which means memory is cleaned up automatically when nothing refers to it anymore.

Pointers are rarely used with Go's built-in types, but as we will see in the next chapter, they are extremely useful when paired with structs.


← Previous Index Next →