YAPILAR

 

Bir program yaparken, çoðu kez, belirli ama farklý türden verilerin bir tek kayýt içinde birarada bulunmasýnýn yararlý ve hatta gerekli olduðu durumlarla karþýlaþýrýz. Birden çok verinin (deðiþkenin) bir araya getirilmesiyle oluþturulan yeni birime (veri türüne)  C dilinde bir yapý (structure) adý verilir. PASCAL'da bunlara record denilmektedir. Örneðin, bir toptancýdaki mallarýn stok durumunu belirlemek için yazýlacak bir Stok Kontrol programinda þu bilgilere gerekseme olacaktýr:

 

1.                  Malin kod numarasý

2.                  Malýn adý

3.                  Malýn mevcudu (kaç tane varoldugu)

4.                  Malýn alýþ fiyatý

 

Tabii, iþyerinin istek ve gereksemelerine baðlý olarak, malýn hangi iþletmeden alýndýðý, hangi tarihte alýndýðý, satýþ fiyatý, v.b. bilgiler stok kontrol programýna konulabilir. Ancak, yapýyý daha basit tutabilmek için yukarýdaki dört veriden oluþan bir yapý oluþturalým.

C dilinde bir yapý belirlemek için struc anahtar sözcüðü kullanýlýr. Ýstenirse, bir ad verilebilir ve bu yapýyý temsil edecek deðiþkenler bu adla bildirilir. Ýstenirse yapýya ad verilmez, yapý tanýmýndan sonra onu temsil edecek deðiþkenler hemen bildirilir. Bu seçenekleri aþaðýdaki örneklerle inceleyeceðiz:

 

1.         Adsýz Yapý Tanýmlama:

 

struct  {

int            kodno;

char            malýn_adý[30];

int            mal_mevcudu;

float alýþ_fiyatý;

} mal1,mal2;

 

Burada struct anahtar sözcüðünden sonra ({) blok  simgesiyle baþlýyan blok içine yapýda yer almasý istenen bilgileri temsil edecek öðeler  yerleþtirilmiþ ve bu iþlem bitince (}) simgesiyle blok kapatýlmýþtýr. Bu öðelere yapýnýn bileþenleri diyeceðiz. Ýstenen bileþenler blok içine, aynen deðiþken bildiriminde yapýldýðý gibi deðiþkenin türü ve adý belirtilerek yerleþtirilmektedir. struct sözcüðünden sonra açýlan { } bloku içinde  belirlenen yapýyý temsil edecek deðiþkenler, blok bitiþ simgesi olan } den hemen sonra bildirilmiþtir. Burada { } içindeki yapýyý temsil eden mal1 ve  mal2 adlý iki deðiþken tanýmlanmýstýr. Ýstenirse daha az  ya da daha çok deðiþken tanýmlanabilirdi.

 

2. Yapýya kimlik (ad) verme

 

Yukarýdaki tanýmda struct anahtar sözcüðünden hemen sonra istenirse yapýya bir ad konulabilir. Örneðin,

 

struct katalog {

int            kodno;

char            malýn_adý[30];

int            mal_mevcudu;

float alýþ_fiyatý;

} mal1,mal2;

 

yazýlýrsa, yapýlan is yukarýdakine denk olmakla birlikte {} içindeki yapýya katalog adý verilmiþ olur.

 

C dilinde yapý'ya ad vermek zorunlu deðildir. Ancak, büyük bir programýn deðiþik fonksiyonlarýnda bu yapýyý temsil edecek deðiþkenlerin tanýmlanmasý gerekiyorsa, ya da bu yapýdan yararlanýlarak yeni yapýlar türetilmek isteniyorsa, yapýya ad vermekte yarar vardýr. Bu durumda, yapýyý temsil edecek deðiþkenleri, gene yukarýdaki örneklerde olduðu gibi, blok bitiþ simgesi olan (}) dan hemen sonra  bildirebiliriz. Ancak yapýya ad verdikten sora, o yapýyý temsil edecek deðiþkenleri tanýmlamanýn daha iyi bir yolu vardir:

 

3. Yapý adýna gönderme yoluyla deðiþken tanýmlama:

 

struct katalog {

int            kodno;

char            malýn_adý[30];

int            mal_mevcudu;

float alýþ_fiyatý;

}

 

struct katalog mal1,mal2 ;

 

