Есть несколько вариантов решения задачи
передавать не указатель, а значение
package main
import (
  "fmt"
  "time"
)
var c = make(chan int, 3)
var data = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
func main() {
  fmt.Println("Hello, playground")
  go save()
  go read()
  time.Sleep(3 * time.Second)
}
func save() {
  for _, val := range data {
    c <- val
  }
}
func read() {
  for {
    val := <-c
    fmt.Println("read:", val)
  }
}
  скопировать значение и передать указатель на это значение
package main
import (
	"fmt"
	"time"
)
var c = make(chan *int)
var data = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
func main() {
	fmt.Println("Hello, playground")
	go save()
	go read()
	time.Sleep(3 * time.Second)
}
func save() {
	for _, val := range data {
	        v := val
		c <- &v
	}
}
func read() {
	for {
		val := <-c
		fmt.Println("read:", *val)
	}
}
  передать правильный указатель, на элемент данных
package main
import (
	"fmt"
	"time"
var c = make(chan *int, 5)
var data = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
func main() {
	fmt.Println("Hello, playground")
	go save()
	go read()
	time.Sleep(3 * time.Second)
}
func save() {
	for i := range data {
		c <- &data[i]
	}
}
func read() {
	for {
		val := <-c
		fmt.Println("read:", *val)
	}
}
  
Проблема в решении возникает потому, что вы передаёте один и тот же указатель при каждой итерации цикла, а когда вторая горутина читает - данные по этому указателю пишущая горутина уже пишет в этот участок памяти новые данные, именно по этой причине возникают одинаковые данные при выводе.
Вот пример, который покажет, что адрес всегда один и тот же
package main
import (
	"fmt"
	"time"
)
var c = make(chan *int, 5)
var data = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
func main() {
	fmt.Println("Hello, playground")
	go save()
	go read()
	time.Sleep(3 * time.Second)
}
func save() {
	for _, val := range data {
		c <- &val
		fmt.Printf("write: %v\n", &val)
	}
}
func read() {
	for {
		val := <-c
		fmt.Println("read:", *val)
	}
}
Вывод будет таким (адрес один и тот же)
Hello, playground
write: 0xc000094000
write: 0xc000094000
write: 0xc000094000
write: 0xc000094000
write: 0xc000094000
write: 0xc000094000
...
А в такой реализации (2й пример)
func save() {
	for _, val := range data {
		v := val
		c <- &v
		fmt.Printf("write: %v\n", &v)
	}
}
тут вывод будет таким (каждый раз новый участок памяти)
Hello, playground
write: 0xc000094000
write: 0xc000094010
write: 0xc000094018
write: 0xc000094020
write: 0xc000094028
write: 0xc000094030
В третьем варианте тоже будут разные указатели.