C DİLİNDE İŞARETÇİ (POINTER) KAVRAMI — Volume 2

Mesut Topuzlu
5 min readDec 10, 2020

--

Merhabalar. “C Dilinde İşaretçi Kavramı” serimizdeki ikinci yazımızla devam ediyoruz. İlk yazımda işaretçilerden, bildirimlerinden ve bellekte nasıl bir görünüm çizdiğinden bahsettim. Şimdi, işaretçiler konusuna biraz ara verip değinilmesi gereken sizeof() operatörü ve size_t tipinden birazcık bahsedelim.

sizeof() operatorü;

sizeof() operatörü kendisine verilen tipin genişliğini (her ne kadar boyutu da dense, boyut farklı anlamlara da geldiğinden genişlik demeyi tercih ediyorum) bize verir. Yani bellekte ne kadar yer kapladığını. Hemen bir örnekle açıklayalım;

#include <stdio.h>
int main(void)
{
int i; //int bir değişken
char c; //karakter tipinde bir değişken
int dizi[20]; //20 kapasiteli int bir dizi

printf("i'nin genisligi : %zu\n", sizeof(i));
printf("c'nin genisligi : %zu\n", sizeof(c));
printf("int tipinin genisligi : %zu\n", sizeof(int));
printf("dizinin genisligi : %zu\n", sizeof(dizi));
}

Yukarıdaki kodu derleyip çalıştırdığımızda aşağıdaki konsol ekranını görüntüleriz;

Şimdi, konsol çıktısını incelersek i değişkeninin genişliğinin 4-byte, c değişkeninin 1-byte, int tipinin 4-byte ve dizi’nin 80-byte olduğunu görmekteyiz. Burada i zaten int ve int tipinin genişliği 4-byte olduğundan (derleyici spesifik olduğunu unutmayalım) sonucun 4 olması gayet normal. Karakter yani char tipindeki değişkenler ise hafızada 1-byte yer tutar ekranda görüldüğü gibi. Peki ya dizi? Tipi int olmasına rağmen sonucun 80-byte çıkmasının nedeni sizeof() operatörünün bize aslında tüm genişliği hesaplamasıdır. 4-byte x 20 işlemi ile sonucu 80-byte hesaplar. Dizinin kapasitesini de bu eşitliğe dayanarak sizeof(dizi)/sizeof(int) veya daha esnek sizeof(dizi)/sizeof(dizi[0]) şeklinde hesaplayabiliriz.

size_t mi? O da ne?

size_t tipine biraz açıklık getirmek lazım. Aslında size_t işaretsiz (unsigned) int tipinin tür eş ismi olarak belirlenmiştir (bkz: typedef). sizeof() operatörünü kullandığımızda aslında bize genişlik ölçüm sonucunu size_t tipinde döndürür. Yani biz yukarıdaki kodu şu şekilde de yazabiliriz;

#include <stdio.h>
int main(void)
{
int i;
size_t genislik = sizeof(i);
printf("i'nin genisligi : %zu\n", genislik);
}

Kodu derleyip çalıştırdığımızda i’nin genişliğinin yine 4-byte olarak hesaplandığını görürüz. “zu” size_t türünden bir değişkeni gösterebilmek için eklenmiş bir (size_t hangi tür ile typedef edilmiş ise aslıda o belirteci de kullanabiliriz) bir format belirtecidir.

Şimdi, size_t ve sizeof() ile birlikte işaretçiler konumuza geri dönmek istiyorum. Konuyu bir noktadan işaretçilere bağlamam lazım. Ben aşağıdaki kodu bu kez 64-bit Linux/Debian yüklü bir bilgisayarda derledim.

#include <stdio.h>
int main(void)
{
int* iP; //integer bir işaretçi
char* cP; //char bir işaretçi
printf("iP'nin genisligi : %zu\n", sizeof(iP));
printf("cP'nin genisligi : %zu\n", sizeof(cP));
}

Kodu Linux ortamında derlemek için terminalden main.c (tabii siz ne isim verdiyseniz) dosyası konumuna gidip şu komutu vermeliyiz;
#gcc main.c -o main.out

Çalıştırmak için;
#./main.out

