ANA SAYFA    |    YAYINLAR    |    BİYOGRAFİ    |    KONUŞMALAR    |    HABERLER    |    DİĞER    |

Kitabin asil yazari

TEMEL PASCAL

newDüzenlemeler
 
BÖLÜM 4 : Kullanıci Tanimlı Veri Tipleri

Halihazırda veri tiplerinin kullanıma sunulmasından sonra Pascal dili ile beraber gelen en önemli özelliklerden biride yeni veri tiplerini tanımlama olanağıdır.Kullanıcılar Type bildirimi ile alt tipler, diziler, record tipleri, enumerated tip, pointer ve küme tipleri gibi yeni tipler yaratabilirler. En önemli kullanıcı tanımlı veri tipi Class’lardır. Bu konu Object pascalın Object Oriented uzantısıdır ve bu konu hakkında bahsedilmeyecektir.

Yeni tip tanımına olanak veren birçok programlama dili bulunmaktadır. Pascal bunlar arasında en sade ve formal yolla tip tanımı yapan dillerdendir.

Adlı ve Adsız Tipler

Bu çeşit tiplere sonradan kullanılmak üzere bir ad verilebilir yada bir değişkene direkt olarak uygulanabilir. Bir veri tipine ad verdiğiniz zaman program kodu içerisinde özelbir bölüm içerisinde belirtmeniz gerekir. Örneğin :
type
// Alt tip tanımı
Buyukharfler = 'A'..'Z';
// dizi tanımı definition
Sicakliklar = array [1..24] of Integer;

// record tanimi
Tarih = record
Ay: Byte;
Gun: Byte;
Yil: Integer;
end;

// enumerated tip tanimi
Renkler = (Kirmizi, Sari, Yesil, Mavi, Turuncu, Pembe);

// Küme Tanimi
Letters = set of Char;

Benzer tip tanımları direkt olarak bir değişken tanımlamak için şöyle kullanılabilir.

var
OcakSicakliklari: array [1..31] of Byte;
RwnkKodu: array [Kirmizi..Pembe] of Word;
Palet: set of Renkler;

NOT: Genelde yukarıdaki örnekteki gibi adsız veri tiplerinden kaçınmanız gerekir, çünkü bunlari parametre olarak gönderemediğiniz gibi ayni tipten verileri tanimlamanızda zorlaşır. Pascalda tip tanımlama kuralları ve tipler arasındaki uyum, tiplerin adları üzerine kurulmuştur. Örneğin a ve b diye iki değişken tanımladık ve bunlar 1..100 arası değer alabilen değişkenler. Tipleri ise kullanıcı tarafından tanımlanmış ve tip isimleri a ve b değişkenleri için farklı olsun. Her nekadarda bu iki değişkenin aldığı değer aralığı aynı olsada tip isimleri farklı olduğu için Derleyici tarafından farklı tipler olarak algılanır. Adsız tipler içinse compiler tarafından bir isim ataması yapılır. Karmaşık yapıdaki değişkenler için yeni veri tipleri tanımlayarak, bu iş için harcayacağınız zamana deydiğini göreceksiniz.

Bu tip tanımlamasıda ne anlama geliyor diyebiliriniz? Bu konuya acıklık getrmsi için Pascalda tip tanımlamasının nasıl yapıldığını anlatacağım. Bunun yanı sıra diğer diller ile arasındakı farkıda gostererek bu konuyu zaten bilenlerinde ilgisini b noktaya toplamaya çalışacağım. Son olarakta birkaç delphi orneği ve araçlardan bahsedip dinamik olarak tip bilgilerin nasıl erişileceğini göstereceğim.

SUBRANGE TİPLER

Subrange veri tipi varolan veri tiplerinin tanım aralığının dahada kısıtlanması ile oluşturulan veri tipleridi. Daha önceden tanumlı olan Integer veri tipini kullanarak 1..10 arasında değer alan yeni bir subrange veri tipi oluşturabilirsiniz. Yada Char veri tipini kullanarak aşağıdaki gibi yeni bir subrange veri tipi oluşturabilirsiniz.

type
ON = 1..10;
YuzUzeri = 100..1000;
BuyukHarf = 'A'..'Z';

