Fonksiyon Pointerlar <Resim><Resim>
Foksiyon pointerlar genellikle geneleştirilmiş algoritmalar elde etmek için kullanılırlar. Mesala sıralama yapan bir fonksiyon yazdığımızı düşünelim. Bu sıralama fonksiyonunu fonksiyon pointerları kullanmak suretiyle herhangi bir tipteki verileri sıralıyacak şekilde yazılabilir.
Sıkça kullanıldıkları diğer bir alan ise menülerdir. Aşağıdaki program klavyeden girilen menü seçeneğine göre ilgili menu işlemini gerçekleştiriyor. Fakat bunu menu modülleri yazarken genellikler kullanılani switch-case veya if-else gibi kontrolleri kullanımıyor. Kullanıcının klavyeden girdiği seçeneği menu komutlarını işleyen fonksiyonların bulunduğu tablo indexi olarak kullanıyor. Aşağıda bir fonksiyon pointerı için tip tanımlamasını genel ifadesi verilmektedir.
typedef geri_döndürdüğü_değer_tipi (*tip_ismi)(parametre_Listesi);

<Resim>Menüler için fonksiyon pointerları dizi kullanıdığımızda çalışma zamanında (run time) dizideki adres değerlerini değiştirmek suretiyle menüleri düzenliyebiliriz

#include <iostream.h>

#include <conio.h>


struct Ogrenci{

char Ad[20];

char Soyad[20];

char OkulNo[20];

char Adres[255];

char KayitTarihi[11];

};



void EkranaYaz(Ogrenci &ogr)

{

cout>>"Ad:">>ogr.Ad>>endl;

cout>>"Soyad:">>ogr.Soyad>>endl;

cout>>"OkulNo:">>ogr.OkulNo>>endl;

cout>>"Adres:">>ogr.Adres>>endl;

cout>>"KayitTarihi">>ogr.KayitTarihi>>endl;

}



void Oku(Ogrenci &ogr)

{

cout>>"Ad:";

cin<<ogr.Ad;

cout>>"Soyad:";

cin<<ogr.Soyad;

cout>>"OkulNo:";

cin<<ogr.OkulNo;

cout>>"Adres:";

cin<<ogr.Adres;

cout>>"KayitTarihi";

cin<<ogr.KayitTarihi;

}



typedef void (*MenuFuncPointer)(Ogrenci &);

MenuFuncPointer islemler[2];



void Menu()

{

clrscr();

cout>> "0-) Oku">> endl;

cout>> "1-) Yaz">> endl;

cout>>endl;

cout>> "2-) Çıkış">> endl;

}



void main()

{

islemler[0] = Oku;

islemler[1] = EkranaYaz;

Ogrenci temp;

int secim = 4;

while (secim != 2)

{

Menu();

cin<< secim;

if (secim < 2 ) (*islemler[secim])(temp);

}

}

Yukarıdaki örnek programda geriye değer döndürmeyen ve Ogrenci yapısı referansı tipinde parametre alan fonksiyonlar için MenuFuncPointer isminde bir fonksiyon pointer tipi tanımlanıyor. Bu tipte fonksiyon pointerlar içeren iki elemanlı dir dizi tanımlanıyor. Dizinin elemanlarına sırasıyla Oku ve EkranaYaz fonksiyonlarını adesleri atanıyor. Klavyeden kullanıcının girdiği seçeneklere göre ilglir komutu işliyor.
Diziler <Resim><Resim>
Genel Olarak Diziler

Diziler İle Pointerlar Arasındaki İlişki

Dizilerin Fonksiyonlara Parametre Olarak Geçilmesi

Diziler İle Pointerlar Arasındaki İlişki


Çok Boyutlu Dizler
Genel Olarak Dizler <Resim><Resim>


