YAPI TANIMI
Yapılar farklıtürden fakat birbiriyle alakalı veri tiplerinin bir arada tutulması içinoluşturulmuştur. Diziler konusunda aynı veri tipindeki elemanların ardışılbiçimde bellekte saklanmasında kullanılması görmüştük. Yapılar ise isim, soyisim, öğrenci numarası gibi verilerin bellekte bir bütün içerisindesaklanmasını sağlamaktadır. Bu örnekte her bir öğrenci için farklı bir yapıoluşturarak bu öğrencinin farklı veri tiplerindeki bilgilerini bir arada saklamışoluruz.
Yaniyapılar temelde 3 önemli özellik gösterir
· Farklı tiplerden verilerin bir arada tutulmasınaolanak sağlarlar.
· Bellekte ardışıl olarak sıralanırlar.
· Ve tüm bu veri tiplerine tek bir yapı ismiüzerinden ulaşılmasını sağlarlar.
Yapıların tanımlanması
struct <yapıismi>{
<değişken türü> <değişken adı 1>;
<değişken türü> <değişken adı 2>;
<değişken türü> <değişken adı 3>;
….
} ;
Buradakigösterimde struct bir anahtar sözcüktür. Yapı bildirimin mutlaka yer almasıgerekmektedir. Her yapı nesnesinin ayrıca bir ismi bulunmaktadır. Bu isimaracılığı ile yapı içerisindeki değişkenlere ulaşılabilinmektedir.
Yapıbildiriminin yapılması ile bellekte derleyici tarafından bir yer ayrılmasınaneden olmaz. Burada bir tanımlama söz konusu değildir. Bu bildirimlederleyiciye yarattığımız yeni veri türü ile ilgili bilgi verilmektedir. Yapıbildirimi yapıldıktan sonra artık bu yapının elemanları tanımlanabilir. Eleman tanımlandıktansonra derleyici yapının özelliklerine göre bellekte yer tahsis eder.
struct OGRENCImahmut;
Yazarak mahmutisimli bir nesne tanımlamış olduk bu nesnenin isim, soy isim, numara bilgilerimahmut isimli yapıda tanımlanmıştır.
Yapı elemanlarına erişim ve değer atanması
Yapılarladiziler arasındaki farklardan biri de elemanlara erişim konusundadır. Dizilerdeelemanlara dizi ismi ve [ ] (index operatörü) yoluyla ulaşılırken yapılardaelemanlara erişim yapı nesnesinin ve elemanının ismi ayrıca nokta operatörüylesağlanır.
Nokta operatörü(.) iki operand alan bir operatördür. Bu operatörün sol tarafındaki operand biryapı türünden değişken olmak zorundadır. Sağ yanındaki operand ise bir yapıilgili yapı türünün bir elemanı olmalıdır.
struct SAYI{
int a;
float b;
} ;
main(){
struct SAYI x;
x.a=3;
x.b=3.14;
}
Veya alternatifolarak bir yapının elemanları aşağıdaki gibi de tanımlanabilir.
struct SAYIx={3,3.14};
YAPI NESNELERİ ÜZERİNDE YAPILABİLECEKİŞLEMLER
Yapı değişkenlerbir bütün olarak aritmetik operatörlerle ve karşılaştırma operatörleri ileişleme sokulamaz. Yapı nesneleri üzerinde aşağıdaki işlemleri yapmak mümkündür.
· Bir yapı değişkeninin adresi alınabilir.
· Aynı türden iki yapı değişkeni birbirineatanabilir.
· sizeof operatörü ile bir yapı nesnesininbellekte kapladığı alan bulunabilir.
struct tarih{
int gun, ay,yıl;
};
struct zaman{
int saniye, dakika, saat;
};
struct tarih a;
struct zaman b;
a=b; // derleme zamanında hata oluşur. a ve baynı türden değil.
Yapı türünden adres ve göstericiler
Bir yapıdeğişkenin adresi alınabilir. Bu durumda elde edilen adresin sayısal bileşeniyapının bellekteki başlangıç adresi, tür bileşeni ise yapı ile aynı türdenadrestir. Bir yapı türünden göstericiler de tanımlanabilir. Yapı türündengöstericilere aynı yapı türünden bir adres atanmalıdır.
struct ogrenci*p = &a;
p yapı türündenbir işaretçi ve numara da bu yapının bir elemanı olmak üzere erişim şu şekildeyapılır:
(*p).numara
Burada öncelikoperatörü kullanılması gerekmektedir yoksa önce p.numara ele alınır daha sonra* operatörü işleme sokulurdu. Bu da hata yapılmasına neden olurdu.
Yapı dizileri
Yapılarda programlamadabir tür olarak sayıldıklarından yapı türünden diziler de söz konusudur vesıklıkla kullanılmaktadır. Yapı dizileriyle de normal dizilerin sahip olduğutüm fonksiyonlar özellikler kullanılabilir.
structzaman{
intgun, ay, yil;
};
main(){
struct zamandogumgunu[4]={{12,7,1988},{14,3,1879},{18,4,1955},{22,9,1791}};
struct zaman *pzaman;
pzaman=dogumgunu;
for(int i=0;i<4;i++){
printf(“%d-%d-%d\n”,pzaman->gun, pzaman->ay, pzaman->yil);
++pzaman; }
}
Ok ( -> ) operatörü
Ok operatörü –ve > karakterlerinin beraber kullanılması ile oluşan iki operand alan biraraek operatörüdür. -> operatörünün solundaki operand adres türünden biroperand olmak zorundadır. Sağ yanında ise ilgili yapının bir elemanı olmalıdır.Sol taraftaki yapının sağ taraftakielemanına ulaşmak için kullanılır. p yapı türünden bir nesnenin adresinitutuyor olsun.
(*p).a ve p->a eşdeğerdir.
Yapıların fonksiyonlarda kullanımı
Yapılarınfonksiyonlarda kullanılması 2 şekilde olmaktadır.
1. Yapının kendisinin fonksiyona parametre olarakgeçmesi
Bu yöntemdeyapıların birbirine atanabilmesi özelliğinden yararlanılır. Bu yöntemdefonksiyonun parametre değişkeni bir yapı değişkeni olur. Fonksiyonda aynı yapıtüründen bir değişken ile çağrılır. Bu aşamada atama işlemi gerçekleşir. Fakatbu yöntemde yapının elemanları blok olarak kopyalandığından hem bellek hemdezaman açısından kayıp oluşturur.
struct kisi{
char isim[20];
int dogumyili;
};
void yaz(struct kisi y){
printf(“%s-%d”,y.isim,y.dogumyili);
}
void main(){
struct kisi x={“Michael Faraday”,1791};
yaz(x);
while(!0);
}
2. Yapıdeğişkenlerinin adreslerinin geçirilmesi
Bu yöntemde ise fonksiyonunparametre değişkeni yapı türünden bir gösterici olmaktadır. Fonksiyon bu türdenbir yapı değişkeninin adresi ile çağrılmaktadır. Bu yöntem ilk yönteme göredaha kullanışlıdır ve büyük çoğunluk bu yöntem kullanılmalıdır. Bu yöntemdeyapının adresi sadece kullanıldığından bellekte israfa yol açmaz. Bu özelliğinkullanılmasında yapının bellekteki ardışıllık özelliğinden faydalanılmaktadır.
struct kisi{
char isim[20];
int dogumyili;
};
void yaz(struct kisi *p){
printf(“%s-%d”,(*p).isim, (*p).dogumyili);
}
void main(){
struct kisi x={“Michael Faraday”, 1791};
yaz(&x);
while(!0);
}
Yapıların kullanım yerleri
1) Algısalkolaylık sağlamak amacıyla birbiriyle alakalı olan değişkenler yapı elemanlarıolarak yapıların içerisinde saklanmaktadır.
2) Cdilinde bir fonksiyon en fazla 4, 5 parametre almalıdır. Daha fazla parametreyesahip olması iyi bir yöntem değildir. Şayet bir fonksiyon çok fazla parametreyeihtiyaç duyuyorsa bu parametreleri bir yapı içerisinde tutmak kullanımı kolaylaştıracaktır.
3) Cdilinde fonksiyonların tekbir geri dönüş değeri vardır. Oysa yapıkullanıldığında geri dönüş değeri yapı değişkeni türünde olabilmektedir. Bununiçin önce bilgileri yapı biçiminde ifade etmen ve yapı değişkeninin adresinifonksiyona parametre olarak vermek gerekir. Geri dönüş değeri olarak bilgileryapı değişkeninin içinde olur.
4) Cdilindeki veri türleri sınırlarıdır. Tarih, karmaşık sayılar gibi verideğişkenleri yapılar sayesinde oluşturulabilir.
İÇ İÇE YAPILAR
Bir yapınınelemanı bir baksa türden bir yapının elemanı ise bu yapılara iç içe yapılar(nested structures) denir. İç içer yapıların bildirimi 2 şekilde olur:
1. Önce eleman olarak kullanılan yapı bildirilir. Onunaşağısında diğer yapısı kapsayan yapı bildirilir.
struct tarih{
int gun, ay,yil;
}
struct kisi{
char isim[20];
struct tarihdogumgunu;
}
int main(){
struct kişi mahmut;
mahmut.name=”Mahmut Tuncer”;
mahmut.tarih.gun=32;
mahmut.tarih.ay=13;
mahmut.tarih.gun=1905;
printf(“%s-%d.%d.%d”, mahmut.name,mahmut.tarih.gun, mahmut.tarih.ay, mahmut.tarih.yil);
return 0;
}
2. Diğer yöntemde ise elemana ait yapı genel olan yapınıniçerisinde verilir.
struct kisi{
char isim[20];
struct tarih{
int gun,ay,yil;
};
};
int main(){
struct kisix={“Mahmut tuncer”,{32,13,1904}};
}
Bir yapınınelemanı başka bir yapı türünden yapı göstericisi olabilir.
struct tarih{
int gun, ay,yil;
} ;
struct kisi{
char isim[20];
struct tarih *dogumgunu;
};
Butanımlamada struct kisi x gibi bir tanımlama yapılmış olsun.
· x.dogumgunu ifadesinin türü struct tarihtüründen birinden adrestir ve bir nesne belirtir. Çünkü dogumgunu bir göstericideğişkenidir.
· x.dogumgunu->gun bir nesne belirtir ve türüint dir.
· &x.dogumgunu->ay int türünden bir adresbelirtir.
Biryapının elemanı kendi türünden bir yapı değikeni olmaz fakat kendi türünden biryapı işaretçisi olabilir ki bu çok kullanılan bir durumdur.
structlist{
inta;
structlist *next;
};
Bu yapılarözellikler bağlı listelerde ve ağaç yapıları üzerinde çalışılırken sıklıklakullanılacaktır. Veri yapıları konusunda bağlı listeler (linked list) oldukçasık karşımıza çıkacaktır. Bağlı listeler ardışıl olarak tutulmayan listelerinbağlanmasında kullanılır. Her eleman kendinden sonraki elemanın adresinisaklamaktadır. Böylece bağlı listenin tüm elemanlarına ulaşmak mümkün halegelmektedir. Son elemana ait gösterice de ise NULL adresi bırakılmaktadır.
BİRLİKLER ( UNIONS )
Birliklerdeyapılar gibi birbiri ile alakalı verilerin bir arada saklanmasını sağlartanımlanmaları ve gösterimleri aynı şekildedir ama aralarında fark yaratanönemli bir nokta vardır. Bir yapı tanımladığımızda bu yapıdaki tüm elemanlariçin bellekten ardışık olarak yer ayrılmaktaydı. Fakat birliklerde buelemanların sadece biri kullanılacağı durumlarda bellekte yer sağlamak içinbirliklere başvurulmuştur. Birliklerde derleyici birlik elemanlarını bellekteen çok yer kaplayan elemanın boyutu kadar yer ayırarak saklanmaktadır.
struct kisi{
charisim;
intyas;
union{
intaskereAlınmaYili;
charkızlıkSoyadi;
}bilgi;
} ;
Burada kişiyapısı içerisinde tanımlı bir birlik bulunmakta. Burada dikkat etmemiz gerekennokta birlik elemanlarının aynı anda ikisinin birden tanımlanması mümkündeğildir. Askere giden bir erkeğin kızlık soyadı olmaması, kızlarında askeregitmediğini farz edersek bu durumda bellekteki fazla yer harcamasını engellemekiçin birlik kullanmaktayız. Birlik elemanları int ve char tipindetanımlanmıştır. Bunlardan bellekte en fazla yer tutan eleman birliğin bellekteayıracağı alanı belirleyecektir. Birliğin bellekte kapladığı alan sizeof(int)olarak belirlenir. Fakat bir yapı tanımlamış olsaydık kullanmasaktasizeof(char) + sizeof(int) değeri kadar bellekten yer ayrılmış olacaktı. Bubağlamda birlik kullanmak bellekten kazanç sağlamada sıklıkla kullanılmaktadır.