zero_cool
zero_cool

Reputation: 4264

Please explain &, and * pointers

There have been multiple instances where the compiler throws an error when I try to pass variables as arguments inside Go functions. I've been able to debug this sometimes by using a pointer in front of the variable. Both &, and * pointers seem to clear the error. Though, I'd like to understand why. I'm wondering what the difference between &, and * is, and when each should be used. Thank you!

func (ctx *NewContext) SendNotification(rw http.ResponseWriter, req *http.Request, p httprouter.Params) {

    decoder := json.NewDecoder(req.Body)

    var u User

    if err := decoder.Decode(&u); err != nil {
        http.Error(rw, "could not decode request", http.StatusBadRequest)
        return
    }
}

Upvotes: 27

Views: 13861

Answers (6)

Vishwa Ratna
Vishwa Ratna

Reputation: 6390

I would like to explain the concept of pointers(* and &) with an example:

Think of an example where we want to increment a variable by 1 with help of a function.

package main

import (
    "fmt"
)

func main() {
    x := 7
    fmt.Print(inc(x))
}
func inc(x int) int {
    return x + 1
}

Explanation of above: We have a function func inc(x int) int which takes an integer and returns an integer with performing an increment.

Note: Kindly pay attention that func inc(x int) int returns an int, Now what happens if we do not have a return type with that function?? This is solved by the pointer.

Look at the below code:

package main

import (
    "fmt"
)

func main() {
    x := 7
    inc(&x)
    fmt.Print(x)

}
func inc(x *int) {
    *x++
}

Explanation of the above code:

Now as our function func inc(x *int) does not have a return type we cannot get any incremented value from this function but what we can do is that we can send a location(address) to this function and tell it to increment the value at this location by one and now we can access that location from inside main() and our job is done.

A quick tip: * in front of a variable means what is stored in that variable?? and & in front of a variable means what is the internal address of that variable?

Upvotes: 0

ttt
ttt

Reputation: 6809

For this answer I will try to explain it with a variable value. A pointer can point also to a struct value.

& returns a pointer, which points to a variable value.

* reads the variable value to which the pointer is pointing.

Example:

func zero(xPointer *int) {
  *xPointer = 0
  fmt.Println(*xPointer)
}

func main() {
  x := 1
  zero(&x)
  fmt.Println(x) // x is 0
}

Upvotes: 1

monkrus
monkrus

Reputation: 1680

A simple example showing the code execution sequence.

   import (
        "fmt"
    )

    func main() {
        x := 0
        fmt.Println("Step 1", x)
        foo(&x)
        fmt.Println("Step 4", x)
    }

    func foo(y *int) {

        fmt.Println("Step 2", *y)
        *y = 100
        fmt.Println("Step 3", *y)
    }
/*
 Steps  Result
   1      0
   2      0
   3      100
   4      100
 */

Upvotes: 3

Shashank Vivek
Shashank Vivek

Reputation: 17504

pointer is used to point towards address and it stores the memory address

Adding one example to help understand pointer vs address:

Demo code

package main

import "fmt"

func main() {
    var y int
    var pointerToY *int
    var x int
    //var willThrowErrorVariable int

    y = 10
    pointerToY = &y
    //willThrowErrorVariable = &y 
    x = *pointerToY

    fmt.Println("y: ",y)
    fmt.Println("y's address using pointerToY: ",pointerToY)

    y = 4
    fmt.Println("====================================================")
    fmt.Println("Address of y after its value is changed: ",pointerToY)
    fmt.Println("value of y using pointer after its value is changed: ",*pointerToY)
    fmt.Println("Value of x after y value is changed: ",x)
}

output

y:  10
y's address using pointerToY:  0x414020
====================================================
Address of y after its value is changed:  0x414020
value of y using pointer after its value is changed:  4
Value of x after y value is changed:  10

As we can see, the value might change but the address(&) remains same and so the pointer(*) points to the value of address.

In above example,

  1. pointerToY holds the pointer to refer address of y.
  2. x holds the value which we pass to it using pointer to address of y.
  3. After changing the value of y , the x still has 10 but if we try to access the value using pointer to address (pointerToY) , we get 4

Upvotes: 2

wueb
wueb

Reputation: 896

In your example above you defined u as type User, but not a pointer to a User. So you need the &u because the Decode function in the json package is expecting an address or pointer.

If you created the instance of User like this: u := new(User) it would be a pointer since the new function returns a pointer. You could also create a pointer to a user like this: var u *User. If you did either of those, you would have to take out the & in the call to Decode for it to work.

Pointers are basically variables that hold addresses. When you put the & in front of a variable it returns the address. The * could be read as 'redirect of'. So when you create a pointer like this:

var x *int

This can be read as x will redirect to an int. And when you assign a value to x you would give it an address like this: y := 10 x = &y

Where y is some int. So if you were to print out x, you would get the address of y, but if you printed out *x you would redirect to the what x points to which is y's value which is 10. If you were to print out &x, you would get the address of the pointer, x, itself.

If you tried to print out *y, which is just an int, not a pointer, it would throw an error because you would be redirecting with some value that is not an address to redirect to.

Run the below for some pointer fun:

package main

import "fmt"

func main() {
    var y int
    var pointerToY *int
    var pointerToPointerToInt **int

    y = 10
    pointerToY = &y
    pointerToPointerToInt = &pointerToY

    fmt.Println("y: ", y)
    fmt.Println("pointerToY: ", pointerToY)
    fmt.Println("pointerToPointerToInt: ", pointerToPointerToInt)

    fmt.Println("&y: ", &y)     // address of y
    fmt.Println("&pointerToY: ", &pointerToY)// address of pointerToY
    fmt.Println("&pointerToPointerToInt: ", &pointerToPointerToInt) // address of pointerToPointerToInt

    // fmt.Println(*y) throws an error because 
    // you can't redirect without an address.. 
    // y only has int value of 10
    fmt.Println("*pointerToY: ", *pointerToY) // gives the value of y
    fmt.Println("*pointerToPointerToInt: ", *pointerToPointerToInt)     // gives the value of pointerToY which is the address of y

    fmt.Println("**pointerToPointerToInt: ", **pointerToPointerToInt)    // this gives 10, because we are redirecting twice to get y

    if pointerToY == *pointerToPointerToInt {
        fmt.Println("'pointerToY == *pointerToPointerToInt' are the same!")
    }

    if pointerToY == &y {
        fmt.Println("'pointerToY == &y' are the same!")
    }

    if &pointerToY == pointerToPointerToInt {
        fmt.Println("'&pointerToY == pointerToPointerToInt' are the same!")
    }

    if y == **pointerToPointerToInt {
        fmt.Println("'y == **pointerToPointerToInt' are the same!")
    }

    if pointerToY == *pointerToPointerToInt {
        fmt.Println("'pointerToY == *pointerToPointerToInt' are the same!")
    }

}

Hope this helps!

Upvotes: 52

user1660210
user1660210

Reputation: 2802

I will quote one smart dude:

& in front of variable name is used to retrieve the address of where this variable’s value is stored. That address is what the pointer is going to store.

* in front of a type name, means that the declared variable will store an address of another variable of that type (not a value of that type).

* in front of a variable of pointer type is used to retrieve a value stored at given address. In Go speak this is called dereferencing.

source: http://piotrzurek.net/2013/09/20/pointers-in-go.html

Upvotes: 16

Related Questions