bildirimi yukarýdaki bildirime denktir. Burada görüldüðü gibi, once  katalog adlý bir yapý tanýmlanmiþ, sonra bu yapýyý temsil eden mal1 ve mal2 deðiþkenleri ayrý bir bildirim olarak verilmiþtir.  Degisken bildiriminin yapýldýðý son satýr, hemen yapý tanýmýndan sora gelebileceði gibi, program içinde yapý bildiriminden sonra istenilen herhangi bir yerde yapýlabilir.

 

Özetlersek, C dilinde bir yapý tanýmý için sözdizimi

 

depo sýnýfý struct ad {

            yapý bileþenleri;

            };

 

biçimindedir. Tanýmda struct anahtar sözcüðünun kullanýlmasý zorunludur. Depo sýnýfý ve ad istenirse kullanýlabilir. { } bloku içindeki bileþenlerin tanýmý, C dilindeki deðiþken tanýmlama yöntemiyle yapýlýr: Bileþenleri temsil eden deðiþkenlerin türleri ve adlarý yazýlýr, deyimler (;) ile birbirlerinden ayrýlýr. Ayný türden deðiþkenler (,) ile birbirlerinden ayrýlarak tek bir deyim halinde verilebileceði gibi, herbiri ayrý bir deyim olarak da verilebilir.

 

4. Yapýya baslangýç deðer adama:

 

C dilinde temel yapý türlerini temsil eden deðiþkenlere ve arraylere, istenirse,bildirim sirasinda baslangýç deðerlerinin hemen adanabilecegini biliyoruz (bak, s.  ) . Benzer iþlem yapý temsil eden deðiþkenler  için de gecerlidir. Örneðin, ilk bildirimde mal2 adlý deðiþkene baslangýç deðerleri adamak için

 

struct  {

int            kodno;

char            malýn_adý[30];

int            mal_mevcudu;

float alýþ_fiyatý;

} mal1, mal2 = {251, "Buzdolabi", 12, 1500000};

 

yazmak yeterlidir. Bu bildirim, mal1 adlý deðiþkene baslangýç deðeri vermezken, mal2 adlý deðiþkenin temsil ettigi nesnenin kodnosunun 251, adýnin buzdolabi, stoktaki mevcudunun 12, alýþ fiyatýnin 1500000 oldugunu belirlenmiþ olur.

 

Denk adamayi ucuncu tanýmlama yönteminde yapmak isteseydik, son satir yerine

 

            struct katalog mal1,mal2= {251, "Buzdolabi", 12, 1500000};

 

yazabilirdik.

 

Yapýdaki Bileþenlere Eriþim

 

Bir yapýnýn bileþenlerine deðer adamak ya da daha once adanmiþ olan deðerleri okumak için direk ve indirek yöntemler olmak uzere iki yöntem vardir:

 

a. Direk Yontem:

Bir yapýyý temsil eden deðiþkenlere, yukarida gösterildiði gibi baslangýçta deðerler verilebilir. Ancak, coðu kez program çalýþirken bu deðerlerin deðiþtirilmesi gerekebilir ya da adanacak deðerler program tarafindan hesaplanacaðý için baslangýç deðerleri verilemeyebilir. Bu nedenle, yapýyý temsil eden deðiþkenlerin bileþenlerine istedigimiz her an  eriþebilmemiz gerekir. Bunun için bileþenleri birer deðiþken olarak kullanabilmemiz gerekir. Bunu saglamak için, yapýyý temsil eden deðiþken adý yazýlýr, bir (.) konulur, bileþen adý yazýlýr. Örneðin, yukarýdaki yapýyý temsil eden mal1 deðiþkeninin bileþenlerine deðer adamak için

 

mal1.kodno = 534;

mal1.malýn_adý = "Sandalye";

mal1.mal_mevcudu = 126;

mal1.alýþ_fiyatý = 215;

 

yazmak yeterlidir. Bileþenleri temsil eden bu deðiþkenler, C dilinde aynen oteki deðiþkenler gibi kullanýlabilirler. Dolayýsýyla, ayný türden baþka deðiþkenlerin deðerleri yapýnýn  bileþenlerrine aktarilabilir ya da tersi iþlem yapýlabilir. Örneðin, yukarýdaki katalog yapisini iceren bir programda

 

int m, n=542;

char ad1[30], ad2[30]= "Camasir Makinasi" ;

float x, y=2356.50;