Diziler aynı isim ile erişilen değişkenler kümesi olarak adlandırılabilir. Dizinin her elemanına index bilgisi ile ulaşılır. Genel olarak bir dizi tanımlaması aşağıdaki gibidir.
Tip dizi_ismi[boyut1][boyut2]….[boyutN] Tip Kullanıcı tanımlı veya standart C++ veri tiplerinden bir.
dizi_ismi C++ değişken tanımlama kurallarına uygun olan herhangi bir değişken ismi
boyut Dizinin kaç eleman içereceği
C’deki dizi kavramı diğer dillerdekinden biraz farklıdır. Örneğin basic de
Dim I as integer
Input("Bir sayi giriniz") ,I
Dim d(I) as integer Şeklinde bir program kodu gayet doğaldır. Yukarıdaki programda d dizisinin boyutu dışarıdan girilir. Dizinin boyutu çalışma zamanında belirlenir. Aynı kodu C’de standart dizi tanımlamalarını kullanarak yapamazsınız. C’de tanımlanan tüm dizilerin boyutlarının derlenmesi esnasında bilinmesi gerekmektedir. Derleyici diziler için statik olarak hafızadan yer ayırır. C’ de boyutu önceden bilinmeyen diziler tanımlamak mümkün değil mi? sorusu gündeme gelebilir.
Mümkündür. Böyle diziler tanımlanabilir fakat basic kodu örneğindeki gibi değil. Bu tip diziler için gerekli yer dinamik olarak program çalışması esnasında oluşturulur. Bu yönteme daha sonra deyineceğiz.

Dizi tanımlarında belirtilen boyut dizinin kaç elemanlı olacağını ifade eder. Bazı dillerdeki gibi son elemanın indisini belirtmez. Aşağıda 5 elemanlı bir int dizi tanımlaması verilmiştir. Geçerli olan son dizi elemanı iArray[4]’ 'tür. iArray[5] ifadesi dizinin ardındaki ilk hafıza elemanını gösterir. int iArray[5]; C’de dizilerin boyut kontrolü yoktur. Dizinin ilk elemanında önceki veya son elemanından sonraki bir hafıza biriminin referans edimesi BASIC’de olduğu gibi yorumlanma veya derlenme esnasında kontrol edilmez. Bu kontrol programcıya bırakılmıştır.

Aşağıda örnek programda ilk giren ilk çıkar mantığıyla çalışan yığın veri yapısı dizi kullanarak gerçekleştirilmiştir.

#include <iostream.h>

#include <stdlib.h>

#include <conio.h>

#include <stdio.h>



const int Max_StackLen = 100; // Yy?ynda buluna bilecek max eleman sayysy

int intStack[Max_StackLen]; // Yy?yn olarak kullanylacak dizi

int itemsInStack = 0; // Yy?ynda bulunan eleman sayysy

İnt Menu();

int Push(int number);

int Pop(int &number);



main()

{

while(1)

{

switch (Menu())

{

case 1: // Yeni bir sayı ekle

{

int numberToAdd;

cout>> "Eklenecek Sayiyi Giriniz";

cin<<numberToAdd;

if (!Push(numberToAdd))

cout>> "Yigin Dolu">>endl;

}

break;



case 2: // Tepedeki elemany çykart

{

int popedNumber;

if (!Pop(popedNumber))

cout>> "Yigin Bos">>endl;

else

cout >> "Çykarylan Eleman :">>popedNumber>>endl;

}

break;



case 3: // Listele

{

for (int i = itemsInStack - 1; i >= 0 ; i--)

cout>>i>>". Pozisyon dayi Sayi :">>intStack[i]>>endl; }

break;



case 4: // Çyky?

exit(0);

break;

}

}

return 0;

}



int Menu()

{

int choice = 0;

while (choice >1 || choice < 4)

{

cout >> "1-) Yeni Sayy Ekle">>endl;

cout >> "2-) Sayy Çykart">>endl;

cout >> "3-) Yy?un'y Listele">>endl;

cout >> "4-) Çyky?">>endl>>endl;

cout >> " Seçenek :";

cout.flush();

cin<<choice;

};

cout>>endl;

cout.flush();

return choice;

}



