To give a simple answer to this
Go looks for variables that outlive the current stack frame and
then heap-allocates them
Basically, the variable v escapes the function f stack frame and gets allocated in heap which is why you see different addresses printed everytime.
Read this nice introduction to escape analysis. https://medium.com/a-journey-with-go/go-introduction-to-the-escape-analysis-f7610174e890
Try running escape analysis to see all the variables that got escaped.
go build -gcflags="-m" main.go:
./main.go:7:2: moved to heap: v   //points to v := 1
./main.go:12:15: moved to heap: v //points to fmt.Println(f())
./main.go:13:15: moved to heap: v //points to fmt.Println(f())
./main.go:14:15: moved to heap: v //points to fmt.Println(f())
Note that the last fmt.Println(f()) statement is not considered for escaping as value passed to Println is p which is a global variable so its already in heap and thus doesn't need to escape.