struct katalog mal1,mal2, *p;

 

bildirimi yapilmiþ olsun. Çaðdaþ C derleyicilerinin hemen hepsi bir yapýyý tümüyle ayný türden bir baþka yapýya aktarabilir. Baska bir deyisle,

 

            mal1 = mal2;

 

deyimi mal2 deðiþkeninin bütün bileþenlerinin deðerlerini mal1 deðiþkeninin ayný adlý bileþenlerine aktarýr.

 

m = mal2.kod_no;

 

deyimi, mal2 adlý deðiþkenin kod_no adlý bileþeninin deðerini m deðiþkenine aktarir.

 

mal1.mal_mevcudu = n;

 

deyimi n deðiþkeninin deðerini mal1 deðiþkeninin mal_mevcudu adlý bileþenine aktarýr.  n deðiþkeninin deðeri 542 olduguna göre, Bu adamadan sonra,

 

mal1.mal_mevcudu == 542;

 

deyimi doðru olacaktýr. Benzer biçimde

 

mal1.malýn_adý = mal2.malýn_adý;

 

deyimi mal2 deðiþkeninin adýný mal1 deðiþkeninin adý bileþenine aktaracaktir.

 

b. Dolaylý (indirect) eriþim

Yapýyý iþaret eden bir pointer yardýmýyla bileþenlere eriþmek olanaðý vardýr. Bunu önce bir örnekle göstereceðiz. Yukarýdaki katalog adlý yapýyý ele alalým.

 

            struct katalog mal, *p;

 

bildirimi, bu yapýyý temsil eden mal adlý bir deðiþken ile o tür bir deðiþkeni iþaret edecek p adlý bir pointer tanýmlar. Daha sonra, kaynak programýn uygun görülecek herhangi bir bloku içinde

 

            p = mal;

 

adamasý yapýlýrsa, p pointeri mal adlý bir deðiþken ile o tür bir deðiþkeni iþaret etmeye baþlar. Bundan sonra, örneðin, mal adlý deðiþkenin kodno adlý bileþenini temsil eden

 

            mal.kodno

 

deðiþkeni

 

            p->kodno = 534;

 

adamasý

 

            p->kodno =534;

 

adamasýna denktir. Baþka bir deyiþle p-> kodno ögesini bir deðiþken gibi kullanabiliriz; bu deðiþkenin türü kodno'nun türüdür. Bu yönteme, yapýnýn bileþenlerine dolaylý eriþim yöntemi diyoruz. Bu yöntemin saðladýðý önemli kolaylýklarý ileride göreceðiz. Öncelikle, p->kodno bir deðiþken olduðundan, onunla, kendi türünün izin verdiði her türlü iþlemi yapabiliriz. Ayrýca p bir pointer olduðundan, gerekli durumlarda pointerin hünerlerinden de yararlanabiliriz. Örneðin,

 

            mal.kodno  = 534;

            p->kodno   = 534;

            (*P).kodno = 534;

 

adamalarý birbirlerine denktir.

 

Dolaysýz eriþimdeki (.) operatörünün öncelik sýrasý * operatörünün öncelik sýrasýný aþar; yani parantez kullanýlmadan ayný satýrda * ve . operatörleri yazýlý ise, derleyici önce . operatörünü iþler. Dolayýsýyla, yukarýdaki adamalarýn son satýrýndaki ()ler gereklidir.

 

p-> kodno bir deðiþken olduðuna göre, bunun adresini gerektikçe program içinde kullanabiliriz;bu adres

 

            &(p->kodno) ögesi ile temsil edilir. Ancak -> operatörünün öncelik sýrasý & adres operatörününkinden önde olduðu için, yukarýdaki öge

 

            &p->kodno

 

ögesine denktir; her ikisi de p->kodno deðiþkeninin adresini gösterir. Bu nedenle, örneðin, printf() fonksiyonu ile ekrana çýktý gönderilecekse

 

            printf("%d",p->kodno);

 

deyiminin yazýlmasý gerekir. Öte yandan, scanf() fonksiyonu ile klavyeden giriþ yapýlacaksa

 

            scanf("%d",&p->kodno);

 

deyiminin yazýlmasý gerekir. Çünkü, scanf() fonksiyonu deðiþkenin adresini ister.

 

Özetle, x deðiþkeni bir yapýyý, p pointeri de x deðiþkenin adresini gösteriyorsa

 

            p->bileþenin_adý

 

