SİTE
İÇİ ARAMA |
|
Blogroll |
|
|
|
Karakter Katarları Üzerinde İşlemler ve Bağlı Liste Uygulaması - 1 |
|
Gönderiliyor lütfen bekleyin... |
|
|
Bu yazı dizisinde,
C dilinde karakter katarlarına (string) ilişkin çeşitli işlemlerin nasıl yapıldığını
inceleyeceğiz. İlk olarak, karakter katarlarına ilişkin genel bir bilgi vereceğiz.
Ardından öğrencilere ilişkin notların tutulmasında kullanacağımız bir bağlı
liste yapısı oluşturacağız. Daha sonra arama, sıralama, ekleme, silme gibi işlemleri
yapacak bir takım fonksiyonlar yazacağız. Bu fonksiyonları, oluşturduğumuz bağlı
listeye uygulayacağız. Uygulama bittiğinde elimizde, öğrencilere ilişkin notları
tutabildiğimiz, arama işlemleri yapabildiğimiz, sıralayabildiğimiz bir programımız
olacak. Yapı içerisinde küçük değişiklikler yaparak, kendi programınızda kullanabileceğiniz
bir hale getirebileceksiniz.
C dilinde karakter
katarları için özel bir tür tanımlanmamıştır. Bilindiği gibi bir tamsayı değeri
int türünden bir değişkende, ondalıklı sayı değeri double ya da float türünden
bir değişkende, karakter türünden bir değer char türünden bir değişkende saklanmaktadır.
Karakter katarları, karakterlerden oluşan diziler olarak tanımlanabilir. C dilinde
karakter katarlarını tutmak için de zaten karakter dizileri kullanılmaktadır.
Nesne yönelimli programlama dillerinin pek çoğunda karakter katarları genellikle
"string" olarak isimlendirilen sınıflarda tutulmaktadır. C dilinde
karakter katarlarını tutmak ve çeşitli işlemleri yapabilmek için kendi kütüphanelerimizi
oluşturup işleri kolaylaştırabiliriz. Karakter katarları çift tırnak içerisinde
yazılırlar. C derleyicileri, çift tırnak içerisinde gördükleri her ifadeye,
karakter katarı muamelesi yaparlar. Karakter katarını alarak sonuna null karakter
(’\0’) ekler, bellekte güvenilir bir bölgeye yerleştirir ve (char *) türünden
adres üretir. Karakter katarı tanımlamalarına bir göz atalım :
char *str =
"C programlama dili";
Bu tanımlama ile
derleyici, "C programlama dili" katarı için derleme zamanında bellekte
bir yer belirler ve str isimli göstericiye bu yerin adres değerini atar. Karakter
katarları, belleğin salt okunur kısmında tutulduğu için, değiştirilmeleri tanımsız
davranışa yol açar. Çift tırnak içerisinde yazılmış bir ifadeyi, char türünden
bir diziye de atayabiliriz :
char str[30]
= "C programlama dili" ;
Bu durumda artık
çift tırnak içerisindeki ifade bir adres belirtmez. Karakter katarının her bir
karakteri str isimli dizinin elemanlarına atanır. Karakter katarları, global
değişkenler olduğu gibi statik ömre sahiptirler. Programın yüklenmesi ile bellekte
yer alırlar ve program sonlanana kadar bellekte kalırlar. (Bu nedenle çok programda
çok fazla karakter katarı kullanmak belleğe yük bindirecektir.)
Uygulamamız için
oluşturacağımız liste, öğrencinin adını ve öğrenciye ilişkin not değerini tutacak.
Bu nedenle yapımızın öğrenci adını tutacak (char *) türünden bir veri elemanı
ve notu tutacak tamsayı türünden bir veri elemanı olacak. Bir liste yapısı oluşturacağımız
için, listedeki bir sonraki elemana ulaşmamızı sağlayacak bir de gösterici veri
elemanımız olacak. Yapımızı oluşturmaya başlayabiliriz. Öncelikle bir kayda
ilişkin bilgileri tutacağımız "record" isminde bir yapı tanımlayalım
:
typedef
struct _record {
     char *rName;
     int rNumber;
     struct _record *rNext;
}record;
|
Yapıyı tanımlarken
typedef bildirimini de yapıyoruz, bundan sonra bu yapının ismini "record"
olarak kullanabileceğiz. Yapının elemanlarını inceleyelim : (char *) türündeki
rName isimli veri elemanı kaydı yapılmakta olan öğrencinin adını tutacak. Tamsayı
türündeki rNumber isimli veri elemanı öğrencinin notunu tutacak. (struct _record
*) türündeki rNext isimli gösterici veri elemanı ise liste içerisinde bu öğrenciden
sonra gelen kaydın adresini tutacak. Liste içerisinde dolaşabilmek için bu veri
elemanını eklememiz gereklidir. Çünkü listede sadece ilk kayda ilişkin adres
değerini tutacağız. Listedeki diğer kayıtlara bu gösterici aracılığıyla erişeceğiz.
Şimdi de liste yapımızı tanımlayalım :
typedef
struct _recordList {
     record *start;
     int size;
}*recordList;
|
Bu yapının typedef
bildirimini de tanımlama sırasında yaptık. Ancak bu bildirim öncekinden biraz
daha farklı. İsmin önünde (*) içerik operatörü yer alıyor. "recordList"
türünden bir nesne tanımladığımızda artık bu nesnenin türü (struct _recordList
*) olacak. Yapının elemanlarını inceleyelim : (record *) türündeki start isimli
veri elemanı listede bulunan ilk öğrenci kaydının adresini tutacak. Tamsayı
türündeki size isimli eleman ise listedeki eleman sayısını tutacak. Burada,
sadece ilk öğrenci kaydının adresini tutmanın yeterli olduğuna dikkat edin.
Her kaydın içinde bir sonraki kaydın adresi de saklandığına göre diğer kayıtlara
record yapısındaki veri elemanı yoluyla ulaşacağız. Oluşturduğumuz yapıyı bir
şema ile gösterelim :
Bağlı listemize
ilişkin fonksiyonları yazmaya geçebiliriz. İlk olarak liste için bellekte yer
ayıracak bir fonksiyon yazmalıyız. Bağlı liste yapımız kendi içerisinde bir
yapı daha içerdiği için bu yapıya ilişkin bir başlangıç fonksiyonu da yazmalıyız.
Önce buradan başlayalım :
record
*CreateRecord(void);    /*Prototip bildirimi*/
record
*CreateRecord(void)
{
    record *rH;
    rH
= (record *)malloc(sizeof(record));  /*rH nesnesi için bellekte dinamik
olarak yer ayrılıyor */
    if (rH == NULL)                                /*Yapılan dinamik bellek ayırma işleminin
başarısı kontrol ediliyor */
    {
        printf("Bellek Yetersiz\n");
        exit(EXIT_FAILURE);
    }     return
rH;
}
|
CreateRecord isimli
fonksiyonda, record türünden bir gösterici tanımlanıyor. Bu gösterici için dinamik
olarak, record nesnesinin bellekte kapladığı yer kadar (sizeof(record)) yer
ayrılıyor. Yer ayırma işleminin başarısı kontrol ediliyor. Eğer işlem başarısız
olmuşsa (exit) fonksiyonu ile program sonlandırılıyor. İşlem başarılı olmuşsa
rH nesnesi döndürülüyor. Listemizin başlangıç fonksiyonunda bu fonksiyonu kullanacağız.
Şimdi listemizin başlangıç fonksiyonunu yazalım :
recordList
CreateList(void);        /*Prototip bildirimi */
recordList
CreateList(void)
{
      recordList pRL = (recordList)malloc(sizeof(*pRL));    /*pRL nesnesi için
dinamik olarak yer ayrılıyor */
      if (pRL == NULL)                                                /*Yapılan dinamik bellek ayırma işleminin başarısı
kontrol ediliyor */
      {
          printf("Bellek Yetersiz\n");
          exit(EXIT_FAILURE);
      }
      pRL->start
= NULL;
      pRL->size = 0;
      return pRL;
}
|
CreateList isimli
fonksiyonda, recordList türünden bir gösterici tanımlanıyor. Bu gösterici için
dinamik olarak, recordList nesnesinin bellekte kapladığı yer kadar (sizeof(*recordList))
yer ayrılıyor. Yer ayırma işleminin başarısı kontrol ediliyor. Eğer işlem başarısız
olmuşsa (exit) fonksiyonu ile program sonlandırılıyor. İşlem başarılı olmuşsa
pRL göstericisinin gösterdiği nesnenin veri elemanlarına ilk değerleri atanıyor.
Göstericinin gösterdiği nesnenin start isimli veri elemanına NULL değeri atanıyor.
start veri elemanı listedeki ilk elemanın adresini tutacak. NULL değer atanmasının
sebebi, liste yeni oluşturulduğu için listede henüz hiç eleman olmamasıdır.
Aynı sebepten ötürü, listedeki eleman sayısını tutacak olan size isimli veri
elemanına da sıfır değeri atanıyor. Listeye eleman ekledikçe size elemanının
değeri bir artırılacaktır, start elemanına ise listeye eklenen elemanın adresi
atanacaktır. Şimdi listemize eleman ekleyeceğimizi görelim. Listeye bir eleman
eklenirken, eklenecek değerler ile record türünden bir nesne oluşturulmalıdır.
Bunun için öncelikle bu işi yapacak bir fonksiyon yazmalıyız :
void SetRecord   (record
*pRecord, char *name, int number); /* Prototip bildirimi */
void SetRecord  (record
*pRecord, char *name, int number)
{     /* Parametre olarak gelen değerler nesneye atanıyor. */
    pRecord->rName = name;
    pRecord->rNumber = number;
    pRecord->rNext = NULL;
}
|
Fonksiyonumuz,
parametre olarak geçilen name ve number isimli değişkenlerin değerlerini pRecord
göstericisinin gösterdiği nesneye atıyor. Bu fonksiyonun çağrılmasıyla artık
elimize ilk değerleri atanmış bir record nesnesi olacaktır. Bu nesneyi listemize
eklemeliyiz. Bunu da şöyle bir fonksiyon ile yapabiliriz :
void AddRecordStart
(recordList rList, char *name, int number);      /*
Prototip bildirimi */
void AddRecordStart (recordList
rList, char *name, int number)
{
    record *addRecord = CreateRecord();
    SetRecord(addRecord,name,number); /* record türünden nesnemize değerler
atanıyor */
    addRecord->rNext
= rList->start; /*record türünden nesnemiz, listeye ekleniyor */
    rList->start = addRecord;
    rList->size++;
}
|
Fonksiyonumuz parametre
olarak oluşturulacak listenin adresini tutan bir gösterici, öğrencinin adını
tutacak name isimli (char *) türünden bir gösterici ve öğrencinin notunu tutacak
number isimli int türünden bir nesne alarak, kaydı listenin başına eklemektedir.
Fonksiyonun başlangıcında öncelikle record türünden bir gösterici tanımlanarak,
malloc fonksiyonu ile dinamik olarak bellekte yer ayrılıyor. Daha sonra az önce
yazmış olduğumuz SetRecord isimli fonksiyon çağrılıyor. Fonksiyona parametre
olarak, record türünden göstericimiz ve kayda ilişkin değerleri tutan name göstericimiz
ve number nesnemiz geçiliyor. Şimdi, oluşturduğumuz bu kaydı listenin başına
eklememiz gerekli. Şu haliyle listenin başında bulunan kayıt ise yeni ekleyeceğimiz
kayıttan bir sonraki konumda yer alacaktır. Bu nedenle ekleyeceğimiz kaydın
rNext isimli veri elemanına şu anda listenin başında bulunan kaydın adresini
atıyoruz. Listemizin start isimli veri elemanına ise yeni oluşturduğumuz kaydın
adresini atıyoruz. Kayıt eklenmeden önce listede bir eleman olduğunu farz ederek
kayıt ekleme işlemini şema ile gösterelim :
Kayıt listeye
eklendikten sonra listenin eleman sayısını tutan size isimli değişkenin değerini
de bir artırıyoruz. Şimdi de listemizin sonuna bir kayıt ekleyecek fonksiyonumuzu
yazalım. Bu fonksiyonun kodu, aşağı yukarı AddRecordStart isimli fonksiyonun
kodu ile aynı olacak. Fark, kaydın listeye eklenmesi sırasında ortaya çıkacak.
Ekleyeceğimiz kaydın, rNext isimli veri elemanına NULL değeri atanacak. Çünkü
kayıt, listenin sonunda yer alıyor. Ancak, kayıt eklenmeden önce listenin sonunda
bulunan kaydın rNext isimli veri elemanına da, yeni ekleyeceğimiz kaydın adresi
atanmalı. Ancak listemizde son kaydı tutan bir veri elemanımız yok. O halde
öncelikle listedeki son elemanı bulacak bir fonksiyon yazmalıyız :
record
*GetLastRecord(recordList list); /* Prototip bildirimi */
record
*GetLastRecord(recordList list)
{     if (list->size == 0)        return NULL;
    record *tmpRecord = list->start;
    while
(tmpRecord->rNext != NULL)
         tmpRecord = tmpRecord->rNext;
    return
tmpRecord;
}
|
Listedeki son kaydı
bulacak fonksiyonumuzda, listedeki kayıtları dolaşırken kullanacağımız (record
*) türünden geçici bir gösterici tanımlıyoruz. Eğer listede hiçbir eleman yoksa
fonksiyon NULL değere geri dönecektir. Bu durumu fonksiyonun başında kontrol
ediyoruz. tmpRecord isimli göstericiye listenin ilk başındaki kaydın adresini
atıyoruz. While döngüsü, geçici tmpRecord göstericisinin rNext isimli veri elamanının
değeri NULL değer olmadığı sürece dönecek. Eğer rNext isimli veri elemanının
değeri NULL değer ise listenin sonuna ulaşılmış demektir. Döngüden çıkıldığı
noktada tmpRecord göstericisinde listedeki son eleman kayıtlı durumdadır. Şimdi
kaydı liste sonuna ekleyecek fonksiyonumuza geçelim :
void AddRecordEnd
(recordList, char *name, int number);       /* Prototip bildirimi */
void AddRecordEnd(recordList
rList, char *name, int number)
{
    record *lastRecord;
    record *addRecord = CreateRecord();
    SetRecord(addRecord,name,number);
   
lastRecord = GetLastRecord(rList);
    srList->size++;     addRecord->rNext = NULL;
    if (lastRecord
== NULL)
    {
       rList->start = addRecord;
       return;
    }
  
  lastRecord->rNext = addRecord;
}
|
(record *) türünden
addRecord isimli göstericinin gösterdiği nesneye, listeye eklenecek kayda ilişkin
verileri atadık. Önceki fonksiyona ilaveten, burada son kayda da ihtiyacımız
olacak. Bu nedenle (record *) türünden lastRecord isimli bir gösterici tanımladık
ve bu göstericiye GetLastRecord isimli fonksiyondan dönen değeri atadık. Ancak
eğer listede hiç eleman yoksa, fonksiyon NULL adrese dönüyordu. Bu durumu da
kontrol etmeliyiz. Eğer listede hiç eleman yoksa, sona eklediğimiz bu eleman
listenin hem başındaki hem de sonundaki eleman olacaktır. Bu durumu sağlamak
için listenin start isimli veri elemanına yeni eklediğimiz kaydın adresini atadık.
Kaydın rNext isimli veri elemanına da NULL adres değerini atadık. Listede kayıt
var ise, son kaydın rNext isimli veri elemanına, yeni eklediğimiz kaydın adresini
atadık. Yeni eklediğimiz kaydın rNext isimli veri elemanına yine NULL değer
atadık.
Şimdi de listemizdeki
kayıtları ekrana yazdıracak bir fonksiyon yazalım :
void DisplayList(recordList
rList); /* Prototip bildirimi */
void DisplayList (recordList
rList)
{
    record *rs;
    for (rs
= rList->start; rs != NULL; rs = rs->rNext)
    {
         printf("Adi : ");
         puts(rs->rName);
         printf("Numarasi : %d\n",rs->rNumber);
    }
}
|
Fonksiyonun başında,
listedeki kayıtları dolaşırken kullanacağımız (record *) türünden rd isimli
geçici bir gösterici tanımladık. rs göstericisine ilk değer olarak listenin
en başındaki elemanın adresini atadık. for döngüsünün her adımında, rd göstericisinin
değerinin NULL adres olup olmadığı kontrol ediliyor. Eğer rs göstericisi NULL
adrese işaret ediliyorsa listenin sonuna gelinmiş demektir. Döngünün her adımında,
rs göstericisine, rs göstericisinin gösterdiği nesnenin rNext isimli veri elemanının
değerini atadık. Bu değer, liste içerisinde, rs göstericisinin gösterdiği nesneden
bir sonra gelen kaydın adresidir. Bu şekilde tüm liste dolaşılarak kayıtlara
ilişkin bilgiler ekrana yazdırılır.
Bir sonraki makalemizde
bağlı liste yapımıza yeni fonksiyonlar ekleyeceğiz. Makaleye ilişkin uygulamayı
indirmek için tıklayınız.
Mutlu ve huzurlu
günler...
Makale:
Karakter Katarları Üzerinde İşlemler ve Bağlı Liste Uygulaması - 1 C ve Sistem Programlama Çiğdem Çavdaroğlu
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|
|