# Pointers are still a mystery to me

Let me start saying that I have no informatics background whatsoever, but I do like coding, and I do like doing it in Go
I am not a newbie, it has been already 4-5 years that I am coding (sporadically tho) in Go, and I believe I have a good knowledge of the Go ecosystem given the fact I managed to create several running-fine apps.

However, there is something that I really do not understand, pointers. Just to be clear, I do understand what pointers are, but I really not able to grasp where/when/why I should use them.

Why one would do this

``````	i, j := 42, 2701

p := &i         // point to i
fmt.Println(*p) // read i through the pointer
*p = 21         // set i through the pointer
fmt.Println(i)  // see the new value of i

p = &j         // point to j
*p = *p / 37   // divide j through the pointer
fmt.Println(j) // see the new value of j

``````

and not this?

``````	i, j := 42, 2701

i = 21         // set new i value directly
fmt.Println(i)  // see the new value of i

j = j / 37   // divide j directly
fmt.Println(j) // see the new value of j
``````

Also, could someone explain me with a `less trivial` example where pointers have an advance over calling the variable directly?

1 Like

Your examples are without use-case context so they arenâ€™t the right example of showing how pointer is used. Hence, the confusion.

For simple function context as shown above, example here:

``````func HelloWorld() {
i, j := 42, 2701

i = 21         // set new i value directly
fmt.Println(i)  // see the new value of i

j = j / 37   // divide j directly
fmt.Println(j) // see the new value of j
}
``````

Then the 2nd one makes a lot more sense as it makes no sense to use pointers at all.

In the context of the following processing function however:

``````func Calculate(i, j *int) {
if i == nil || j == nil {
return  // handle error and return. Can't operate
}

fmt.Println(*i) // read i through the pointer
*i = 21         // set value directly to the memory i
fmt.Println(*i)  // see the new value of i

*j = *j / 37   // divide j through the pointer
fmt.Println(*j) // set value directly to the memory j
}

func main() {
i := 42;
j := 2701;
Calculate(&i, &j);

fmt.Printf("After caculate i is: %v\n", i); // you won't get 42
fmt.Printf("After caculate j is: %v\n", j); // you won't get 2701
}
``````

Then it makes sense to use pointer. Note that you do not need to assign `p` pointer just to use them but you have to check the pointerâ€™s viability (they can be supplied with `nil` symbolizing no data in memory is given).

The introduction and its mechanics was explained in this forum before here:

Generally speaking, you use pointer in the event where you want to:

1. get/set a set of data stored in a specific memory rather than copy-pasting all over the places (e.g. function taking non-pointer type are usually copied as duplicate and not directly modifying the original one).
2. Separate the processing function away from actual runtime data.
3. Compositing a larger data structure.

A good case: if youâ€™re working on a function for a complex data structure, as below, pointer is highly essential as duplicating can be quite daunting:

``````type Wheel struct {
Clean bool
Dimension int64
Brand string
...
}

// create more component data structure, like door, windows, engine, etc.

type Car struct {
WheelA *Wheel
WheelB *Wheel
WheelC *Wheel
WheelD *Wheel
...
}

func WashTheCar(car *Car) {
if car != nil {
WashTheWheel(car.WheelA);
WashTheWheel(car.WheelB);
WashTheWheel(car.WheelC);
WashTheWheel(car.WheelD);
// wash something else ... like door, windows, wipers, bumper, car plate, etc.
}
}

func WashTheWheel(wheel *Wheel) {
if wheel != nil {
wheel.Clean = true
}
}

func main() {
mercedes := &Car {
// fill in car data
};

lambo := &Car {
// fill in car data
};

WashTheCar(mercedes);
WashTheCar(lambo);
}
``````

You can still re-write the above without pointer implementations using `return` value but for a large data structure, you will find at one point you will be bottle-necking yourself copy-pasting the `return`-ed value here and there, making your `main` function unnecessary long and complicated. Also, FYI, at low-level, these copy-pasting can cost a lot of compute cycles just to achieve the intended effect: directly update the already memory allocated `mercedes` and `lambo` data for a given function `WashTheCar`.

5 Likes

I am a newbie as well, but to me the difference is about the same as between a parcel and an address to a parcel. Less weight with a piece of paper.

I found one explanation here:

4 Likes

@hollowaykeanho Thanks for the detailed explanation, things start to be clearer

Just to make sure I fully understand your first case

1. get/set a set of data stored in a specific memory rather than copy-pasting all over the places (e.g. function taking non-pointer type are usually copied as duplicate and not directly modifying the original one).

Does this mean that if I do this:

``````func Calculate(i, j int) (int, int) {
i = 21         // set new value i, into its duplicate?
fmt.Println(i) // see the new value of i, from its duplicate?

j = j / 37     // divide j
fmt.Println(j) // see the new value of j

return i, j //those are the duplicates right? they will get handled by the GC?
}

func main() {
i := 42
j := 2701
i, j = Calculate(i, j)

fmt.Printf("After caculate i is: %v\n", i) // you won't get 42
fmt.Printf("After caculate j is: %v\n", j) // you won't get 2701
}
``````

`i` and `j` are duplicated when used within `Calculate`? Meaning that
`i = 21` and `j = j / 37` are actually allocating new addresses into the memory, rather than modifying the already allocated ones directly?

If that is the case, what would happen if the `Calculate` function is as follow:

``````func Calculate(i, j int) (int, int) {
m := i / 2
n := j / 37

return m, n
}
``````

`m` and `n` are for sure allocated. What about `i` and `j`, do they get duplicated here?

1 Like

Nope, that will be 2 copy-duplicates, one at the parameter input, one at return value in `main`. Iâ€™m referring to the parameter level. To be precise, here are the comparison (without the `return` modifications):

``````func Calculate(i, j int) { // as the function is called by main, i, j actual data are duplicated here as another set of memory data
...
}

func main() {
i := 42
j := 2701
Calculate(i, j)

fmt.Printf("After calculate i is: %v\n", i) // you WILL get 42 unchanged
fmt.Printf("After calculate j is: %v\n", j) // you WILL get 2701 unchanged
}
``````

Compared to:

``````func Calculate(i, j *int) { // as the function is called by main, i, j pointer data are duplicated here as another set of memory data
...
}

func main() {
i := 42
j := 2701
Calculate(i, j)

fmt.Printf("After calculate i is: %v\n", i) // you WONT get 42 but the value you last modified in Calculate()
fmt.Printf("After calculate j is: %v\n", j) // you WONT get 2701 but the value you last modified in Calculate()
}
``````

Notice that the one without using pointer, you will expect the `i` and `j` values in `main` remain unchanged but the one using pointer does even though `main` does not manually modify their values.

In case youâ€™re wondering, for the function using the pointer input, the pointer data type is copied over (pointer itself is also a data) but not the actual data in memory. `int` data type is too primitive to visualise; imagine large data structure like the `car` above and you can see the profit.

Same case, explain in verbose mode with a manual copy over:

``````func Calculate(i, j int) (int, int) { // i, j are duplicated as a different set of data in memory
m := i / 2        // i looks the same as 4 but it's a different 4 from main's i
n := j / 37       // j looks the same as 37 but it's a different 37 from main's j

return m, n      // return the newly processed values
}

func main() {
var retI, retJ int
i := 4
j := 37

retI, retJ = Calculate(i, j);  // newly processed values saved in retI and retJ

fmt.Println(i);  // expect 4 instead of 2
fmt.Println(j);  // expect 37 instead of 1
fmt.Println(retI); // expect 2
fmt.Println(retJ); // expect 1

i = retI    // manually copy over from return value
j = retJ   // manually copy over from return value

fmt.Println(i);  // expect 2
fmt.Println(j);  // expect 1
}
``````

As for when GC kicks in, canâ€™t tell unless you run your program against memory profile and tracks GC activities. However, `m` and `n` are definitely released since theyâ€™re highly likely to be in stack memory if we speak in C language (canâ€™t guarantee since Go compiler operates differently without memory profile report). If for unknown reason Go compiler allocates them to heap memory (again very unlikely), then they are for sure GC-ed since they are no longer in used.

3 Likes

The best description Iâ€™ve seen on where/when/why to use pointers is in this video course by Bill Kennedy.

Not cheap, but very good.

1 Like

fwiwâ€¦ use of and when of pointers depends on ones imagination. in the same sense as when/where/how youâ€™ll use the â€ś+â€ť operator.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.