Skip to content

Instantly share code, notes, and snippets.

@mortdeus
Last active December 20, 2015 11:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mortdeus/6120456 to your computer and use it in GitHub Desktop.
Save mortdeus/6120456 to your computer and use it in GitHub Desktop.
a few pointer pointers.
package main
import "fmt"
func main() {
a := 0
b := 0
// a and b's address that points to where they are located in memory.
fmt.Printf("main: &a = %v &b = %v\n\n", &a, &b)
/*
Note that when we pass by value, the 'a' declared in foo()'s arguments has a different
address than the a variable declared in main().
Which means that we are actually passing in a copy of main()'s 'a' variable.
Any changes made to the value of foo()'s 'a' will not change the value of main()'s a.
*/
fmt.Println("[pass by value]")
fmt.Println("main: before foo(a), a =", a)
foo(a)
fmt.Println("main: after foo(a), a =", a)
/*
Note that when we pass by pointer, the VALUE of bar()'s argument bptr equals
the address of main()'s b. Also note that the main()'s bptr address is different
than the addresses of main()'s b and bar()'s bptr.
This means that a pointer is just a integer data type that stores an address in memory
as it's values. When passing a pointer into a function, instead of passing in a copy of the
variable being pointed to, we pass in a copy of the pointer itself. The new pointer still
points to the same variable because the pointer's value (the variable's address)
doesnt change.
Since a pointer's value is only an integer representing the address of a variable in memory
we cant directly modify the value of the variable being pointed at, by modifying the
pointer's value.
For example, lets say we wanted to increment variable 'b' (b+=1). If we tried,
b := 0
bptr := &b // bptr == 0x01000008
bptr++
fmt.Println(b, bptr) // b == 0, bptr == 0x01000012
the value of b wont be incremented when 'bptr++' is called. What actually happens is that the
value stored in bptr (the address bptr is currently pointing at) will be incremented to point
to a new contigious block of memory.
[NOTE: Unlike C/C++, developers arent actually allowed to directly modify the value of a pointer
using arithmetic in go. Pointer arithmetic is considered an unsafe language feature, therefore
developers must use go's "unsafe" pkg to manipulate a pointer's value.]
In go and many other C-like language, accessing the variable through one of its pointers
requires dereferencing the pointer by prefixing the dereference operator ('*') onto
the pointer's identifier (e.g '*bptr'). In computer science terms this is called indirection.
[NOTE: In C/C++/Go/etc, The asterisk symbol ('*') has several semantical meanings depending on
the context in which it is used. Most developers will be familiar with it's use as the
multiplication operator. However, for developers unfamiliar with C-style pointer syntax,
the asterisk is a notoriously common source of confusion when first learning about pointers.
I assume the reason for this confusion stems from the fact that the asterisk is not only used to
dereferences a pointer, but to specify a pointer type as well. The confusion is only made much
worse when the address-of operator ('&') and pointer pointers (i.e. xptr_ptr => xptr => x) are
thrown in the mix.
For example, check out this function literal.
func(b uint32) float32 {
return *(*float32)(unsafe.Pointer(&b))
}
Despite only being one line of code, it's not uncommon for even an experienced go developer
to require a few moments to fully digest whats going on the first time they stumble upon
code like this. I assume most developers, who are still new to pointers, will
find code like this to be intimidating and very difficult to conceptually visualize whats
going on semantically.
If you, the reader of this blog post, are struggling to understand
what this code does. I recommend taking it slow and using the language's spec as a codex to
decipher what is going on.
Here is code example to help point you in the right direction.
http://play.golang.org/p/myunEgQPRG]
*/
bptr := &b
fmt.Printf("\nmain: bptr = %v (aka &b), &bptr = %v, *bptr (aka b) = %v \n\n", bptr, &bptr, *bptr)
fmt.Println("[pass by pointer]")
fmt.Println("main: before bar(bptr), b =", b)
bar(bptr)
fmt.Println("main: after bar(bptr), b =", b)
/*
To be continued....
*/
}
func foo(a int) {
fmt.Printf("foo: a = %v, &a = %v, \n", a, &a)
fmt.Println("foo: a++")
a++
fmt.Printf("foo: a = %v, &a = %v, \n", a, &a)
}
func bar(bptr *int) {
fmt.Printf("bar: bptr = %v, &bptr = %v, *bptr (aka b) = %v \n", bptr, &bptr, *bptr)
fmt.Println("bar: *bptr++")
*bptr++
fmt.Printf("bar: bptr = %v, &bptr = %v, *bptr (aka b) = %v \n\n", bptr, &bptr, *bptr)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment