---
title: 'İşaretçi Temelleri'
source: 'https://academia.sh/tr/kurslar/c-bellek/isaretci-temelleri'
course: "C'de Bellek ve İşaretçiler"
language: tr
updated: '2026-09-26T03:02:43+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir bellek bloğunun sahibini dil, çağıran, çağrılan ve sahipsiz olarak dört sınıfa ayırır'
    - 'Adres alma ve dolaylama işleçlerini adres basmadan eşitlik ve işaret edilen değerle ölçer'
    - 'Bir işaretçinin tipinin, gösterdiği bloğun sahibini söylemediğini örnekle gösterir'
---

# İşaretçi Temelleri

Bir bellek bloğunu kimin sahiplendiği sorusu; beş dosyalık ölçüm çekirdeğinin tam koşumu ve dört sınıfın (dil, çağıran, çağrılan, sahipsiz) 4/4/3/2 dağılımı, ardından adres alma ve dolaylama işleçlerinin adres basılmadan ölçülmesi.

C Temelleri kursu bir kararın hangi aşamada (ön işlemci, derleyici, bağlayıcı, koşum)
verildiğini ölçtü. Bu kurs farklı bir soruyla başlıyor: kaynakta hiçbir aşama bir bellek
bloğunu kimin **bırakacağını** söylemiyor. Derleyici bir bildirimin tipini bilir, bağlayıcı
bir adın hangi tanıma bağlandığını çözer, koşum yalnız sonucu görür — ama "bu bloğu kim
serbest bırakacak" sorusunun yanıtı hiçbirinde durmuyor. Bu yanıt, kaynakta yazılı bir
**sözleşmeyle** taşınıyor: bir başlık dosyasındaki yorum, bir işlev adı, bir alışkanlık.

Kurs bunu tek bir soruyla ölçüyor: **bu belleği kim sahipleniyor?** Yanıt dört sınıftan
birine düşüyor ve bu dört ad kurs boyunca değişmiyor.

## Dört Sınıf: Dil, Çağıran, Çağrılan, Sahipsiz

| Sınıf | Tanım |
|---|---|
| **dil** | Ömrü dil belirler (otomatik ya da statik); kimse bırakma çağrısı yapmaz |
| **çağıran** | Belleği ayıran ya da bir işlevden alan taraf bırakmakla yükümlüdür |
| **çağrılan** | Belleği bir modül tutar; çağırana yalnız ödünç verir, hata yolunda da kendisi temizler |
| **sahipsiz** | Hiçbir taraf bırakmakla yükümlü değildir; blok yalnız bir sayaç farkı olarak görünür |

Bu dört sınıfı beş dosyalık bir ölçüm çekirdeği kuruyor: `sayac.h`/`sayac.c` her ayırma ve
bırakma çağrısını sayan ince bir sarmalayıcı, `sahip.h`/`sahip.c` opak bir kaydın sahiplik
sözleşmesini yorumlarda taşıyan bir birim, `sahiplik.c` ise on üç gözlemi tek bir koşumda
toplayan ölçüm işlevi. Kursun geri kalan on dört dersi bu çekirdeğin **kesitlerini** alacak;
bu ders tek istisna olarak tamamını çalıştırıyor.

```c
// sayac.h — her ayirmayi ve her birakmayi sayan sarmalayici
#ifndef SAYAC_H
#define SAYAC_H

#include <stddef.h>

void *say_ayir(size_t boyut);
void *say_buyut(void *eski, size_t boyut);
void say_birak(void *blok);
int ayrilan_sayisi(void);
int birakilan_sayisi(void);

#endif
```

```c
// sayac.c — sayaclar yalniz bu birimde tutulur
#include <stdlib.h>
#include "sayac.h"

static int ayrilan = 0;
static int birakilan = 0;

void *say_ayir(size_t boyut) {
    void *blok = malloc(boyut);
    if (blok != NULL) {
        ayrilan++;
    }
    return blok;
}

void *say_buyut(void *eski, size_t boyut) {
    int yeni_blok = (eski == NULL);
    void *yeni = realloc(eski, boyut);
    if (yeni != NULL && yeni_blok) {
        ayrilan++;
    }
    return yeni;
}

void say_birak(void *blok) {
    if (blok != NULL) {
        birakilan++;
    }
    free(blok);
}

int ayrilan_sayisi(void) {
    return ayrilan;
}

int birakilan_sayisi(void) {
    return birakilan;
}
```

```c
// sahip.h — kaydin ici gizli, sahiplik sozlesmesi yorumlarda yazili
#ifndef SAHIP_H
#define SAHIP_H

#include <stddef.h>

typedef struct Kayit Kayit;

/* Cagiran sahiplenir ve kayit_yok_et ile birakir. Ad sinira sigmazsa NULL
   doner; o ana kadar ayrilan bellegi islev kendisi birakir. */
Kayit *kayit_olustur(const char *ad, size_t sinir);

/* Kaydi ve kaydin icindeki ad tamponunu birlikte birakir. */
void kayit_yok_et(Kayit *k);

/* Kayit sahiplenir: donen isaretci kayit yok edilene dek gecerlidir,
   cagiran onu birakmaz. */
const char *kayit_ad(const Kayit *k);

/* Cagiran sahiplenir: donen kopya say_birak ile birakilir. */
char *kayit_ad_kopyasi(const Kayit *k);

#endif
```

```c
// sahip.c — sozlesmenin uygulandigi birim
#include <string.h>
#include "sahip.h"
#include "sayac.h"

struct Kayit {
    char *ad;
    size_t uzunluk;
};

Kayit *kayit_olustur(const char *ad, size_t sinir) {
    Kayit *k = say_ayir(sizeof *k);
    if (k == NULL) {
        return NULL;
    }
    k->uzunluk = strlen(ad);
    if (k->uzunluk >= sinir) {
        say_birak(k);
        return NULL;
    }
    k->ad = say_ayir(k->uzunluk + 1);
    if (k->ad == NULL) {
        say_birak(k);
        return NULL;
    }
    memcpy(k->ad, ad, k->uzunluk + 1);
    return k;
}

void kayit_yok_et(Kayit *k) {
    if (k == NULL) {
        return;
    }
    say_birak(k->ad);
    say_birak(k);
}

const char *kayit_ad(const Kayit *k) {
    return k->ad;
}

char *kayit_ad_kopyasi(const Kayit *k) {
    char *kopya = say_ayir(k->uzunluk + 1);
    if (kopya != NULL) {
        memcpy(kopya, k->ad, k->uzunluk + 1);
    }
    return kopya;
}
```

```c
// sahiplik.c — bir bellegi kimin sahiplendigini olcen cekirdek
#include <stdio.h>
#include <string.h>
#include "sahip.h"
#include "sayac.h"

static int statik_sayac = 3;

static int fark(void) {
    return ayrilan_sayisi() - birakilan_sayisi();
}

static void gozle(const char *ad, const char *sinif, const char *kanit) {
    printf("%-30s%-10s%s\n", ad, sinif, kanit);
}

int main(void) {
    char tampon[64];
    int dil = 0, cagiran = 0, cagrilan = 0, sahipsiz = 0;
    int once, ayrilan_once, birakilan_once;

    printf("%-30s%-10s%s\n", "gozlem", "sahip", "kanit");

    once = fark();
    int yerel = 5;
    int *p = &yerel;
    snprintf(tampon, sizeof tampon, "*p %d, sayac farki %d", *p, fark() - once);
    gozle("yerel degisken", "dil", tampon);
    dil++;

    int *s = &statik_sayac;
    snprintf(tampon, sizeof tampon, "*s %d, birakma cagrisi yok", *s);
    gozle("statik alan", "dil", tampon);
    dil++;

    const char *degismez = "sabit";
    snprintf(tampon, sizeof tampon, "uzunluk %d, birakma cagrisi yok", (int)strlen(degismez));
    gozle("dizgi degismezi", "dil", tampon);
    dil++;

    int dizi[4] = {1, 2, 3, 4};
    int *ilk = dizi;
    int *son = &dizi[3];
    snprintf(tampon, sizeof tampon, "son - ilk %d, *son %d", (int)(son - ilk), *son);
    gozle("yerel dizi", "dil", tampon);
    dil++;

    once = fark();
    int *blok = say_ayir(4 * sizeof *blok);
    int toplam = 0;
    if (blok != NULL) {
        for (int i = 0; i < 4; i++) {
            blok[i] = i + 1;
            toplam += blok[i];
        }
    }
    say_birak(blok);
    snprintf(tampon, sizeof tampon, "toplam %d, sayac farki %d", toplam, fark() - once);
    gozle("ayir ve birak", "cagiran", tampon);
    cagiran++;

    once = fark();
    int *buyuyen = say_buyut(NULL, 2 * sizeof *buyuyen);
    int korunan = 0;
    if (buyuyen != NULL) {
        buyuyen[0] = 7;
        int *yeni = say_buyut(buyuyen, 8 * sizeof *yeni);
        if (yeni != NULL) {
            buyuyen = yeni;
        }
        korunan = buyuyen[0];
    }
    say_birak(buyuyen);
    snprintf(tampon, sizeof tampon, "ilk eleman %d, sayac farki %d", korunan, fark() - once);
    gozle("yeniden boyutlandirma", "cagiran", tampon);
    cagiran++;

    ayrilan_once = ayrilan_sayisi();
    Kayit *k = kayit_olustur("defter", 16);
    snprintf(tampon, sizeof tampon, "bos degil %d, ayrilan blok %d", k != NULL, ayrilan_sayisi() - ayrilan_once);
    gozle("opak kayit", "cagiran", tampon);
    cagiran++;

    once = fark();
    char *kopya = kayit_ad_kopyasi(k);
    snprintf(tampon, sizeof tampon, "kopya %s", kopya != NULL ? kopya : "yok");
    say_birak(kopya);
    snprintf(tampon + strlen(tampon), sizeof tampon - strlen(tampon), ", sayac farki %d", fark() - once);
    gozle("donen kopya", "cagiran", tampon);
    cagiran++;

    once = fark();
    const char *odunc = kayit_ad(k);
    snprintf(tampon, sizeof tampon, "ad %s, sayac farki %d", odunc, fark() - once);
    gozle("odunc verilen ad", "cagrilan", tampon);
    cagrilan++;

    once = fark();
    Kayit *uzun = kayit_olustur("cok uzun bir kayit adi", 8);
    snprintf(tampon, sizeof tampon, "bos %d, sayac farki %d", uzun == NULL, fark() - once);
    gozle("hata yolunda temizlik", "cagrilan", tampon);
    cagrilan++;

    birakilan_once = birakilan_sayisi();
    kayit_yok_et(k);
    snprintf(tampon, sizeof tampon, "birakilan blok %d", birakilan_sayisi() - birakilan_once);
    gozle("kaydin ic tamponu", "cagrilan", tampon);
    cagrilan++;

    once = fark();
    int *kayip = say_ayir(sizeof *kayip);
    kayip = say_ayir(sizeof *kayip);
    say_birak(kayip);
    snprintf(tampon, sizeof tampon, "sayac farki %d", fark() - once);
    gozle("uzerine yazilan isaretci", "sahipsiz", tampon);
    sahipsiz++;

    Kayit *k2 = kayit_olustur("taslak", 16);
    once = fark();
    if (k2 != NULL) {
        kayit_ad_kopyasi(k2);
    }
    snprintf(tampon, sizeof tampon, "sayac farki %d", fark() - once);
    kayit_yok_et(k2);
    gozle("yok sayilan donus", "sahipsiz", tampon);
    sahipsiz++;

    printf("\n%-10s%d\n", "dil", dil);
    printf("%-10s%d\n", "cagiran", cagiran);
    printf("%-10s%d\n", "cagrilan", cagrilan);
    printf("%-10s%d\n", "sahipsiz", sahipsiz);
    printf("toplam gozlem: %d\n", dil + cagiran + cagrilan + sahipsiz);
    printf("ayrilan %d birakilan %d fark %d\n", ayrilan_sayisi(), birakilan_sayisi(), fark());
    return 0;
}
```

```
gozlem                        sahip     kanit
yerel degisken                dil       *p 5, sayac farki 0
statik alan                   dil       *s 3, birakma cagrisi yok
dizgi degismezi               dil       uzunluk 5, birakma cagrisi yok
yerel dizi                    dil       son - ilk 3, *son 4
ayir ve birak                 cagiran   toplam 10, sayac farki 0
yeniden boyutlandirma         cagiran   ilk eleman 7, sayac farki 0
opak kayit                    cagiran   bos degil 1, ayrilan blok 2
donen kopya                   cagiran   kopya defter, sayac farki 0
odunc verilen ad              cagrilan  ad defter, sayac farki 0
hata yolunda temizlik         cagrilan  bos 1, sayac farki 0
kaydin ic tamponu             cagrilan  birakilan blok 2
uzerine yazilan isaretci      sahipsiz  sayac farki 1
yok sayilan donus             sahipsiz  sayac farki 1

dil       4
cagiran   4
cagrilan  3
sahipsiz  2
toplam gozlem: 13
ayrilan 11 birakilan 9 fark 2
```

**IS1.** On üç gözlemin **4**'ü `dil` sınıfında, **4**'ü `çağıran`'da, **3**'ü `çağrılan`'da
ve **2**'si `sahipsiz`'de topladı. `dil` sınıfının dördünde de bir bırakma çağrısı yok —
yerel değişken, statik alan, dizgi değişmezi ve yerel dizi kendi ömrünü kendisi bitiriyor.
`ayrilan 11 birakilan 9 fark 2` satırı, koşumun sonunda hâlâ **iki** bloğun bırakılmadan
kaldığını söylüyor; bu iki blok, `sahipsiz` satırlarının bıraktığı fark ile birebir eşleşiyor
— üzerine yazılan işaretçi ve yok sayılan dönüş, ikisi de tam bir blok kaybetti. Bu koşum
**uyarısız** derlendi ve üç ayrı koşumda **birebir aynı** çıktıyı verdi; kursun geri kalan
her dersi bu dört sınıfı ve bu tabloyu kaynak alacak.

## Adres Alma ve Dolaylama: `yerel degisken` Satırının Derinleştirilmesi

Çekirdeğin ilk satırı — `yerel degisken` — iki işlecin en sık kullanılan çiftini içeriyor:
adres alma (`&`) ve dolaylama (`*`). Bu ders onları çekirdeğin dışında, yalnız bu ikisine
odaklanan küçük bir koşumla ayrıca ölçüyor.

```c
// adres_alma.c — adres alma ve dolaylama, adres basmadan esitlik ve deger ile olculur
#include <stdio.h>

int main(void) {
    int sayi = 42;
    int *p = &sayi;

    printf("%s %d\n", "isaret edilen deger", *p);
    printf("%s %d\n", "p sayinin adresini mi gosteriyor", (int)(p == &sayi));

    *p = 100;
    printf("%s %d\n", "dolaylamayla yazilan yeni deger", sayi);

    int baska = 7;
    p = &baska;
    printf("%s %d\n", "yeniden atamadan sonra isaret edilen deger", *p);
    printf("%s %d\n", "p artik sayiyi mi gosteriyor", (int)(p == &sayi));
    return 0;
}
```

```
isaret edilen deger 42
p sayinin adresini mi gosteriyor 1
dolaylamayla yazilan yeni deger 100
yeniden atamadan sonra isaret edilen deger 7
p artik sayiyi mi gosteriyor 0
```

