1. Reklam


    1. joysro
      ledas
      jungler
      keasro
      zeus
      karantina

İsaretci Yapımı


  1. Leader

    Leader Buralıyım rank8

    Kayıt:
    18 Ağustos 2007
    Mesajlar:
    4.966
    Beğenilen Mesajlar:
    0
    Ödül Puanları:
    0
    İŞARETÇİLER

    Birçok kişi, işaretçilerin gerçek programcıları diğerlerinden ayırdığını düşünür. Bu konuda haksız sayılmazlar, çünkü C ve C++ dillerinde bir sürü işlem (alt programlarla bağlantı, değişkenlere dolaylı yoldan değer atama (indirect Access) bellek bölgelerine ulaşım, dinamik bellek rezerve edilmesi ve kullanımı, dosyalara erişim gibi) ve birçok algoritma (bağlı listeler, sıralama algoritmaları gibi) işaretçiler üzerinden yapılır. Söz konusu algoritmalar olduğunda, her programcı kendine özgü algoritmalar geliştirdiği için işaretçilerin kullanım alanları ve önemleri artar. İşaretçiler özellikle nesneye yönelik programlamada büyük önem kazanırlar. “C ve C++ dilleri (özellikle C dili) işaretçiler üzerine kurulmuştur.” düşüncesi pek te abartılmış sayılmaz.

    İşaretçiler, adlarından da anlaşıldığı gibi bilgisayarın belleğindeki belli bir adresi gösteren (ya da o adrese işaret eden) değişkenlerdir. İşaretçiler tanımlanırken * operatörü kullanılır ve işaretçiler veri tipi * değişken adı şeklinde tanımlanırlar. Aşağıdaki örnek kod satırlarında işaretçilerin tanımlanması gösterilmiştir.

    char * karakter // char tipinde bir değişkeni gösteren işaretçi
    int * tamsayi // int tipinde bir değişkeni gösteren işaretçi
    float * reel // float tipinde bir değişkeni gösteren işaretçi
    double * cift // double tipinde bir değişkeni gösteren işaretçi
    İşaretçi tanımlanırken, önemli onar * operatörünün veri tipi ve değişken adı arasında olmasıdır. Aşağıdaki yazımlardan hepsi genellikle doğrudur.


    int* i1;
    int * i2;
    int *i3;
    int*i4;

    İŞARETÇİNİN KENDİSİ
    İşaretçinin kendisi, gösterdiği değer ne olursa olsun bir tamsayıdır (int). Eğer işletim sistemi olarak DOS kullanılıyorsa bu tamsayı kullanılan bellek modeline göre 16 yada 32 Bit uzunluğunda olabilir. Eğer işletim sistemi olarak Windows 95, Windows NT yada Linux gibi 32 bitlik bir işletim sistemi kullanılıyorsa, işaretçi 32 bitlik uzunluğunda olur. Bilgisayarların ve işletim sistemlerinin bellek organizasyonlarına göre daha farklı uzunlukta işaretçilere rastlamak mümkündür. Fakat burada önemli bir durum söz konusudur. İşaretçilerin içlerindeki tamsayı adrestir. İşaretçilerin içine bakılırsa tamsayı bir değer görülür, ancak bu bir işaretçinin bir tamsayıya eşitlenebileceği anlamına gelmez. Aşağıdaki kod satırı kesinlikle hatalıdır.

    int* i;
    i = 35; // hata

    Bu hatanın nedeni, int* ile int veri tiplerinin birbirlerine çevrilemez oluşudur. Bu çevirme işlemi ancak kasıt operatörü ile yapılabilir fakat genelde anlamsızdır.

    Bir işaretçinin kendisine bir değer atanamaz, fakat işaretçinin gösterdiği bellek adresine bir değer atanabilir. Bunun için * operatörü kullanılır. Aşağıdaki kod satırlarında bu durum gösterilmiştir.

    int* i;
    *i = 35; // şimdi doğru

    İŞARETÇİNİN GÖSTERDİĞİ ADRES
    İşaretçinin içinde bulundurduğu tamsayı, bellekteki belli bir adresi temsil eder. Bu, işaretçinin gösterdiği adrestir. Bu adresin içinde herhangi bir veri tipi veya başka bir işaretçi olabilir. İşaretçinin o bellek bölgesindeki değerle bir ilgisi yoktur. Sadece o bellek bölgesini gösterir. Eğer bellek bölgesindeki değer değişirse, işaretçi bundan etkilenmez ve bu kuralın tersi de geçerlidir. Eğer işaretçinin gösterdiği adres değişirse eskiden gösterdiği adresteki veri değişmez.

    İşaretçinin kendisi, gösterdiği adrese eşittir. (!!!DİKKAT GÖSTERDİĞİ ADRES İÇİNDEKİ DEĞERE DEĞİL!!!). Eğer bir işaretçinin gösterdiği adres içindeki veriye bir değer atanmak isteniyorsa, iki imkan vardır:

    1. * operatörü kullanılır. * operatörü işaretçinin önünde kullanılırsa, işaretçi değil işaretçinin gösterdiği bellek bölgesinin içi kastedilir.

    char* c;
    char karakter;
    karakter = ‘A’;

    2. *c = karakter; // karakter değişkeninin içeriği c işaretçisinin gösterdiği adresin içindeki değere atandı.
    İşaretçinin gösterdiği adres (kendisi) değiştirilir. Bunu yapmak için & operatörü kullanılır. & operatörüne adres operatörü denir.

    char* c;

    char karakter;

    karakter = ‘A’;

    c = &karakter; // karakter değişkeninin adresi, c işaretçisine atandı

    İŞARETÇİNİN ADRESİ
    İşaretçi görevi diğer veri tiplerinden farklı olsa da, bir veri tipidir, baştada anlatıldığı gibi bir tamsayıdır. Dolayısıyla her tamsayı gibi bellekte bir yer kaplar ve belli bir adresi vardır.
    (DİKKAT! İŞARETÇİNİN KENDİ ADRESİ İLE İŞARETÇİNİN GÖSTERDİĞİ ADRES FARKLI KAVRAMLARDIR VE BİRBİRLERİNDEN FARKLI ADRESLERDİR.)

    Bu durumu yapacağımız bir Program aracılığıyla daha iyi anlayabiliriz.

    #include
    void main( void )
    {
    int* i_pointer;
    int i = 5;
    float* f_pointer;
    float f = 2.38;
    i_pointer = &i;
    f_pointer = &f;
    cout << "i_pointer işaretçisinin gösterdiği adres : " << i_pointer << endl;
    cout << "i_pointer işaretçisinin gösterdiği adres icindeki veri : " << *i_pointer << endl;
    cout << "i_pointer işaretçisinin adresi : " << &i_pointer << endl;
    cout << endl;
    cout << "f_pointer işaretçisinin gösterdiği adres : " << f_pointer << endl;
    cout << "f_pointer işaretçisinin gösterdiği adres icindeki veri : " << *f_pointer << endl;
    cout << "f_pointer işaretçisinin adresi : " << &f_pointer << endl;
    cout << endl;
    }

    Programın çıktısı:

    i_pointer işaretçisinin gösterdiği adres : 0xfff2
    i_pointer işaretçisinin gösterdiği adres icindeki veri : 5
    i_pointer işaretçisinin adresi : 0xfff4
    f_pointer işaretçisinin gösterdiği adres : 0xffec
    f_pointer işaretçisinin gösterdiği adres icindeki veri : 2.38
    f_pointer işaretçisinin adresi : 0xfff0

    Kullanılan bellek modeli programın verileri için sadece 64KB’lık bir bellek alanı kullanmasına izin verir (SMALL bellek modeli), bundan dolayı 16 bit uzunluğundaki işaretçiler yeterli olur. Aşağıdaki şemada program çalıştıktan sonra belleğin durumu gösterilmektedir.

    Değişkenlerin adresleri tamamen derleyicinin programa bağladığı özel bir kod tarafından seçilir. Bu kod, program çalıştırıldığı zaman güvenli bellek bölgelerini bulur ve verileri o bölgelere yerleştirir. Program başka bir bilgisayarda çalıştırıldığında, program koduna bazı eklemeler yapıldığında, program başka şartlar altında çalıştırıldığında, seçilen adresler farklı olabilir. Yukarıdaki şemada verilerin 64 KB’lik bloğun sonuna çok yakın yerleştirilmesi tesadüftür. Eğer program Linux gibi 32 bitlik bir işletim sisteminde derlenip çalıştırılsaydı, çıktısında görülen adresler 32 bit uzunluğunda olacaklardı.


    İŞARETÇİ TİPLERİ

    Bütün işaretçiler birer tamsayı olmalarına rağmen değişik işaretçi tipleri mevcuttur. Her veri tipine özgü bir işaretçi tipi vardır ve her veri tipinin adresi, her işaretçiye atanamaz. Atamalara izin konusunda C ve C++ dilleri farklılık gösterirler. Aşağıdaki örnek kod C ve C++ derleyicileri ile derlenirse derleyici farklı şekilde davranır.

    main()
    {
    char* c;
    float f;
    c = &f;
    return 0;
    }

    Programda char tipinde bir işaretçi ile float tipinde bir değişken tanımlanmıştır. Daha sonra char işaretçisine float değişkenin adresi atanmıştır.

    Eğer program C derleyicisi ile derlenirse, derleyici işaretçinin veri tipi ile değişkenin veri tipinin birbirleri ile uyuşmadıklarını anlatan bir uyarı mesajı verir ve program derlenip çalışır kod oluşturulur. Bu başta kulağa hoş ve cazip gelebilir ama bir çok hataya neden olabilir. char tipinde bir işaretçi, char tipinde bir değişkeni göstermek veya char tipindeki bir değişkene dolaylı yoldan erişim sağlamak için tasarlanmıştır ve float tipinde bir değişken ile çalışırken hatalara neden olabilir.

    Eğer program C++ dili ile derlenirse, derleyici işaretçinin veri tipi ile değişkenin veri tipinin birbirleri ile uyuşmadıklarını anlatan hata mesajı verir ve çalışabilir kod üretilmez. C++ dilinin tip dönüşümü kontrolü daha sıkıdır ve programcının hata yapmasını daha iyi engelleyebilir.

    Eğer programcı bütün uyarı veya hata mesajlarına rağmen c işaretçisine f değişkeninin adresini atamaya kararlı ise, kasıt operatörünü kullanmak zorundadır.

    ( float* )c = &f;

    Fakat kasıt operatörü ile char tipindeki bir işaretçiyi float tipinde bir işaretçiye çevirmek yerine doğrudan float tipinde bir işaretçi kullanmak daha mantıklıdır, gene de özel bir durum söz konusu ise kasıt operatörü kullanılabilir.
     
  2. Narqotic

    Narqotic Bilgiliyim rank8

    Kayıt:
    22 Nisan 2007
    Mesajlar:
    1.365
    Beğenilen Mesajlar:
    0
    Ödül Puanları:
    0
    Meslek:
    !!!
    Şehir:
    BeN SeNiN CaNıN İçİN ÖmRüMü BiR KiBRiTiN KaBıNDa T
    Saol Güzel bilgi