27 / 68

Pointers

Ko'rsatkichlar

Go dasturlash tilida ko'rsatkichlar (pointers) xotira manzillari (memory addresses) bilan to'g'ridan-to'g'ri ishlash imkonini beradi. Ko'rsatkichlar orqali o'zgaruvchining xotiradagi manziliga murojaat qilish va uning qiymatini o'zgartirish mumkin.


1. Xotira manzili va & operatori

Dasturda biror o'zgaruvchi yaratilganida, operativ xotiradan (RAM) unga ma'lum bir katakcha (xotira manzili) ajratiladi.

Go tilida o'zgaruvchining xotira manzilini olish uchun uning oldiga & (ampersand) belgisi qo'yiladi:

example.go
package main

import "fmt"

func main() {
    var num int = 5

    // O'zgaruvchining qiymatini chop etish
    fmt.Println("O'zgaruvchi qiymati:", num)

    // O'zgaruvchining xotira manzilini chop etish
    fmt.Println("Xotira manzili:", &num)
}

Natija:

kod
O'zgaruvchi qiymati: 5
Xotira manzili: 0xc000018030

0xc000018030 — bu num o'zgaruvchisi xotiraning qaysi katakchasida joylashganini ko'rsatuvchi 16-lik (hexadecimal) manzil.


2. Ko'rsatkich o'zgaruvchisi (Pointer Variable)

Xotira manzilini saqlovchi maxsus o'zgaruvchi ko'rsatkich (pointer) deb ataladi. U ma'lumot turi oldiga * belgisini qo'yish orqali e'lon qilinadi:

example.go
var num int = 5
var ptr *int = &num

Bu yerda *int — bu ko'rsatkich butun son (int) turidagi o'zgaruvchining xotira manzilini saqlashini bildiradi.

Misol: Ko'rsatkichga xotira manzilini yuklash

example.go
package main

import "fmt"

func main() {
    var name = "Ali"
    var ptr *string

    // name o'zgaruvchisining manzilini ptr ga o'zlashtiramiz
    ptr = &name

    fmt.Println("Ko'rsatkich qiymati (manzil):", ptr)
    fmt.Println("O'zgaruvchi manzili:", &name)
}

Natija:

kod
Ko'rsatkich qiymati (manzil): 0xc00007c1c0
O'zgaruvchi manzili: 0xc00007c1c0

3. Ko'rsatkich orqali qiymatni o'qish (Dereferencing - * operatori)

Ko'rsatkich saqlayotgan xotira manzilidagi qiymatni o'qish uchun uning oldiga * (dereferensiya operatori) qo'yiladi:

example.go
package main

import "fmt"

func main() {
    var name = "Ali"
    var ptr *string = &name

    // *ptr orqali manzildagi asl qiymatni olamiz
    fmt.Println("Asl qiymat:", *ptr) // Ali
}

4. Ko'rsatkich orqali o'zgaruvchi qiymatini o'zgartirish

Ko'rsatkich yordamida o'zgaruvchining xotiradagi asl qiymatini bevosita yangilash mumkin. Buning bosqichma-bosqich qanday ishlashini ko'rib chiqamiz.

1-qadam: O'zgaruvchilarni e'lon qilish

example.go
var num int
var ptr *int

O'zgaruvchi va ko'rsatkich e'lon qilinadi

Bu yerda biz int turidagi ptr ko'rsatkichini va oddiy num o'zgaruvchisini yaratdik. Ikkalasi ham hali initsializatsiya qilinmagani uchun ptr hech qanday manzilni ko'rsatmaydi.

2-qadam: Oddiy o'zgaruvchiga qiymat berish

example.go
num = 22

Oddiy o'zgaruvchiga qiymat beriladi

Bu num o'zgaruvchisiga 22 qiymatini beradi, ya'ni 22 numning xotira katakchasiga yoziladi.

3-qadam: Ko'rsatkichga manzil biriktirish