**IS2.** `&sayi` ifadesi `sayi` değişkeninin adresini üretiyor ve bu adres `p`'ye atanıyor;
`p == &sayi` karşılaştırması **1** veriyor, yani `p` gerçekten `sayi`'yi gösteriyor — ama bu
karşılaştırma adresin **kendisini** hiç yazdırmadan, yalnız iki adresin eşit olup olmadığını
soruyor. `*p = 100` satırı **dolaylama işlecini** bir atamanın sol tarafında kullanıyor:
`p`'nin gösterdiği yere yazıyor, `p`'nin kendisine değil. Bunun kanıtı bir sonraki satır —
`sayi` artık **100**; `p` üzerinden yapılan yazma, gösterdiği değişkeni gerçekten değiştirdi.
`p = &baska` ile `p` başka bir değişkeni göstermeye **yeniden atanabiliyor**; bu atamadan
sonra `*p` **7**'yi veriyor ve `p == &sayi` artık **0** — `p`'nin kendisi bir değişken,
istenildiğinde başka bir adresi tutmak üzere değiştirilebilir.

**IS3.** `int *p` bildirimi, `p`'nin **bir `int`'in adresini** tutacağını söylüyor — ama bu
tip, `p`'nin gösterdiği belleğin nasıl elde edildiğini hiç söylemiyor. Yukarıdaki koşumda
`p` önce bir yerel değişkeni (`sayi`), sonra bir başkasını (`baska`) gösterdi; ikisi de
`dil` sınıfındaydı ve kimse onları bırakmadı. Ama `int *` tipi, dinamik olarak ayrılmış bir
bloğu göstermek için de kullanılabilir — çekirdekteki `ayir ve birak` satırı tam olarak
bunu yaptı: `int *blok = say_ayir(...)`. Aynı bildirim, aynı işleçler (`*`, `&`), iki farklı
sahiplik sınıfı. Bu, dersin sınırlayıcı ölçümüdür.

## İşaretçiye İşaretçi: Dolaylamanın İkinci Katmanı

Yukarıdaki `p` değişkeni bir `int`'i gösteriyordu; ama bir işaretçinin kendisi de bir
değişken olduğuna göre, onun adresini tutan başka bir işaretçi de yazılabilir. Bu, tek bir
`*` yerine iki tane kullanmayı gerektiriyor ve dolaylamayı bir kat daha derinleştiriyor.

```c
// cift_isaretci.c — bir isaretciye isaretci, dolaylamayi bir kat daha uygular
#include <stdio.h>

int main(void) {
    int sayi = 9;
    int *p = &sayi;
    int **pp = &p;

    printf("%s %d\n", "iki kat dolaylamayla okunan deger", **pp);
    printf("%s %d\n", "pp p'nin adresini mi gosteriyor", (int)(*pp == p));

    **pp = 30;
    printf("%s %d\n", "iki kat dolaylamayla yazilan yeni deger", sayi);

    int baska = 4;
    *pp = &baska;
    printf("%s %d\n", "pp uzerinden p'yi degistirince p'nin gosterdigi deger", *p);
    printf("%s %d\n", "p artik sayiyi mi gosteriyor", (int)(p == &sayi));
    return 0;
}
```

```
iki kat dolaylamayla okunan deger 9
pp p'nin adresini mi gosteriyor 1
iki kat dolaylamayla yazilan yeni deger 30
pp uzerinden p'yi degistirince p'nin gosterdigi deger 4
p artik sayiyi mi gosteriyor 0
```