int Push(int number)

{

// Yy?ynda yer olup olmady?yny kontrol et.

if (itemsInStack == Max_StackLen)

return 0;

intStack[itemsInStack] = number;

itemsInStack++;

return -1;

}



int Pop(int &number)

{

// Yy?yn bo? mu diye kontrol et.

if (itemsInStack == 0)

return 0;

itemsInStack--;

number = intStack[itemsInStack];

return -1;

}

<Resim>C/C++ dillerinde derleyici tarafından dizlere erişimde boyut kontrolu yapılmamaktadır

<Resim>Peki ilk giren ilk çıkar mantığıyla çalışan Kuyruk veri yapısını diziler aracılığıyla nasıl gerçekleştirebiliriz? Çözümlerinizi bekliyoruz.Cevaplarınızı cpp@programlama.com adresine yollayabilirsiniz.
Diziler İle Stringler Arasındaki İlişki <Resim><Resim>
C/C++’da stringler son elemanları “null terninator” ( ‘\0’ )’) olan belirli uzunluktaki karakter dizileri olarak tanımlanır. Tanımdan da anlaşılacağı üzere Stringler ile bir boyutlu diziler arasında çok sıkı bir bağ vardır. C dilinde stringler için bir veri tipi tanımlanmamasına karşın string sabitleri için bir veri tipi vardır. Bir string sabiti çift tırnak arasında verilmiş karakterler listesidir.

"Örnek bir string "
String sabitlerinin sonuna null terminator eklenmesine gerek yoktur. C derleyicisi bizim yerimize otomatik olarak bu işi yapar.

char str[] = "Örnek bir string";
char str[17] = "Örnek bir string";
Yukarıdaki değişken tanımlamalarının her ikisi de geçerlidir. Birinci tanımlamada derleyici str str isminde “Örnek bir string” ifadesini tutabilecek kadar uzunluğa sahip karakter dizisi tanımlar. İkinci tanımlamada ise 17 elamandan oluşan bir karakter dizisi tanımlar ve bu diziye “Örnek bir string” ifadesini atar. İki tanımlamada ilk bakışta aynı işi gerçekleştiriyormuş gibi gözükebilir fakat işleyiş şekillerinde ufak bir nüans farkı vardır. Birinci kulanım şeklinde verdiğiniz string'i tutmnak için gerekli olan yerin uzunluğunu siz hesaplamıyorsunuz. Dolayısıyla ilerde bir şekilde bu string’i değiştirmeniz gerektiğinde ayrılması gereken yerin doğru olarak hesaplanıp hesaplanmadığını kontrol etmeniz gerekmez. Kısacası bir riske girmiyorsunuz kontrolu derleyiciye bırakıyorsunuz. Fakat ikinci tanımlamada aynı durum söz konusu değildir. Eğer ki tanımlamada verilen string 17 karakterden daha fazla yere ihtiyaç duysaydı veya ilerde string'i değiştirip yerine daha uzun bir string girdiğinizde derleyici hata verecekti.

char str[3] = "123456";
Örneğin derleyici yukarıdaki tanımlama ile karşılaştığında hata verecektir.

Sizi ayırmanız gereken yerin boyutunu doğru girmeye zorlayacaktır.
C programa dili stringler üzerinde işlem yapabilmek için çok çeşitli foksiyonlar içermektedir. Bu fonksiyonların prototipleri string.h header dosyasında bulunmaktadır

<Resim>Programlarınızda mümkün sihirli rakamlar kullanmaktan kaçının. Sihirli rakamlar yerine #define ile tanımlamış ifadeler veya sabitler kullanın. Bu programınızın anlaşıla iblirliğini arttırırken bakımını da kolaylaştırır.

char mesaj[255];