Subrange veri tipi oluştururkn ana veri tipini belirtmek zorunda değilsiniz. Sadece ana veri tipinin iki sabtini belirtmeniz gerekir. Orjina veri tipi ordinal tipte olmali ve yeni oluşturulan veri tipide ordinal tipte olacaktir. Eğer subrange bir veri tipi tanımladıysanız bu tiptek değişkene atayacağınız değer aralığı tipin alt ve ust değerleri ile sınırlıdır.

Örneğlin aşağıdaki kod geçerli bir örnektir:

var
Bharf : BuyukHarf;
begin
BHarf := 'F';

Fakat aşağıdaki kod geçerli bir kod değildir

var
BHarf: BuyukHarf;
begin
BHarf := 'e'; // compile-time hatası

Delphi yukarıdaki kodu derleyecektir fakat Range Checking Compiler opsiyonunu seçtiyseniz. Range Check Error hatasını alacaksınız.

NOT: Size önerim bu opsiyonu açık bırakmanız olacaktır. Böylece daha güvenilir ve hatalrı kolayca ayılayableceğiniz bir program geliştirmiş olursunuz. Yada bu opsiyonu kapatıp programın son halini derlerken açarak biraz hız kazanmış olursunuz. Her halükarda kazanacağınız hız fazla olmayacaktır bu sebeple opsiyonu açık bırakmnızı öneririm. Bu önerim stack ve overfow opsiyonları içinde geçerli olacaktır.

ENUMERATED TİPLER

Enumerated veri tipi kulanıcı taımlı veri tipinin başka br çeşididir. Varolan bir tipin değişim aralığını vermek yerine, olası biin değerleri yeni yaratacağınız tipte belirtmeniz gerekir. Diğer bir deyişle enumerated veri tipi bir değerlr listesidir. İşte birkaç örnek :

Type
Renkler = (Kirmizi, Sari, Yeşil, Mavi, Turuncu);
Kartlar = (Kupa, Papaz, vale);

Listedeki her değer 0 dan başlayan ordinal bir değere sahiptir. Eğer bu listedeki değerlerden birisini ord fonksiyonu ile birlikte kulanırsanız sıfırı temel alan bir değerin geri donduğünü görürsünüz. Örneğin ord(Sari) 1 değerini geri dönderecektir.

NOT: Enumerated veri tipleri Delphi içerisinde 8 bitlik bir değer ile gösterilir. Eğer listeniz 256 elemandan fazlaysa Delphi 16bit lik bir gösterim kullanır. Bunun yanında 32 bitlik gösterimde bulunmatadır böylelikle C ve C++ uyumluluğuda sağlanmış olur. Varsayım olarak kullanılan 8 bitlik gosterimi değiştieblir ve 16 yada 32 bit yapabilirsiniz bunun için $Z compiler direktifini kullanabilirsiniz. Delphideki VCL(Visual Component Library) enumerated veri tiplerini birçok yerde kullanmaktadır. Mesela Border”ın style”I şöyle tanımlanmıştır

type
TFormBorderStyle = (bsNone, bsSingle, bsSizeable, bsDialog, bsSizeToolWin, bsToolWindow);

Eğer değer özelliği enumerated veri tipinde ise bu değerleri Object inspector penceresinden seçebilirsiniz.


Şekil 4.1 : Object Inspecter penceresinde enumerated veri tipi


SET (KÜME) TİPİ

Set tipi bir gurup değerden oluşmaktadır. Bu değerler kümenin üzerine kurulmuş olduğu ordinal veri tipine göre belirtilirler. Bu ordinal veri tipleri genellikle sınırlıdır, enumerated yada ordnal tpte gösterlir. Eğer subrange olarak 1..3 alrsak bu kümenin alacağ değerler sadece 1, sadece 2, sadece 3, 1 ve 2, 1 ve 3 , 2 ve 3, hepsi yada hiçbiri.

Bir değişken tanım aralğındaki değerlerden yalnızca birini alır. Halbuki küme tipi ile tanımlanmış bir değişken bırden fazla değer alabilir. Bir küme değişkeni içerisinde bırden fazla değer tanımlamak için köşeli parantez içerisinde virgullerle ayrılmış değerleri yazmamız yeterli olacaktır. İştesize bir örnek :

