Yapılar (structures) da diziler gibi birden fazla nesneyi içlerinde tutabilen bir veri türürdür.
Yapıların da elemanları bellekte ardışıl (contigious) bir biçimde bulunur. Fakat yapıların dizilerden temel farkı şudur: Diziler aynı türden nesneleri içinde tutabilirken, yapılar farklı türlerden nesneleri tutabilirler. Yapıların kullanılmasının ana nedeni budur. Çoğu zaman, türleri farklı bir takım nesneler, mantıksal olarak bir bütün oluşturabilirler. İsim, yaş, departman, ücret, öğrenim durumu gibi bilgileri farklı türden nesneler içinde saklayabiliriz ve bunların tamamı çalışan bir personele ait bilgiler olabilir. Bu gibi aynı konu ile ilgili farklı türden veriler yapılar içinde saklanır. Yapı Bildiriminin Genel Şekli <struct > [yapı ismi] { <tür> <m1>; <tür> <m2>; <tür> <m3>; ... }; Yukarıdaki gösterimde struct bir anahtar sözcüktür. Bildirimde mutlaka yer alması gerekmektedir. Yapı ismi (structure tag) C dilinin isimlendirme kurallarına uygun olarak seçilmiş bir isimdir. Örnek bildirimler: struct SAMPLE { int a; long b; char ch; }; struct DATE { int day, month, year; }; struct POINT { int x, y; }; Yapı isimleri (structure tags) geleneksel olarak büyük harfle yazılır. Bu bir zorunluluk değildir. Yapı bildiriminin yapılması bellekte derleyici tarafından bir yer ayrılmasına neden olmaz. Yani bir tanımlama (definition) söz konusu değildir. Bu bildirimle (declaration) programcının yarattığı yeni bir veri türü hakkında derleyiciye bilgi verilmektedir. Yapı bildiriminin yapılmasından sonra artık bildirimi yapılmış yapı türünden nesneler tanımlanabilir. Yapı bilidiriminin yapılması ile yeni bir veri türü yaratılmıştır. Derleyici artık bu tür hakkında bilgi sahibi oldugundan, bu yeni veri türünden, nesneler tanımlanabilir. Yeni veri türünden nesnelerin tanımlanması durumunda artık derleyici bu nesneler için bellekte ne kadar bir alan ayırması gerektiği bilgisine sahip olacaktır. Yapı Türünden Nesne Tanımlaması <struct> <yapı isimi> <nesne ismi>; Örnekler : struct DATE x; /* x DATE yapısı türünden bir nesnedir. */ struct POINT p1, p1; /* p1 ve p2 POINT yapısı türünden nesnelerdir. */ struct SAMPLE sample; /* sample SAMPLE yapı türünden bir nesnedir. */ Yapı değişkenleri bileşik nesnelerdir. Yani parçalardan oluşurlar. Zaten yapı bildirimlerinin yapılmasının amacı da bu parçaların isimleri ve türleri hakkında derleyiciye bilgi vermektir. Bir yapı bildirimini gören derleyici, daha sonra bildirimi yapılan yapı türünden bir değişken tanımlanması durumunda, bu değişken için bellekte ne kadar yer ayıracağını, ve ayırdığı yeri ne şekilde organize edeceğini bilir. Bir yapı değişkeni (nesnesi) için, yapı bildiriminde belirtilen elemanların toplam uzunluğu kadar (byte olarak) yer ayrılır. struct SAMPLE { int a; long b; char ch; }; void main() { struct SAMPLE x; printf("%d\n", sizeof(x)); } Yukarıdaki program parçasında ekrana (DOS altında) 7 sayısı yazdırılacaktır. Çünkü yapı nesnesi olan x nesnesinin bellekte kapladığı yer üç parçasının kapladığı uzunluğun toplamıdır. Bunu aşağıdaki şekilde de ifade edebiliriz: sizeof(x) == sizeof(int) + sizeof(long) + sizeof(char) (Hizalama [alignment] konusuna geldiğimizde bu durumu daha detaylı olarak inceleyeceğiz.) Yapı Elemanlarına Erişim Yapıların dizilerden önemli bir farkı da elemanlara erişim konusundadır. Dizi elemanlarına erişim, dizi ismi (aslında bir adres bilgisidir) ve indis operatörü [ ] (index operator - subscript operator) yoluyla yapılırken, yapı elemanlarına erişim doğrudan yapı nesnesinin ve elemanın isimleriyle olur. Yapı elemanlarına erişimde nokta operatörü kullanılır. Nokta operatörü (.) iki operand alan araek konumunda (binary infix) bir operatördür. Bu operatörün sol tarafındaki operand bir yapı türünden değişken olmalıdır. Sağ tarafındaki operand ise ilgili yapı türününün (yani yapı bildiriminde önceden belirlenmiş) bir üyesi olmak zorundadır. Nokta operatörü, operatör öncelik tablosunun en yüksek düzeyinde bulunur. Yapı nesneleri de yerel ya da global olabilir. Diğer nesnelerde olduğu gibi yapı nesneleri içinde faaliyet alanı (scope) kavramı söz konusudur. Tüm blokların dışında tanımlanan yapı nesneleri global iken blokların içlerinde tanımlanan yapı değişkenleri yereldir. Global yapı nesneleri diğer türden global nesneler gibi statik ömür karakterine sahiptir ve dosya faaliyet alanı kuralına uyarlar. Yerel yapı nesneleri ise dinamik ömürlüdür ve blok faaliyet alanı kuralına uyarlar. Yapı değişkenlerine programcı tarafından değer verilmemişse, yapı değişkeni yerel (local) ise tüm elemanlarında rasgele değerler (garbage value) bulunur. Yapı nesnesi global ise tüm elemanlarında 0 değeri bulunur. Bir yapı nesnesi tanımlanarak, bu yapı nesnesinin elemanlarına nokta operatörü ile ulaşıldığında artık bu elemanların her biri ayrı bir nesne olarak ele alınır. Bu nesnelerin yapı dışında tanımlanan nesnelerden herhangi bir farkı yoktur, nesnelerin tüm özelliklerine sahiptirler. Örnek: struct SAMPLE { int a; long b; char c; }; int main() { struct SAMPLE x; x.a = 10; x.b = 200000; x.c = 'M'; printf("x.a = %d\nx.b = %ld\nx.c = %c\n", x.a, x.b, x.c); return 0; } Yukarıdaki örnekte görüldüğü gibi x.a, x.b ve x.c yapı elemanları ayrı birer nesne özelliği gösterirler. Bu elemanlara ayrı ayrı ulaşabilir ve ayrı ayrı atamalar yapabiliriz. Bu nesneleri ++ ve -- operatörlerine ya da & operatörüne operand yapabiliriz. Yapı Bildirimlerinin Yapılış Yerleri Yapı bildirimi global ya da yerel olarak yapılabilir. Eğer yerel olarak yapılırsa yalnızca bildirimin yapıldığı blokta o yapı türünden nesne tanımlanabilir. Bildirim global olarak yapılırsa her yerde o yapı türünden değişken tanımlanabilir. Uygulamalarda hemen hemen her zaman yapı bildirimleri programın tepesinde global olarak yapılır. (Yapı bildirimi başlık dosyalarının içinde de yapılabilir. Bu durumu ileride detaylı olarak inceleyeceğiz.) Yapı bildiriminde yer alan yapı elemanlarının faaliyet alanı yapı bildirim bloğuyla sınırlıdır. Yani yapı bildirimi bloğu dışında, yapı elemanı ile aynı isimli bir değişken tanımlanabilir. Yapı ismi (structure tag) ile aynı isimli değişkenler de tanımlanabilir. Aşağıdaki program parçasında isimlendirme açısından bir hata yok. Okunabilirlik açısından iyi bir uygulama değil. struct SAMPLE { int sample; long x; }; int main() { int sample, SAMPLE; ... return 0; } Yapı Elemanlarının Bellekteki Yerleşimi Yapı elemanları belleğe, bildirimde ilk yazılan eleman küçük adreste olacak biçimde, ardışıl olarak yerleştirilir. Örnek: struct SAMPLE { int a; long b; char c; }; int main() { struct SAMPLE x; printf("x.a adresi = %p\nx.b adresi = %p\n x.c adresi = %p\n", &x.a, &x.b, &x.c); } Yapı Değişkenlerine İlk Değer Verilmesi (initialization) Yapı değişkenlerine küme parantezleri içerisinde ilk değer verilebilir. Bu durumda verilen ilk değerler sırası ile yapı elemanlarına yerleştirilir. Daha az sayıda yapı elemanına ilk değer verilebilir, bu durumda ilk değer verilmemiş yapı elemanları 0 değeri alırlar. struct DATE { int day, month, year; }; int main() { struct DATE x = {10, 12, 1999}; struct DATE y = {10, 12}; printf("%d %d %d\n", x.day, x.month, x.year}; printf("%d %d %d\n", y.day, y.month, y.year}; } Dizilerde olduğu gibi, yapılarda da yapı elemanlarından daha fazla sayıda elemana ilk değer vermek derleme zamanında hata oluşumuna neden olacaktır. Yapı Elemanı Olarak Göstericilerin Kullanılması Yapının bir elemanı herhangi türden bir gösterici olabilir. Bu durumda bu yapı elemanına ulaşıldıdığında, bu gösterici de yapı elemanı olmayan göstericiler gibi değerlendirilir Örnek: struct PERSON { char *name; int no; }; int main() { struct PERSON x; x.name = "sifirzero"; x.no = 125; printf("%s %d\n", x.name, x.no); return 0; } Yukarıdaki örnekte yapı elemanlarına ilk değer verme sentaksıyla da (initialization) değer atanabilirdi: .... struct PERSON x = {"sifirzero", 125}; ...
Hiç yorum yok:
Yorum Gönder
Her yorum bilgidir. Araştırmaya devam...