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.