**IS4.** `int **pp` bildirimi, `pp`'nin bir `int *`'in adresini tuttuğunu söylüyor —
`pp`, `p`'yi gösteriyor, `p` de `sayi`'yi gösteriyor. `**pp` iki dolaylama işlecini art
arda uyguluyor: önce `*pp` ile `p`'nin taşıdığı adrese ulaşılıyor, sonra ikinci `*` ile o
adresteki değere. `**pp = 30` satırı bu iki katmanlı yolu bir atamanın sol tarafında
kullanıyor ve `sayi` gerçekten **30** oluyor — tıpkı `*p = 100`'ün `sayi`'yi değiştirdiği
gibi, ama araya `p` giriyor. Son iki satır `*pp`'nin, yani `p`'nin kendisinin, yeniden
atanabildiğini gösteriyor: `*pp = &baska` ataması `p`'yi `baska`'yı göstermeye çeviriyor —
`pp` üzerinden, `p`'ye doğrudan erişmeden. Bu ayrım, bir işlevin çağıranın işaretçisini
kendisi değiştirmek istediği durumlarda önem kazanıyor: `int *` alan bir işlev yalnız
gösterilen değeri değiştirebilir, `int **` alan bir işlev çağıranın işaretçisini başka bir
adrese çevirebilir. Sınıf yine `dil`: üçü de yerel değişken, hiçbiri ayrılmadı.

## Sınırlayıcı Ölçüm

Bir işaretçinin tipi, gösterdiği bloğun **kim tarafından bırakılacağını** söylemez. `int *`
bir yerel değişkeni de gösterebilir, `say_ayir` ile ayrılmış bir bloğu da — kaynakta ikisi
de aynı görünür ve derleyici aralarında hiçbir ayrım yapmaz. Yukarıdaki iki koşumda `p`
değişkeni üç farklı anda üç farklı şeyi gösterdi: bir yerel değişken, başka bir yerel
değişken ve (çekirdekte) ayrılmış bir blok. Üçünde de bildirim aynıydı (`int *`). Bir
işaretçiyi okuyan biri, tipine bakarak sahiplik sınıfını **çıkaramaz** — bu bilgi ancak
değişkenin nereden geldiğine (bir `&` ifadesinden mi, bir ayırma çağrısından mı) bakılarak
ya da onu belgeleyen sözleşme okunarak öğrenilebilir. Kursun geri kalanı, bu
sözleşmenin nasıl yazıldığını ve nasıl kırıldığını ölçüyor.

## Özet

- Bir bellek bloğunun sahibi dört sınıftan biridir: **dil**, **çağıran**, **çağrılan**,
  **sahipsiz**; bu ders **dil** sınıfını çekirdeğin tam koşumuyla ölçüyor.
- Beş dosyalık ölçüm çekirdeği (`sayac.h`, `sayac.c`, `sahip.h`, `sahip.c`, `sahiplik.c`)
  on üç gözlemi **4 dil · 4 çağıran · 3 çağrılan · 2 sahipsiz** olarak dağıtıyor; toplam
  fark **2**.
- Adres alma (`&`) bir değişkenin adresini üretir; dolaylama (`*`) o adresteki değeri okur
  ya da ona yazar — ikisi de adres basılmadan, eşitlik ve değerle ölçülebilir.
- Bir işaretçi yeniden atanabilir ve farklı zamanlarda farklı değişkenleri gösterebilir;
  bu, işaretçinin kendisiyle gösterdiği değer arasındaki farktır.
- Bir işaretçinin tipi, gösterdiği bloğun **kim tarafından bırakılacağını** söylemez —
  aynı `int *` bildirimi hem bir yerel değişkeni hem ayrılmış bir bloğu gösterebilir.

## Sonraki Adım

Bu derste ölçülen `yerel dizi` satırı, `son - ilk` farkını **3** olarak verdi ama bu farkın
nasıl hesaplandığı üzerinde durulmadı. Bir sonraki ders, İşaretçi Aritmetiği, bu farkın neden
bayt cinsinden değil **eleman cinsinden** olduğunu ve bir işaretçiyi artırmanın tip boyutuna
göre nasıl ilerlediğini ölçüyor — hâlâ `dil` sınıfında kalarak, ama artık tek bir değere
değil bir dizinin elemanları arasındaki ilişkiye bakarak.