ögesi, x deðiþkeninin sözkonusu bileþenini temsil eden bir deðiþkendir. Bu deðiþken, türünün girebildiði bütün iþlemlere girer ve ayný kurallara uyar.

 

C dilinde yapýlar kullanýcýnýn tanýmladýðý bir veri türüdür. Dolayýsýyla bu türlerle ilgili deðiþkenlerin, pointerlerin, fonksiyonlarýn ve arraylerin tanýmlanmasý mümkündür.

 

1.Ornek

 

struct katalog mal, (*beyan)(), mallar[1000];

 

deyimi, katalog adlý yapýyý temsim eden mal adlý bir deðiþken, deðeri katalog olan bir fonksiyonu isaret eden beyan adlý bir pointer, ve kataloglardan oluþan mallar adlý 1000 dizinlik bir array tanýmlar.

 

Ýç içe yuvalanmýþ yapýlar

C dili yapýlarýn iç içe yuvalanmasýna izin verir. Genel olarak, iç içe yuvalanmýþ yapýlarý iki türlü oluþturabiliriz. Aþaðýdaki iki örnek bu yöntemleri açýklamaktadýr.

 

1. Bir yapý içine baþka bir yaphýyý çaðýrma

 

struct personel {

char   soyad[20];

char   ad[20];

int    sicilno;

int          derece;

};

stuct birim {

char   ad[20];

struct personel sef;

struct birim altbirim[10];

};

struct daire {

char   ad[20];

struct personel baskan;

struct birim altbirim[15];

};

struct daire m;

#include <stdio.h>

 

main() {

m.altbirim[7].sef.sicilno = 2547;

printf("%dn" ,m.altbirim[7].sef.sicilno);

}

 

Dikkatle incelenirse, kaynak programda tanýmlanan daire adlý yapýnýn birim adlý yapýyý çaðýrdýðý veonun da personel adlý yapýyý çaðýrdýðý görülür. Böylece, örneðin, daire'nin üçücü bileþeninde bildirilen dizinin sekizinci öðesinin (altbirim[7]) þefinin sicilno'suna eriþmek için, dolaysýz eriþim yöntemini arka arkaya kullanabiliriz:

 

            m.altbirim[7].sef.sicilno

 

Bu öge bir deðiþkendir ve iç içe yuvalanmýþ üç yapýnýn en içtekinin bir bileþenini temsil etmektedir.Farklý yapýlar içinde, ayný deðiþken adýný kullanmak mümkündür. Örneðin, her üç yapýda da ad  adýyla birer bileþen vardýr. Derleyici bunlarýn herbirisine ayrý yerler ayýracaðýndan, birbirleriyle karýþmazlar. Buna göre, Örneðin

 

            strcpg(m.altbirim[3].memur[9].ad, "Tekin Uludere");

 

adamasý. dördüncü altbirim'de çalýþan sonuncu memurun (memur[9]) adýna adama yapacaktýr.

 

2.Bir yapý içinde baþka bir yapýyý tanýmlama

žimdi, yukarýdaki programa denk iþ yapmak üzere, ayný yapýlarý iç içe yuvalayarak bildiren bir program yazalým:

 

            struct daire

                        {

                        char ad[20];

                           struct birim

                                    {

                                    char ad[20];

                                                struct personel

                                                            {

                                                            char  soyad[20];

                                                            char  ad[20];

                                                            int   sicilno;

                                                            int   derece;

                                                            } baskan,sef,memur[10];

                                                } altbirim[15];

                                    } m;

                        #include <stdio.h>

                        main()

                                    {

                                    m.altbirim[7].sef.sicilno = 2547;

                                    printf("%d\n",m.altbirim[7].sef.sicilno);

                                    }

 

Bu kaynak programlarýn her ikisini de deyim deyim çözümleyiniz.

 

2.Ornek

 

            struct katalog mal, *p ;

için, yukarýdaki öge

 

            &p->kodno

 

ögesine denktir; her ikisi de p->kodno deðiþkeninin adresini gösterir. Bu nedenle

            printf("%d",p->kodno);

 

deyiminin yazýlmasý gerekir. Öte yandan, scanf() fonksiyonu ile klavyeden giriþ yapýlacaksa

 

            scanf("%d",&p->kodno);

 

deyiminin yazýlmasý gerekir.