example.go
ptr = &num

O'zgaruvchi manzili ko'rsatkichga biriktiriladi

Bu num o'zgaruvchisining xotira manzilini ptr ko'rsatkichiga biriktiradi.

4-qadam: O'zgaruvchi qiymatini bevosita o'zgartirish

example.go
num = 11

O'zgaruvchi qiymati o'zgartiriladi

Bu numga 11 qiymatini beradi.

5-qadam: Ko'rsatkich orqali qiymatni o'zgartirish

example.go
*ptr = 2

O'zgaruvchi qiymati ko'rsatkich orqali o'zgartiriladi

Bu ko'rsatkich ptr ko'rsatib turgan xotira manzilidagi qiymatni bevosita o'zgartiradi — demak, numning qiymati ham o'zgaradi.

To'liq misol:

example.go
package main

import "fmt"

func main() {
    var num int = 22
    var ptr *int = &num

    fmt.Println("Boshlang'ich num:", num)   // 22
    fmt.Println("ptr ko'rsatgan qiymat:", *ptr) // 22

    // Ko'rsatkich orqali qiymatni o'zgartiramiz
    *ptr = 2

    fmt.Println("Yangilangan num:", num)   // 2
    fmt.Println("ptr ko'rsatgan qiymat:", *ptr) // 2
}

Natija:

kod
Boshlang'ich num: 22
ptr ko'rsatgan qiymat: 22
Yangilangan num: 2
ptr ko'rsatgan qiymat: 2

*ptr = 2 amali bajarilganda, ptr ko'rsatib turgan xotira katagidagi qiymat to'g'ridan-to'g'ri 2 ga o'zgaradi, natijada num o'zgaruvchisining qiymati ham 2 bo'ladi.


5. nil ko'rsatkichlar

Agar ko'rsatkich e'lon qilinib, unga hech qanday manzil biriktirilmasa, uning standart qiymati nil (bo'sh) bo'ladi:

example.go
package main

import "fmt"

func main() {
    var ptr *int
    fmt.Println("Ko'rsatkich qiymati:", ptr)
}

Natija:

kod
Ko'rsatkich qiymati: <nil>

[!WARNING] nil ko'rsatkichni dereferensiya qilish (*ptr deb qiymatini o'qishga urinish) dasturning to'xtab qolishiga (panic: runtime error: invalid memory address or nil pointer dereference) olib keladi.


6. new() funksiyasi yordamida ko'rsatkich yaratish

Go tilida new() o'rnatilgan funksiyasi orqali ham yangi xotira ajratib ko'rsatkich olish mumkin:

example.go
package main

import "fmt"

func main() {
    // new(int) int uchun xotira ajratadi va uning ko'rsatkichini qaytaradi
    ptr := new(int)

    // Manzilga qiymat yozamiz
    *ptr = 20

    fmt.Println("Xotira manzili:", ptr)
    fmt.Println("Manzildagi qiymat:", *ptr)
}

Natija:

kod
Xotira manzili: 0xc000016058
Manzildagi qiymat: 20

7. * operatorisiz ko'rsatkich yaratish

Go tilida := (qisqa e'lon qilish) yordamida ko'rsatkich turi (*Tur) yozmasdan ham ko'rsatkich yaratish mumkin — Go kompilyatori turi avtomatik aniqlaydi:

example.go
package main

import "fmt"

func main() {
    var name = "Ali"

    // *string yozmasdan ham ptr ko'rsatkich bo'ladi
    var ptr = &name

    fmt.Println("ptr qiymati:", ptr)
    fmt.Println("name manzili:", &name)
}

Natija:

kod
ptr qiymati: 0xc0000101e0
name manzili: 0xc0000101e0

Bu yerda &name to'g'ridan-to'g'ri ptr o'zgaruvchisiga o'zlashtirilgan. * operatori yozilmagan bo'lsa-da, ptr baribir to'liq qonuniy ko'rsatkich hisoblanadi.