type
Harfler = set of buyukharf;

Şimdi bu tipte bu tipte bir değişken tanımlayıp ordınal tipte birkaç değer atayabiliriz. Aşadaki örnek birdeğişkene değerlerin nasıl atandığını gstermekte.

var
harfler1, harfler2, harfler3: harfler;
begin
harfler1 := ['A', 'B', 'C'];
harfler2 := ['K'];
harfler3 := [];

Bir pencerenin border”I için mümkün olan değerleri aşağıdaki kod ile belirtmekte mümkündür Delphi içerisndede aynı kod kullanılmaktadır.

type TBorderIcon = (biSystemMenu, biMinimize, biMaximize, biHelp);
TBorderIcons = set of TBorderIcon;

Bu tanımla bir pencerenin icon türünü belirleriz. Object ınspector penceresinden herhangi bir formun borderıcons özelliğini çift tıkladığınız zaman açılan alt özellikleri true yada false yaparak kümeye dahil edebilirsiniz.


Set veri tipi üzerine kurulmuş diğer bir özellikte yazı fontunun sitilidir. Mümkün olan değerler bold, italik, underline, ve striketheough dur. Ve tabiki yazının stili bu özelliklerden bir yada daha fazlası olabilir. Böyle bir kümeye programodu yazarak değer ataabilmek için aşağıdaki örneği inceleyiniz.

Font.Style := []; // sitilsiz
Font.Style := [fsBold]; // kalın yazı sitili
Font.Style := [fsBold, fsItalic]; // hem italik hem kaın yazı

Ve tabiki iki kümeyi kullanarakda işlem yapabilirsiniz. Mesela iki kümenin kesişimini yada brleşimini almak gibi işlemleri geröekleştirebilirsiniz.

Font.Style := OldStyle + [fsUnderline]; // iki küme


ARRAY (DİZİ) TİPLERİ

Array veri tipi belirli sayı ve tipteki elemanların liste şeklinde tanımıdır. Array’in herhangi bir elemanına köşeli parantez içerisinde bir endeks numarısı ile erişilir. Köşeli parantezler ayrıca array tanımı yapılırken array’in boyutlarını belirlemek içinde kullanılır. Örneğin aşağıdaki kod ile 24 tane integer veri tipinde bir array yapısı oluşturulur.

type
SicaklikListesi = array [1..24] of Integer;

Arrayın tanımı gereği, bir array tipi tanımlarken köşeli parantezler içerisinde o array’in boyutları belirtilmelidir. İkinci bir yöntem ise köşeli paratez içerisinde ordinal veri tiplerini kullanılarak bu boyutların belirlenmesidir.

Bu sınırlar array’in geçerli olan boyutlarını belirler. Bir array veri tipinin alt ve üst sınırlarını tanımladıktan sonra C, C++, Java ve diğer programlama dillerinde olduğu gibi sıfır tabanlı bir endeks oluşturma zorunluluğu yoktur.

Bir array’in alt ve üst sınırlarını tanımladığımıza göre Delphi önceden bildiğimiz üzere bu aralığın geçerliliğini kontrol eder. Bu sınırlar dışında bir endeks kullanıldığı zaman Compiler opsiyonlarındaki seçeneklere bağlı olarak ya derleme esnasında yada çalışma esnasında ‘invalid constant subrange’ geçersiz endeks aralığı hatası alınır. Array yapısının yukarıda yapılmış olan tanımını kullanarak SicaklikListesi veri tipinin GunlukSicaklik1 adındaki değişkenini şu şekilde yapılandırabilirsiniz:

type
SicaklikListesi = array [1..24] of Integer;

var
GunlukSicaklik1: SicaklikListesi;

procedure SicaklikTanimlama;
begin
GunlukSicaklik1 [1] := 54;
GunlukSicaklik1 [2] := 52;
...
GunlukSicaklik1 [24] := 66;
GunlukSicaklik1 [25] := 67; // derleme – zamanı hatası

Array veri tipi aşağıdaki örnekte görüldüü gibi çok boyutlu olabilir:

