What is the pointer?
Shortly, the pointer is a variable which stores an address of another variable, where some data is stored.
Contents
A pointer example
Let’s take the simplest example where a pointer is used:
package main
import "fmt"
func main() {
a := 1
b := &a
fmt.Println("A: ", a)
fmt.Println("B: ", b)
fmt.Println("B: ", *b)
}
Here:
- a variable
ais created with the integer type and value 1 - a variable
bis created with the pointer to the integer type (see below) - and data output:
- first just the
avalue - the value(!) or content of the
bvariable - finally, we are getting the value of the
a, to which thebis pointed to (will look at the*and&operators bit later)
- first just the
Run the code:
[simterm]
$ go run pointers_example.go A: 1 B: 0xc0000140e8 B: 1
[/simterm]
On the second line, we are seeing the memory address, where the b pointer is pointed.
On the third line – we got value from this memory address.
The pointer could be initialized in a more amply way with types specification instead of using := so the code will look like:
...
func main() {
var a int = 1
var b *int = &a
fmt.Println("A: ", a)
fmt.Println("B: ", b)
fmt.Println("B: ", *b)
}
...
In the var b *int = &a line we set that the b variable is a pointer to the integer data.
In the same way, a pointer to the string data could be created just with the *string instead of the *int in its data type:
...
var c *string
fmt.Printf("The C var type: %T, default value: %v\n", c, c)
var d string = "This is a string"
c = &d
fmt.Printf("The C var type: %T, default value: %v, string value: %s\n", c, c, *c)
...
here:
- the
cvariable is created as a pointer to the string data - using
Printf()‘s modifiers thecvariable’s data type (%T) and its value (%v) are displayed - the
dvariable is created with the string data type and “This is a string” value - for the
cvariable the memory address of thedvariable is set - using
Printf()‘s modifiers thecvariable’s data type (%T), its value (%v), and the value from the memory address which is stored in thec
Run:
[simterm]
$ go run pointers_example.go The C var type: *string, default value: <nil> The C var type: *string, default value: 0xc0000101e0, string value: This is a string
[/simterm]
* and & operators
We already used them in examples above but let’s take a closer look.
The * operator is a dereference operator.
The dereference here means that we are getting a value not of a pointer (which stores an address) but from the memory address where this pointer is… Well – pointed to 🙂
Let go back to our previous example:
...
fmt.Printf("The C var type: %T, default value: %v, string value: %s\n", c, c, *c)
...
Here:
default value: %vwith theс– displays a value which is stored in the c variable – a memory address, where c is pointed tostring value: %swith the*с– displays a value which is got after calling the memory from thecvariable
The & operator returns a variable’s memory address.
For example, let’s add to our previous example one more line and lets display addresses using Printf() with %p modifier:
...
var c *string
fmt.Printf("The C var type: %T, default value: %v\n", c, c)
var d string = "This is a string"
c = &d
fmt.Printf("The C var type: %T, default value: %v, string value: %s\n", c, c, *c)
fmt.Printf("The D adress: %p\nThe C address: %p\nThe C value: %v\n", &d, &c, c)
...
Check:
[simterm]
$ go run pointers_example.go The C var type: *string, default value: <nil> The C var type: *string, default value: 0xc0000101e0, string value: This is a string The D adress: 0xc0000101e0 The C address: 0xc00000e028 The C value: 0xc0000101e0
[/simterm]
Here we got 0xc0000101e0 value as the d variable address, 0xc00000e028 as the address of the c variable, but the c itself stores address of the d variable – 0xc0000101e0.
Actually a data initialization in the c pointer variable is done by getting the address of the d variable:
... c = &d ...
The new() function
To define and initialize a pointer using the var pointername *type notation – you can use the builtin new() Go function which accepts a data type as the first argument and will return a pointer to a memory allocated for a variable’s data:
...
a := 1
b := new(int)
fmt.Printf("A: %d, B: %v, %v\n", a, b, *b)
b = &a
fmt.Printf("A: %d, B: %v, %v\n", a, b, *b)
...
Here:
- the
avariable is created with value 1 - the
bvariable is created which will hold a pointer to the memory returned by the new() function and which keeps 0 for now, as already allocated memory can’t holdnil - the
b‘s value is updated with thea‘s address
Check:
[simterm]
$ go run pointers_example.go A: 1, B: 0xc000014100, 0 A: 1, B: 0xc0000140e8, 1
[/simterm]
Changing a pointer’s value
Well, this is not correct to say “changing a pointer’s value” as a pointer variable stores a memory address – not a value itself.
But using a pointer we can change this value in a memory location to which this pointer is pointed to.
For example:
...
a := 1
b := &a
fmt.Println("A: ", a)
fmt.Println("B: ", *b)
*b = 2
fmt.Println("B: ", *b)
...
Here:
- the
avariable has value 1 - the
bvariable has thea‘s address - the
avariable value displayed - the value displayed take from the address where the
bis pointed to - we are changing the value in this memory to the 2
- and displays the new value
Run the code:
[simterm]
$ go run pointers_example.go A: 1 B: 1 B: 2
[/simterm]
Passing a pointer as a function’s argument
You can pass a pointer to a function as its argument.
For example:
package main
import "fmt"
func setVal(b *int) {
*b = 2
}
func main() {
a := 1
b := &a
fmt.Println("Init values")
fmt.Println("A: ", a)
fmt.Println("B: ", *b)
setVal(b)
fmt.Println("Changed values")
fmt.Println("A: ", a)
fmt.Println("B: ", *b)
}
Here we are creating a setVal() function which accepts an integer pointer as an argument and will change a value in the address passed with this pointer.
Check it:
[simterm]
$ go run pointers_example.go Init values A: 1 B: 1 Changed values A: 2 B: 2
[/simterm]
After calling the setVal() – thea and b will display a new value.
Even more – we could pass just an address of the a‘s variable to the setVal():
...
func setVal(b *int) {
*b = 2
}
func main() {
a := 1
fmt.Println("Init values")
fmt.Println("A: ", a)
setVal(&a)
fmt.Println("Changed values")
fmt.Println("A: ", a)
}
The result is:
[simterm]
$ go run pointers_example.go Init values A: 1 Changed values A: 2
[/simterm]
Functions: passing arguments by value and by reference
A bit offtopic here but using the example above the difference between passing argument by value and argument by reference also can be displayed.
Let’s update this example:
...
func setVal(b *int, c int) {
*b = 2
c = 4
fmt.Printf("B from setVal(). Poiner to: %p, val: %v\n", b, *b)
fmt.Printf("C from setVal(). Addr: %p, val: %v\n", &c, c)
}
func main() {
a := 1
b := &a
c := 3
fmt.Println("Init values")
fmt.Printf("A from main(). Addr: %p, val: %v\n", &a, a)
fmt.Printf("B from main(). Poiner to: %p, val: %v\n", b, *b)
fmt.Printf("C from main(). Addr: %p, val: %v\n", &c, c)
fmt.Println("Changed values")
setVal(b, c)
fmt.Printf("A from main(). Addr: %p, val: %v\n", &a, a)
fmt.Printf("B from main(). Poiner to: %p, val: %v\n", b, *b)
fmt.Printf("C from main(). Addr: %p, val: %v\n", &c, c)
}
Here:
- get the
avariable address and its value - get the address which is stored in the
bvariable and then the data which is stored on this address - get the
cvariable address and its value - call the
setVal()function and pass thea‘s value by the reference in theband thec– as a value - in the
setVal()getting the address which is stored in thebvariable and the value which is stored there - in the
setVal()getting thecvariable address and the value which is stored in this memory area - in the
main()getting thea‘s address and the value stored there - in the
main()getting the address which is stored in thebvariable and value from there - in the
main()getting thecvariable address and the value which is stored there
Run it:
[simterm]
$ go run pointers_example.go Init values A from main(). Addr: 0xc0000140e8, val: 1 B from main(). Poiner to: 0xc0000140e8, val: 1 C from main(). Addr: 0xc000014100, val: 3 Changed values B from setVal(). Poiner to: 0xc0000140e8, val: 2 C from setVal(). Addr: 0xc000014130, val: 4 A from main(). Addr: 0xc0000140e8, val: 2 B from main(). Poiner to: 0xc0000140e8, val: 2 C from main(). Addr: 0xc000014100, val: 3
[/simterm]
Here:
- the
ais stored in the 0xc0000140e8 location and has value 1 - the
bis pointed to the same location 0xc0000140e8 and returns the same 1 value - the
cis stored in the 0xc000014100 location with the 3 value - the
setVal()is called - the
bin thesetVal()still pointed to the 0xc0000140e8 location with the 2 as its value - the
cin thesetVal()got its new address 0xc000014130 where the 4 is stored - the
ain themain()now keeps the 2 value from the same 0xc0000140e8 location the bin themain()still the same as it is in thesetVal()– points to the same location and returns the same value- in the
main()for thecvariable nothing was changed as thecin thesetVal()has own address 0xc000014130, but thecin themain()uses the 0xc000014100 location
Actually, that’s all need to know to better understand what pointers are and how to use them.