Ve benim terminal ekranında şu ifadeler yazdı;

Çalıştırılabilir çıktıyı çalıştırdıktan sonra Linux terminal ekranına baktığımızda iP ve cP genişlikliklerinin 8-byte olduğunu görmekteyiz. Peki ama neden? E hani int 4-byte ve char da 1-byte idi? Sorun işletim sistemi ile mi ilgili? Yoksa derleyici mi? Cevap ikisi de değil. Aslında bu bir sorun da değil. Bu, olması gereken şey. Çünkü biz sizeof() operatörüne iP ve cP işaretçilerinin işaret ettikleri değişkenlerin genişliklerini bul demedik, işaretçilerin kendilerinin genişliklerini bul dedik. İlk yazımızda hatırlarsanız bir i değişkeni tanımlamıştık ve bellekteki adresini 0x000000000061FE14 gibi bir değer bulmuştuk. İşte tam burada biraz incelersek değerin 8-byte yani 64-bit olduğunu görebiliriz. Bu da demek oluyor ki burada bulduğumuz işaretçi adresleri 64-bit’lik bir adres uzayı (yani kümesi) içinde var olabilir.

Şimdi ise kodu birde -m32 opsiyonu ile derleyelim ve çalıştıralım;
#gcc main.c -m32 -o main.out
#./main.out

Hoppaaaaa… Gene ne oldu? Bu kez 4-byte hesaplandı işaretçi genişliği? Esasında durum ne kodun execute edildiği işletim sistemi ne de derleyiciyle ilgilidir. Durum tamamen bizim derleyiciye bildirdiğimiz hedef (target) platform ile ilgilidir. İlk başta kodu derlediğimde, işletim sistemi 64-bit olduğundan derleyici default olarak 64-bit target için derleme yaptı. Ben ne yaptım; ona kodu -m32 opsiyonu (flag) ile 32-bit platform için derlemesini söyledim. İşte tüm mevzu bundan ibaret. Aynı şekilde size_t tipi de hedef platforma göre boyutu 4 ya da 8-byte olabilmektedir (tür eş ismine bakmak gerekir). Bu da demektir ki biz işaretçinin tuttuğu adresi bir değişkene aktarmak ve orada saklamak istediğimizde, bunu size_t tipinde bir değişken ile yapmak esnek ve güzel bir yaklaşım olacaktır. Örneğin size_t addr = p; gibi.

Madem bu kadar bahsettik ilginç bir örnekle pekiştirelim anlattıklarımızı dimi;

#include <stdio.h>
int main(void)
{
int i=201;
int* p=&i;
size_t s = p; //işaretçi, sakladığı adresi başka bir size_t tipli değişkene aktarıyor

printf("s'in degeri : %x\n", s); //s'in işaretçiden devraldığı adres (hex)

printf("i'nin degeri : %d\n", i); //klasik ekrana yazdırma işlemi
printf("i'nin degeri : %d\n", *p); //işaretçi kullanarak yazdır.
printf("i'nin degeri : %d\n", *((int*)s)); //ilginç bir kullanım
}

Evet gördüklerimiz bir hayal değil gerçek :) Hepsinde de i’nin değeri tam olarak ekrana doğru bir biçimde yansıdı. Son printf satırının kullanımı biraz ilginç : s size_t tipinde, p’den devraldığı adresi tutan bir işaretsiz tam sayı olduğu için onu derleyiciye “kardeşim anladık bu bir tam sayı fakat ben aynı zamanda önceden tespit edilmiş bir adrestir diyorum sana” diyebilmek için “işaretçiye dönüştürme (cast)” yani (int*) işlemini yaptık. Yoksa derleyici bunu bir adres olarak algılamaz ve muhtemelen kodu derlemez. Daha sonra int* türüne cast edilmiş bu değeri dereference (adres çözümlemesi) ederek içeriğini ekrana yazdırdık.

Evet bu yazımızın da sonuna geldik. İşaretçiler hakkında başka konulara da değinecektim fakat yazıyı medium’a yükledikten sonra aklıma geldi :) Artık sonraki yazılarımda…

Beyninizde kalıcı bilgi hasarı bıraktıysam ne mutlu bana…

Sağlıcakla kalın.

--

--