type
AylikSicakliklar = array [1..24, 1..31] of Integer;
YillikSicakliklar = array [1..24, 1..31, Jan..Dec] of Integer;

Bu iki array tipide aynı temel veri tiplerini kullanmaktadır. Bu yüzden aşağıdaki kodda olduğu gibi tanımlanabilirler:

type
AylikSicakliklar = array [1..31] of GunlukSicaklik1;
YillikSicakliklar = array [Jan..Dec] of AylikSicakliklar;

Yukarıdaki tanımlama şekli ile endeks sirasi ters çevirilmiş oldu, fakat yinede verilerin bir blok halinde iki değişken arasında aktarımına izin vermektedir. Örneğin aşağıdaki kod ile Ocak ayı sıcaklıkları şubat ayına kopyalanmaktadır:

var
BuYil: YillikSicakliklar;
begin
...
BuYil[Subat] := BuYil[Ocak];

Sıfır tabanlı bir array tipi yaratmak içinse, array’in taban sinirini sıfır yapmanız yeterli olacaktir. Genelde mantıksal sınırlar yaratmak daha avantajlıdır, çünkü array’in 3. elemanına erişmek için 2 yazmanıza gerek kalmaz(sıfır tabanlı dizide 3. elemanın endeksi 2’dir ). Hernekadarda windows sıfır tabanlı array tipini kullansada (çünkü C programlama dili kullanılmıştır.), Delphi bileşen kütüphaneside aynı eğilimdedir.

Eğer array veri tipi ile çalışmak durumunda kalırsanız, Low ve High fonksiyonlarını kullanarak bu array’in alt ve üst sınırlarını öğrenebilirsiniz. Low ve High fonksiyonlarının kullanımı tavsiye edilir , özellikle döngülerde, çünkü program kodunu array’in alt ve üst sınırlarından bağımsız kılar. İleride array’in alt ve üst sınırlarını değiştirdiğinizde Low ve High fonksiyonları eskisi gibi işlevlerini sürdüreceklerdir. Eğer bu fonksiyonlar kullanılmamış olsaydı döngülerdeki kodlarıda güncellemeniz gerekecekti. Low ve High fonksiyonları program kodunuzu daha okunaklı ve kolay anlaşılır kılacaktır.

NOT : Bu arada Low ve High fonksiyonlarının kullanımı çalışma zamanı hataları alınmayacağı anlamına gelmemelidir. Çünkü bu ve bunu gibi bazı sistem fonksiyonları geri döndermeleri geren değerleri çalışma esnasında değilde derleme esnasında yaparlar ve kod derlendiği zaman Low ve High yerine sabit değerler atanır.

NOT: Delphi4 Object Pascal Dinamik array veri tipinide bir yenilik olarak getirmiştir. Bu özellik sayesinde array’lerin alt ve üst sınırları çalışma kipi esnasında dinamik olarak attırılıp azaltılabilir. Bu konu hakkındaki bilgiyi bölüm 8 de bulabilirsiniz.


RECORD TİPLERİ

Record veri tipi farklı tiplerin tek bir tip altında toplanması sağlar. Record tipinin her bir elemanı kendine has bir veri tipine sahiptir. Record veri tipi ileride kullanılmak üzere bu alanlara birer ad verir. Aşağıda Record veri tipinin tanımı ve bu tipin kullanımı ile ilgili küçük bir örnek bulacaksınız.

type
Tarih = record
Yil: Integer;
Ay: Byte;
Gun: Byte;
end;

var
DogumGunu: Tarih;

begin
DogumGunu.Til := 1997;
DogumGunu.Ay := 2;
DogumGunu.Gun := 14;

Class’lar ve Object’ler (sınıflar ve nesneler) record veri tipinin genişletilmiş hali olarak düşünülebilir. Delphi kütüphaneleri record tipi yerine Class kullanımına eğilimlidir, fakat bir çok record veri tipi Windows API’lerinde tanımlıdır.

Record veri tipide değişken yapıda alanlara sahip olabilir, yani birden fazla farklı veri tipindeki alan aynı hafıza alanını paylaşabilir. ( C programlama dilindeki Union gibi). Değişken record tipi kullanımı Delphide Nesneye yönelim ve ileri programlama teknikleri ile yerini değiştirmiştir.

Değişken tipteki record kullanımı iyi bir programlama tekniği olmadığından özellikle eni başlayanlar için pek tavsiye edilmez. Uzman kullanıcılar için sorun yok zira Delphinin çekirdek kütüphane kodlarındada bu kullanım tarzına rastlanmaktadır.

POINTER’LAR

Pointer veri tipi başka değişkenlerin hafızadaki adreslerini tutmaya yarayan farklı br veri tipidir. Bu yüzden pointer veri tipi bir veriye dolaylı yoldan gösterim tarzıdır. Pointer tanımı yapmak için özel bir kelime kullanılmaz aksine bir sembol kullanılır. Bu özel sembol (^)’ dür.

type
PointerToInt = ^Integer;

Pointer değişkenini tanımladıktan sonra bu değişkene aynı tipteki başka bir değişkenin adresini @ sembolünü kullanarak atayabilirsiniz.

var
P: ^Integer;
X: Integer;

begin
P := @X;
// değeri iki farklı şekilde değiştirbiliriz.
X := 10;
P^ := 20;

P adındaki pointer ile o pointer gösterdiği adrese erişirsiniz, o adresin içerisindeki veriye erişmek için p^ yazımını kullanmak gerekir.

Mevcut bir hafıza alanına erişmek yerine New yordamı ile dinamik olarak ayrılan yeni bir hafıza alanınada erişilebilir. Bu yolla ayırdığınız hafıza alanına ihtiyacınız kalmadığında dispose yordamını kullanarak bu alanı ana hafızaya tekrar kazandırabilirsiniz.

var
P: ^Integer;

begin
// initialization
New (P);
// operations
P^ := 20;
ShowMessage (IntToStr (P^));
// termination
Dispose (P);
end;

Eğer pointer değişkeninize bir değer atanmamışsa ona nil değerini atayabilirsiniz bu sayede değişkene bir değerin atanıp atanmadığını nil değeri ile karşılaştırarak bulabilirsiniz.

procedure TFormGPF.BtnGpfClick(Sender: TObject);
var
P: ^Integer;

begin
P := nil;
ShowMessage (IntToStr (P^));
end;

Yukarıdaki kod ile P pointerına nil değeri atanıştır yani P pointeri hiçbir adresi göstermemektedir dolayısı ile showmessage komutunun işletilmesi ile aşagıda gösterilen hata mesajı alınır.



Aşağıdaki kod ile daha güvenli bir program yazılmış olunur. Çünkü P pointerinin içeri boşsa yani nil ise bir sonraki komut işletilmemektedir.

procedure TFormGPF.BtnSafeClick(Sender: TObject);
var
P: ^Integer;
X: Integer;

begin
P := @X;
X := 100;
if P <> nil then
ShowMessage (IntToStr (P^));
end;

Delphi belli bir tipte olmayan pointerlarda tanımlayabilir( C dilindeki void* gibi). Eğer tipi belirli olmayan bir pointer kullanacaksanız New yerine GetMem yordamını kullanmanız gerekir. GetMem yordamı dinamik olarak ayrılacak hafıza alanının boyutları belirlenemediği zaman kullanılır.

Delphide pointer’lara nadiran ihtiyaç duyuluyor olmasına rağme bu ilginç bir avantajdır. Buna rağmen Pointer kavramını iyi anlama Delphinin arka plandaki object modelini anlamanın en önemli yoludur.

NOT: Delphide pointerları sık kullanmıyor olmanıza rağmen her bir obje aslında gerçek veriyi gösteren pointer’dır. Herşeye rağmen işin bu kısmı programcıya görünmez ve objeler birer veri tipi gibi kullanılır.


FILE TİPLERİ

Pascal’a özgü diğer bir tipte File tipidir. File veri tipi disk üzerindeki fiziksel bir dosyayı göstermek amacı ile kullanır. Yeni bir File veri tipini şöyle tanımlarsınız :

type IntegerDosya = file of Integer;

Bu tanımlamayı yaptıktan sonra bu dosyaya integer tipteki verileri yazıp okuyabilirsiniz.


© 1999 Mustafa Kasap. Tüm Hakları saklıdır.

 
Hosted by www.Geocities.ws

1