Pointers in Go

Pointers in Go

In this tutorial, we will discuss pointers in Go Language, and we will also understand how Go pointers differ from pointers in other programming languages such as C and C++.

What is a pointer?

A pointer is a variable that stores the memory address of another variable. Confused? Let me explain. Let’s first understand what a variable is.

Well, Whenever we write any program, we need to store some data/ information in memory. The data is stored in memory at a particular address. The memory addresses look something like 0xAFFFF (That’s a hexadecimal representation of a memory address).

Now, To access the data, we need to know the address where it is stored. We can keep track of all the memory addresses where the data related to our program is stored. But imagine how hard it would be to remember all those memory addresses and access data using them.

That is why we have the concept of variables. A variable is just a convenient name given to a memory location where the data is stored.

A pointer is also a variable. But it’s a special kind of variable because the data that it stores is not just any normal value like a simple integer or a string; it’s a memory address of another variable.

Pointers in Go

In the above example, the pointer p contains the value 0x0001, which is the address of the variable a.

Declaring pointers

A pointer of type T is declared using the following syntax

// A pointer of type T 
var p *T

Where T is the type of the variable that the pointer points to. For example, the following is a pointer of type int.

// A pointer of type int 
var p *int 

The above pointer can only store the memory address of int variables. The zero value of a pointer is nil. That means any uninitialized pointer will have the value nil.

package main

import "fmt"

func main() {
    var p *int
    fmt.Println("p = ", p)
}

Output

p = <nil>

Run in playground

Initializing a Pointer

You can initialize a pointer with the memory address of another variable. The address of a variable can be retrieved using the & operator.

var a = 100 
var p *int = &a

Notice how we use the & operator with the variable a to get its address and then assign the address to the pointer p.

package main

import (  
    "fmt"
)

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

Output

Type of p is *int 
Address of a is 0xc00002c008

Run in playground

Like any other variable in the Go language, the type of a pointer variable is also inferred by the compiler. So you can omit the type declaration from the pointer p in the above example and write it below.

var p = &a

Let’s see a complete example to make things more clear

package main

import (
    "fmt"
)

func main() {
    a := 100
    var p = &a
    fmt.Println("Value stored in variable a = ", a)
    fmt.Println("Address of variable a = ", &a)
    fmt.Printf("Type of p is %T\n", p)
    fmt.Println("Value stored in variable p = ", p)
}

Output

Value stored in variable a =  100 
Address of variable a =  0xc000100010 
Type of p is *int 
Value stored in variable p =  0xc000100010

Run in playground

Dereferencing a Pointer

You can use the * operator on a pointer to access the value stored in the variable that the pointer points to. This is called dereferencing or indirecting

package main

import (
	"fmt"
)

func main() {
	var a = 100
	var p = &a

	fmt.Println("a = ", a)
	fmt.Println("p = ", p)
	fmt.Println("*p = ", *p)
}

Output

a =  100 
p =  0xc00002c008 
*p =  100

Run in playground

You can not only access the value of the pointer variable using the * operator, but you can change it as well.

package main

import (
	"fmt"
)

func main() {
	var a = 100
	var p = &a
	
	fmt.Println("a (before) = ", a)

	// Changing the value stored in the pointed variable through the pointer
	*p = 200

	fmt.Println("a (after) = ", a)
}

Output

a (before) =  100 
a (after) =  200

Run in playground

Creating pointers using the new function

You can also create a pointer using the built-in new() function. The new() function takes a type as an argument, allocates enough memory to accommodate a value of that type, and returns a pointer to it.

package main

import (
	"fmt"
)

func main() {
	ptr := new(int) // Pointer to an `int` type
	*ptr = 100

	fmt.Printf("Ptr = %#x, Ptr value = %d", ptr, *ptr)
}

Output

Ptr = 0xc00002c008, Ptr value = 100

Run in playground

Pointer to Pointer
package main

import (
	"fmt"
)

func main() {
	var a = 100
	var p = &a
	var pp = &p

	fmt.Println("a = ", a)
	fmt.Println("Address of a = ", &a)

	fmt.Println("p = ", p)
	fmt.Println("Address of p = ", &p)

	fmt.Println("pp = ", pp)

	// Dereferencing a pointer to pointer
	fmt.Println("*pp = ", *pp)
	fmt.Println("**pp = ", **pp)
}

Output

a =  100 
Address of a =  0xc000094010 
p =  0xc000094010 
Address of p =  0xc000096018 
pp =  0xc000096018 
*pp =  0xc000094010 
**pp =  100

Run in playground

No Pointer Arithmetic in Go

If you have worked with C/C++, then you must be aware that these languages support pointer arithmetic.

For example, you can increment/decrement a pointer to move to the next/previous memory address. You can add or subtract an integer value to/from a pointer.

You can also compare two pointers using relational operators ==, <, >, etc. But Go language doesn’t support such arithmetic operations on pointers. Any such operation will result in a compile-time error.

However, you can compare two pointers of the same type for equality using the == operator.

package main

import (
	"fmt"
)

func main() {
	var a = 75
	var p1 = &a
	var p2 = &a

	// var p3 = p1 + 1 // invalid operation: p1 + 1 (mismatched types *int and int)

	if p1 == p2 {
		fmt.Println("Both pointers p1 and p2 point to the same variable.")
	}
}

Output

Both pointers p1 and p2 point to the same variable.

Run in playground

Passing pointer to a function
package main

import (
    "fmt"
)

func changeValue(val *int) {
    *val = 15000
}

func main() {
    salary := 10000
    fmt.Println("Value of a before function call is", salary)
    salPtr := &salary
    changeValue(salPtr)
    fmt.Println("Value of a after function call is", salary)
}

Output

Value of a before function call is 10000 
Value of a after function call is 15000

Run in playground

Pointer to a Pointer

It is also possible to create a pointer to a pointer in go language.

a := 10
b := &a
c := &b

c is a pointer to a pointer here. It stores the address of b, which stores the address of a. Double dereferencing using the * operator can be used to print the value at the pointer to pointer. Hence**c will print the value at which 10.

package main

import "fmt"

func main() {
	a := 10
	b := &a
	c := &b

	fmt.Printf("a: %d\n", a)
	fmt.Printf("b: %x\n", b)
	fmt.Printf("c: %x\n", c)

	fmt.Println()
	fmt.Printf("a: %d\n", a)
	fmt.Printf("*&a: %d\n", *&a)
	fmt.Printf("*b: %d\n", *b)
	fmt.Printf("**c: %d\n", **c)
}

Output

a: 10
b: c000018030
c: c00000e028

a: 10
*&a: 10
*b: 10
**c: 10

Run in playground

Pointers in Go
Scroll to top