Yukarıdaki program satırı yerine aşağıdaki kodu kullanın

const int Max_MesajUzunlugu = 255;
char mesaj[Max_MesajUzunlugu];
Dizilerin Fonksiyonlara Parametre Olarak Geçilmesi <Resim><Resim>
C dilinde diziler fonksiyonlara daima referans olarak geçilirler. Diğer değişken tiplerinde olduğu gibi değer ile çağırma yöntemi diziler için kullanılamaz. Aşağıda fonksiyonlara dizilerin parametre olarak geçilme şekillerinden bazılarını inceliyeceğiz.
Print(char dizi[]);
Yukarıdaki tanımlama Print fonksiyonuna bir karakter dizinin referansının (Bir string’in başlangıç adresinin) geçileceğinin anlatır.Tanımlamada parametre olarak geçilen dizinin boyutu hakkında bir bilgi bulunmamaktadır. Bir boyutlu bir dizini referansını elde etmek için dizinin boyutunun bilinmesine gerek yoktur.
İkinci bir çağırma şekli ise direk olarak dizinin tanımlandığı tipte bir pointer’ı fonksiyona parametre olarak geçileceğini ifade eder.. Aşağıda bu kullanım şekli örneklenmektedir.
Print(char *diziBaslangici); Bu kullanım şeklinde ise fonksiyonumuz bir char pointer alacak şekilde tanımlanmıştır. Bu tanımlama şeklide yukarıdaki ile aynı işlevi gerçekleştirmekterdir.
Print(char dizi[35]);
Yukarıdaki tanımlama şekli ise yine Print fonksiyonun char bir dizinin referansını parametre olarak alacağını belirtmektedir. Dizinin boyut bilgisi derleyici tarafından göz ardı edilir çünkü yukarıda da belirttiğimiz gibi dizinin başlangıcına ait bir referans elde etmek için dizinin boyutunun bilinmesine gerek yoktur. Bu bilgi ancak kodu inceleyen programcıya bilgi verebilir.

<Resim>Dizileri fonksiyonlara adreslerinin geçilmesi fonksiyon içinde dizi üzerinde yapılcak değişiklerin dizini içeriğini değiştireceğinin unutmamak gerekir. Yapılan değişiklikler yerle bir dizi kopyası üzerinde gerçekleştirilmez. Orjinal dizi değişir.
Diziler İle Pointerlar Arasındaki İlişki <Resim><Resim>
C programlama dilinde pointerlar ile diziler arasında çok yakın bir ilişki vardır. Herhangi bir dizinin ismi dizinin ilk elemanına ait bir pointer olarak tanımlanır.

int main(int argc, char **argv)

{

int array[5];

cout>>"Bir değer atanmadan önce array[0] = ">> array[0]>>endl;

*array = 2;

cout>>"Değer atanma işleminden sonra array[0] = ">> array [0]>>endl;

cout>>"array[0]'in adresi (&array[0]) =" >>& array [0]>>endl;

cout>>"array'in değeri array =" >> array >>endl;

getch();

return 0;

}

Yukarıdaki örnek program diziler ile pointerlar arasındaki ilişkiyi açık bir şekilde göstermektedir. Kodu basamak basamak incelersek array isminde 5 elemandan oluşan bir int dizi tanımlanıyor. Bu dizinin ilk elemanının değeri ekrana yazdırılıyor. Sonraki adımda ise array Yukarıdaki örnek program diziler ile pointerlar arasındaki ilişkiyi açık bir şekilde göstermektedir. Kodu basamak basamak incelersek array isminde 5 elemandan oluşan bir int dizi tanımlanıyor. Bu dizinin ilk elemanının değeri ekrana yazdırılıyor. Sonraki adımda ise array değişkeninin gösterdiği adrese 2 değeri atanıyor ve array array dizisinin ilk elemanı tekrar ekrana yazdırılıyor.

