Разбор указателей
Не могу разобраться в указателях, есть код
package main
import "fmt"
func main() {
p0 := new(int)
fmt.Println(p0)
fmt.Println(*p0)
x := *p0
p1, p2 := &x, &x
fmt.Println(p1 == p2) // true
fmt.Println(p0 == p1) // false
fmt.Println(p0 == p2) // false
p3 := &*p0
fmt.Println(p3)
fmt.Println(p0 == p3) // true
*p0, *p1 = 123, 789
fmt.Println(*p2, x, *p3) // 789 789 123
fmt.Printf("%T, %T \n", *p0, x) // int, int
fmt.Printf("%T, %T \n", p0, p1) // *int, *int
}
Итак в строке
x := *pу нас лежит копия *p, 0p1, p2 := &x, &x, у нас адрес на x- теперь самое непонятное
p3 := &*p0, что тут вообще произошло? p0 == p3почему это true
Так же в учебнике встретил такие конструкции:
*&a++
*&*&a++
**&p++
*&*p++
это нормальный код?
Ответы (1 шт):
Не зная голанга, можно рассмотреть такие общечеловеческие соображения:
p0 := new(int)
Выделена память под целое число, указатель на неё хранится в указательной переменной p0 (пусть это адрес 0x44444444). Возможно, подразумевается инициализация нулями (спецификацию языка я не смотрел, может быть мусор). Само целое число по данному адресу не имеет своей личной целочисленной переменной, оно безымянно.
x := *p0
Указатель разыменован - содержимое по адресу памяти 0x44444444 - 4 байта (целое в голанге 32-х битное?) - интерпретируется как целое число, и записывается в переменную x. Значение пока совпадает с безымянным значением (да, является копией).
p1 := &x
Адрес переменной x записан в p1, этот адрес другой, скажем, 0x44444448
Область памяти, начиная с адреса 0x44444444
00 00 00 00 | 00 00 00 00
--------------------------------
noname= 00 | x= 00
.
p3 := &*p0
Переменная разыменована, но в результат взят опять адрес, куда она указывала, т.е. реально произошло копирование указателя p0 в указатель p3, там всё то же 0x44444444
*p0, *p1 = 123, 789
По адресу безымянной переменной записано 123, а по адресу x записано 789. Мы помним, что эти адреса разные. Теперь в области памяти, начиная с адреса 0x44444444, хранится
7B 00 00 00 | 15 03 00 00
--------------------------------
noname=123 | x=789
т.е. значение x больше не является копией
Про конструкции из учебника *&a++ это взятие адреса, разыменование, инкремент (т.е. a += 1) (++ особый оператор, см. описание приоритетов). Это более логичная конструкция, чем разыменование+взятие адреса (в других языках на промежуточных этапах можно привести тип к другому).
Если сделать
a := 3;
p := &a;
И применить любую из конструкций, то a станет равно 4.
Код ненормальный ;)