gokayburuc.dev

Zig Programlama Dilinde Pointer (İşaretçi) Kullanımı

Zig, düşük seviyeli programlama için tasarlanmış modern bir sistem programlama dilidir. Zig'de pointer'lar (işaretçiler), bellek adreslerini doğrudan manipüle etmek ve veri üzerinde dolaylı erişim sağlamak için önemli araçlardır. Bu makalede Zig dilinde pointer kavramı, kullanımı, değiştirilebilirliği ve fonksiyonlara pointer aktarımı ele alınacak, doğru ve eksiksiz bilgilerle açıklamalar sunulacaktır.


1. Pointer Nedir?

Pointer, bellekteki bir değerin adresini tutan değişkendir. Zig dilinde bir değişkenin adresini almak için & operatörü, pointer'ın işaret ettiği değere erişmek için ise .* (dereference) operatörü kullanılır.

Örnek:

var original: u8 = 5;
var pointer_ref: *u8 = &original;

Pointer üzerinden değer okumak ya da yazmak için aşağıdaki gibi dereference edilir:

const val: u8 = pointer_ref.*;
pointer_ref.* = 10; // Bellekteki değeri değiştirir.

2. Pointer Kullanımı

Pointer'lar dolaylı adresleme yaparak, bellekteki verilere erişmek ve değiştirmek için kullanılır.

const std = @import("std");

pub fn main() void {
    var x: i32 = 42;
    var ptr: *i32 = &x;

    std.debug.print("Value before: {}\n", .{ptr.*});
    ptr.* = 100; // x'in değeri 100 olur
    std.debug.print("Value after: {}\n", .{x});
}

Burada ptr.* ifadesi pointer'ın işaret ettiği değeri alır veya yazdırır. Bu kullanımda ptr doğrudan x'in adresini tutar ve ptr.* üzerinden x'in değerine erişilir.


3. Pointer ve Fonksiyonlar

Zig'de fonksiyonlara pointer geçirerek, fonksiyonun çağrıldığı yerdeki değişken üzerinde değişiklik yapılabilir.

Örnek:

const std = @import("std");

pub fn PointerOps() void {
    var x: i32 = 5;
    std.debug.print("Original x before: {}\n", .{x});
    ModifyPointer(&x);
    std.debug.print("Modified x after: {}\n", .{x});
}

fn ModifyPointer(x_ptr: *i32) void {
    x_ptr.* = 99;
}

Önemli:


4. Const Pointer (Sabit Pointer) ve Const Data

Zig’de pointer’lar hem gösterdikleri veri hem de kendileri açısından değiştirilebilirlik özelliğine sahiptir. İki farklı kavram vardır:

Pointer Türü Veri Değiştirilebilirliği Pointer Değiştirilebilirliği
*T Evet Evet
*const T Hayır Evet
const *T Evet Hayır
const *const T Hayır Hayır

Detay:

Örnek:

const std = @import("std");

pub fn main() void {
    const a: u8 = 12;
    const b: *const u8 = &a; // 'a' sabit, dolayısıyla pointer da const data pointer.

    std.debug.print("a: {}, b: {}\n", .{ a, b.* });
}

Eğer a değişkeni var olarak tanımlıysa, aşağıdaki gibi yazabiliriz:

var a: u8 = 12;
const b: *u8 = &a;

Burada pointer veri üzerinde değişiklik yapabilir.


5. Undefined Pointer Kullanımı

Zig'de pointer değişkenleri, atanmamış (uninitialized) olmamalıdır çünkü tanımsız (undefined) bilgilerle çalışmak programda belirsiz davranışlara yol açabilir. Ancak, aşağıdaki gibi bir yazım Zig’de geçerlidir:

var p: *u8 = undefined;

Bu, p'nin başlangıçta herhangi bir geçerli adres tutmadığını belirtir. Bellek alanı işaret eden pointer'lar kullanılmadan önce mutlaka geçerli bir adresle başlatılmalıdır.

Örnek:

const std = @import("std");

pub fn UndefinedPointer() void {
    var a: u8 = 17;
    var b: u8 = 22;
    var p: *u8 = undefined;

    p = &a;
    p.* += 5;   // a = 22

    p = &b;
    p.* += 7;   // b = 29

    std.debug.print("a: {} b: {}\n", .{a, b});
}

6. Struct ve Pointer Kullanımı

Bir struct örneğine pointer ile erişmek ve alanlarını değiştirmek mümkündür. Struct pointer’larında erişim için ptr.* yerine işaretçi kullanımında ptr.field notasyonu tercih edilir.

const std = @import("std");

const Person = struct {
    age: u8,
    name: []const u8,
};

pub fn main() void {
    var gokay = Person{ .age = 30, .name = "Gokay" };
    var ptr: *Person = &gokay;

    ptr.age += 1; // Pointer üzerinden yaş arttırılır
    std.debug.print("Name: {}, Age: {}\n", .{ptr.name, ptr.age});
}

Buradaki ptr.age ifadesi, Zig dilinin pointer struct erişim söz dizimidir ve (*ptr).age ifadesine eşdeğerdir.


7. Pointerların Fonksiyon Argümanı Olarak Kullanımı

Pointerlar, fonksiyon parametresi olarak geçildiğinde fonksiyon çağrıldığı yerdeki veriyi direkt değiştirebilir.

Struct örneği ile:

const Person = struct {
    age: u8,
    name: []const u8,
};

fn birthday(p: *Person) void {
    p.age += 1;
}

pub fn main() void {
    var gokay = Person{ .age = 30, .name = "Gokay" };
    birthday(&gokay);
    // gokay.age artık 31 oldu
}

Fonksiyonun parametresi pointer olduğunda, fonksiyon çağrıldığında yapının bir kopyası değil, orijinal veri üzerinde değişiklik yapılır.


8. Struct Alanına Pointer Atama

Struct alanlarından birine işaret eden pointer oluşturmak mümkündür.

Örnek:

var age_ptr: *u8 = &gokay.age;
age_ptr.* = 99;

Bu işlem sonucunda gokay.age alanının değeri 99 olarak güncellenir.


9. Pointer Mutability (Değiştirilebilirlik) - Detaylı Açıklama

Zig dilinde pointer değişkenlerinin mutability durumu, gösterilen verinin değiştirilebilirliği (*const T vs *T) ve pointer'ın kendisinin değiştirilebilirliği (const ptr = ... gibi) ile ilgilidir.


10. Güvenlik ve Zig’de Pointerlar

Zig dilinin felsefesi üzerinden pointer kullanımına dikkat etmek çok önemlidir:


Sonuç

Zig dilinde pointerlar, hem düşük seviye bellek erişimi sağlar hem de tip güvenliği ve mutability kuralları ile programcıyı korur. Pointer kullanımı;

Dikkatli kullanıldığında, Zig pointerları sistem programlama için güçlü ve verimli bir araçtır.

#zig