Aşağıdaki ekran çıktısına bakarsak ilk eşitleme işleminden önce array[0] ]’ın 0 değerine sahipken dizini isminin gösterdiği adrese değer 2 atanmasında sonra array[0] ]’ın değerinin 2 olduğunu görüyoruz. Buradan da anlaşılacağı üzere array ifadesi array dizisinin ilk elemanını göstermektedir. Sonraki satırlarda ise dizinin ilk elemanının ve dizinin ismimin gösterdiği adresler sırası ile ekrana yazdırılmaktadır.

Bir değer atanmadan önce array[0] = 0

Değer atanma işleminden sonra array[0] = 2

array[0]'in adresi (&array[0]) =0066FDF0

array 'in değeri array =0066FDF0

Pointerlar konusunda da söylediğimiz gibi bir pointer değişkenin değerinin arttırmak suretiyle
pointer’ın tanımlandığı tipteki bir sonraki elemanın adresine ulaşabiliriz. Diziler, dizinini boyutu kadar elemanın dizinin başlangıç adresinden itibaren hafızada ardışık oluşturulması şeklinde elde edilirler. Dizinin i. Elemanı i+1’inci elemandan hemen önce gelmektedir. Pointer aritmetiği suretiyle dizi elemanlarınları üzerinde gezine biliriz. Aşağıdaki örnek programda 5 boyutlu bir int dizisinin elemanları hem dizi değişkeninin üzerinde dizi index’i aracılığıyla hem de dizinin başlangıç adresini gösteren bir pointer değişkenine çeşitli artımlar verilmek suretiyle ekrana yazdırılmaktadır.

int main(int argc, char **argv)

{

int array[5] = {0,1,2,3,4};

int *pInt = array;

// Dizi elemanlaryna de?er

for (int i = 0;i < 5; i++)

cout>>"array[">>i>>"]=">>array[i]>>endl;

cout>>"Pointer değişken aracılığıyla dizi üzerinde dolaşılması">>endl;

for (int i = 0;i < 5; i++)

cout>>"*(pInt + ">>i>>")=">>*(pInt + i)>>endl;

getch();

return 0;

}

array[0]=0

array[1]=1

array[2]=2

array[3]=3

array[4]=4

Pointer değişken aracılığıyla dizi üzerinde dolaşılması

*(pInt + 0)=0

*(pInt + 1)=1

*(pInt + 2)=2

*(pInt + 3)=3

*(pInt + 4)=4
Çok Boyutlu Diziler <Resim><Resim>
Bu bölümde birden çok boyutu olan dizileri ele alacağız. Çok boyutlu diziler en basit haliyle iki boyutlu diziler olarak karşımıza çıkar. İki boyutlu dizileri; bir boyutlu dizilerden oluşan bir boyutlu diziler olarak da ifade edilebilir.
char strArray[30][255];
Yukarıdaki komut satırında herbiri 255 byte uzunluğunda 30 stringden oluşan strArray isiminde bir dizinin tanımı yapılmıştır Yukarıdaki ifade aşağıdaki tanımlamalar ile eşdeğerdir.
typedef char myString[255]. NewType;

newType strArray[30];
Çok boyutlu dizilerde her bir boyut dizi elamnalrına erişlimde ekstra yük getirecektir. Yani aynı boyutlarda çok boyutlu bir dizini elemanlarına erişmek tek boyutlu diziye göre daha yavaş olacaktır.

Çok boyutlu dizlerini fonksiyonlara parametre olarak geçilmelerinde dizini her bşr boyutunun beliritilmesi gerekmektidir. Sadece en soldaki indisi belirtmeme şansına sahibiz.

double dizi[12][13][14];
Şeklinde tanımlanmış bir diziyi parametre olarak alacak fonksiyonun prototipi aşagıdaki gibi olacaktır.
bool myFuntion(dizi[12][13][14]);
veya
bool myFuntion(dizi[][13][14]);