Veri Yapıları ve Programlama (BTP 104) İçerik Sorumlusu: Yrd. Doç. Dr. Nurşen SUÇSUZ Trakya Üniversitesi Tunca Meslek Yüksekokulu Edirne-2010 T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 TRAKYA ÜNİVERSİTESİ Tunca Meslek Yüksekokulu Müdürlüğü’nden Öğrencilerimize Önemli Uyarı 123- 4- Bu ders içeriği Yüksekokulumuz Uzaktan Eğitim Öğrenme Yönetim Sisteminden (LMS) yayınlanan materyallerden oluşmaktadır. Ders içerikleri Uzaktan Eğitim Öğrenme Yönetim Sistemimizde Ders Bilgileri altında verilen kaynaklardan derlenen ders notlarıdır. Öğrencilerimize Uzaktan Eğitim Öğrenme Yönetim Sisteminde (LMS) ders içeriklerinin dışında, animasyon, uygulama videoları, örnek programlar vb gibi görsel ve uygulamaya yönelik ders materyalleri de verilmektedir, pdf formatındaki içerik bunları kapsamaz. Öğrencilerimizin sınavlarda sadece pdf formatında verilen ders içeriklerinden sorumlu olmadıkları ve herhangi bir bilgi karmaşasında Eğitim Öğrenme Yönetim Sisteminden (LMS) yayınlanan ders içeriğini baz almaları önemle rica olunur. Bu ders içeriğinin basım, yayım ve satış hakları Trakya Üniversitesi’ne aittir. "Uzaktan Öğretim" tekniğine uygun olarak hazırlanan bu ders içeriğinin bütün hakları saklıdır. İlgili kuruluştan izin almadan ders içeriğinin tümü ya da bölümleri mekanik, elektronik, fotokopi, manyetik kayıt veya başka şekillerde çoğaltılamaz, basılamaz ve dağıtılamaz. Copyright © 2010 by Trakya University All rights reserved No part of this course content may be reproduced or stored in a retrieval system, or transmitted in any form or by any means mechanical, electronic, photocopy, magnetic, tape or otherwise, without permission in writing from the University. Edirne 2010 T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 (1. Hafta) 1. DĠZĠLER Programlama dillerinde genel olarak, bir değiĢken iĢlem anında sadece bir tek değeri saklama özelliğine sahiptir. Örneğin bir ürünün fiyatı urun_fiyat adlı bir değiĢken tarafından temsil edilmek üzere float urun_fiyat olarak tanımlanabilir. Böylece program içersinde bir iĢlem anında ürün fiyatı urun_fiyat değiĢkeni kullanılarak iĢlenebilir. Ürünün bir baĢka değeri urun_fiyat değiĢkenine aktarılarak iĢlendiğinde bir önceki değer programlama mantığı gereği silinecek ve programın daha sonraki bölümlerinde bu değere eriĢme imkânı olmayacaktır. Bazı durumlarda, özellikleri nedeni ile birbirine bağımlı ve aynı anda iĢlem görmesi gereken veri, değerler kümesinden oluĢabilir ve bu değerlerin tümü ya da bir kısmı aynı anda iĢleme girebilir. Örneğin, üç aynı ürünün ortalama fiyatı hesaplanmak istendiğinde float urun_fiyat1, urun_fiyat2, urun_fiyat3 Ģeklinde bir tanımlama her üç ürünün program içersinde aynı anda kullanımını sağlayacak ve bunların silinmesini önleyecektir. Ancak veri kümesi 100 elemanlı olduğunda bu yöntem hiç kullanıĢlı değildir. Bu durumlarda, hem büyük veri kümelerinin tüm değerlerinin bir iĢlem anında kullanılabilmelerini sağlayacak ve hem de bunların tek bir değiĢken ile temsil edilmelerine olanak tanıyacak bir yapıya gereksinim vardır. Programlama dillerinde bu tür yapılara DĠZĠ adı verilmektedir. Tek boyutlu dizilerin C programlama dilinde tanımlanması için genel yapı; veri_türü dizi_adı [dizi_büyüklüğü]; Ģeklindedir. Bu yapıda C programlama dilinin standart veri türlerinden biri ya da kullanıcı tanımlı bir veri türü kullanılabilir. Örneğin 100 adet ürünün fiyatını program içersinde kullanabilmek için gerekli olan dizi tanımlaması: float urun_fiyat[100]; Ģeklindedir. Dizi tanımlaması ile verilmiĢ bulunan değiĢkenler program içersinde indisler yardımı ile kullanılırlar. Ġndisler, tamsayı değer almak zorundadırlar ve o dizi içersinde kaçıncı elemanın istendiğini belirtmek için kullanılırlar. Bu yüzden indis değiĢkenleri program içersinde tamsayı değiĢken olarak tanımlanırlar. C programlama dilinde en küçük dizin değeri 0 dır ve dizinin ilk elemanını gösterir. T.Ü. Tunca M.Y.O (Uzaktan Eğitim) Dizi eleman pozisyonu Dizi değeri Ġndis değeri 1 2 A B 0 1 3 C 2 BTP104-H1 4 D 3 Dizi eleman pozisyonu 1 2 3 4 5 Ogr_not 50 25 8 20 30 Ġndis değeri 0 1 2 3 4 Dizi değerlerine eriĢim, değiĢken adının eriĢilecek kullanımı ile sağlanmaktadır. Örneğin; 6 79 5 dizi elemanının indis değeri ile birlikte i=3; x=kod[2]; y=ogr_not[i]; Dizi elemanlarına eriĢimde indis değiĢkeninin yanı sıra, sonucu tamsayı olan aritmetik iĢlem kullanma olanağı da vardır. i=1; x=kod[i+2]; y=ogr_not[i+3]; Bir program içersinde dizi tanımlaması yapıldığında bellekte dizinin boyutu kadar yer ayrılmaktadır. Örneğin, yukarıdaki dizilerden kod için bellekte 3 karakter iken ogr_not için 4 karakter saklayacak Ģekilde yer ayrılacaktır. ÖRNEK: AĢağıda 5 tamsayıyı a dizisine aktaran ve çıktıda bu tamsayılar ile ortalamalarını veren bir program görülmektedir. BTP104-H1 T.Ü. Tunca M.Y.O (Uzaktan Eğitim) Dizi elemanlarına baĢlangıç değer ataması dizilerin program içersinde tanımlandıkları satırlarda da yapılabilir. char kod[4]={‘A’, ‘B’, ‘C’, ‘D’}; int ogr_not[6]={50, 25, 8, 20, 30, 79}; yada char kod[ ]={‘A’, ‘B’, ‘C’, ‘D’}; int ogr_not[ ]={50, 25, 8, 20, 30, 79}; satırları ile kod ve ogr_not dizilerine program içerisinde kullanacakları ilk değerler atanmaktadır. Bir dizinin boyutu, o dizinin elemanlarına eriĢim için kullanılan indis sayısını belirler. Birçok durumda elemanlarına eriĢim için, tek bir indis kullanımı gerektiren bir boyutlu diziler problemlerin çözümü için yeterlidir. Ancak bazı durumlarda daha fazla boyutlu ve daha fazla indis kullanımı gerektiren dizi tanımlamaları söz konusu olabilir. Bunlardan iki boyutlu diziler tablo yapılarını gösterirler ve tanımlamaları: int tab[3][5]; örneğinde olduğu gibi iki adet [ ][ ] kullanımı ile yapılır. Bu yapıda ilk [ ], tablodaki sıra sayısını ikinci [ ], ise kolon sayısını gösterir ve dolayısı ile tablo elemanlarına ulaĢım için iki adet indis kullanılması gerekir. Ġki boyutlu diziler matris olarak isimlendirilmektedir. Ġki boyutlu tab dizisinin yapısı kolon 0 kolon 1 kolon 2 kolon 3 kolon 4 T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 sıra0 sıra1 sıra2 Ģeklindedir. Genel olarak iki boyutlu dizilerdeki değerlerin iĢlenmesi için iç içe iki döngü kullanılması gerekir. Dizi iĢlemlerinde bir dizinin boyutu, o dizi değerlerinin iĢlenmesi için gereken iç içe döngü sayısını belirler. Döngünün düzenleniĢ Ģekline göre bu diziler kolon kolon veya satır satır iĢlenirler. int tab[3][5]={ {10, 15, 20, 25, 30}, {35, 40, 45, 50, 55}, {60, 65, 70, 75, 80} }; ÖRNEK: AĢağıdaki program bir öğrencinin 4 dersin her birinden almıĢ olduğu 3 notu girerek ekrana görüntülemekte ve öğrencinin her ders için not ortalamasını hesaplamaktadır. Bu program her ders için ortalamaları ort=0.30*snv1+0.30*snv2+0.40*snv3 formülü ile hesaplamaktadır. ÖRNEK: AĢağıdaki örnek 2X3 büyüklüğündeki 2 boyutlu bir tamsayı dizisinin değerlerinin en büyüğünü bularak ekrana görüntülemektedir. T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 C ile hazırlanan programlarda diziler genelde 2 boyuttan büyük olmamakla birlikte, gerektiğinde daha fazla boyutu tanımlamak mümkündür. ÖRNEK: Program 5X2X9 büyüklüğünde 3 boyutlu bir tamsayı dizisinin elemanlarını tek boyutlu diziye kopyalamaktadır. 3 boyutlu dizinin her elemanı bulunduğu pozisyonun indis değerlerinin toplamıdır. Bu programda tanımlanan 3 boyutlu dizinin elemanları 2 tane iç içe geçmiĢ 3 döngü yardımı ile oluĢturulmakta ve daha sonra iĢlenmektedir. Ġlk döngü yapısında indis değerleri toplanarak 3 boyutlu dizi1’e atanmaktadır. Ġkinci döngü yapısında da bu elemanlar 90 (5*2*9) eleman büyüklüğünde dizi2 adlı tek boyutlu diziye aktarılarak ekrana görüntülenmektedir. T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 Bazı durumlarda bir dizi elemanı fonksiyona aktarılarak kullanılabilir. Bu durumda o dizi elemanı fonksiyon çağrılırken argüman listesi içerisinde indis değeri ile birlikte verilmelidir. Örneğin void ort(int x, int y) ile tanımlanan bir fonksiyon ort(sayi[1], sayi[2]); satırı ile çağrılması durumunda dizinin sayi[1] ve sayi[2] değerleri fonksiyona aktarılmaktadır. Eğer tüm dizi fonksiyona aktarılmak istenirse argüman listesi içinde dizi adının belirtilmesi gerekmektedir. Örneğin; int sayi[10]; char kod[5]; dizi tanımlamaları ile void sayi_bul (int x[]) void kod_bul (char y[]) fonksiyon tanımlamaları için kullanılacak çağırma satırları aĢağıdaki gibi olmalıdır. say_bul(say); kod_bul(kod); Bu aktarma iĢlemleri programlama dillerinde değer ile aktarma olarak tanımlanmaktadır. Dizi büyüklükleri C programlama dilinde # define standart fonksiyonu ile tanımlanabilir. # define BOYUT 10 void main() { int sayi[BOYUT]; tanımı ile BOYUT kullanılan her satırda 10 değeri geçerlidir. Yani dizi boyutu 10 dur. ÖRNEK: Bir dizinin 16’dan küçük değerlerinin ortalamasını çağırdığı fonksiyonda bularak ekrana görüntüleyen program aĢağıda verilmektedir. T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 Bu programda deger adlı dizi tanımlanarak ilk değer ataması yapılmakta, daha sonra ort_bul(deger) ifadesi ile deger dizisinin tümü fonksiyona aktarılarak burada bir döngü yardımı ile dizinin en küçük değeri bulunarak ekrana görüntülenmektedir. 2. GÖSTERĠCĠLER C dilinde adres bilgisi tutan değiĢkenlere gösterici adı verilmektedir. Gösterici değiĢken tanımlamaları * sembolü ile saklanacak değerin adres bilgisini tutmak üzere yapılır. Gösterici tanımlamaları için genel yapı; veri_türü * değiĢken_adi; Ģeklindedir. Veri_türü olarak C programlama dilinin standart veri türü kullanılabileceği gibi kullanıcı tanımlı bir veri türü kullanmakta mümkündür. Örneğin bir tamsayı değiĢkenin adresini tutan bir gösterici int sayi1; int *pt; BTP104-H1 T.Ü. Tunca M.Y.O (Uzaktan Eğitim) Ģeklinde tanımlanabilmektedir. Burada pt, bir tamsayı değiĢkenin bellek adres alanını tutan bir göstericidir. sayi1 değiĢkeninin adresini pt ye aktarmak için pt=&sayi1; satırı kullanılmalıdır. Bu tanımlamadan sonra *pt=3; ifadesi, sayi1 değiĢkenine 3 değerini atar ve sayi1=3; satırı ile aynı anlamı taĢır. ÖRNEK: 20 ve 50 tamsayı değerlerini gösterici değiĢken kullanarak değiĢtirip bu değerleri ekrana 50 ve 20 diye görüntüleyen program yazılmak istenirse; yukarıdaki programda sayi1 değiĢkeninin 1002 sayi2 değiĢkeninin 1006 adreslerinde olduğu varsayılırsa; DeğiĢken adı sayi1 sayi2 içerik 10 15 adres 1002 1006 p1 p2 1002 1006 Ģeklindedir. Programın çalıĢması sonucunda bu yapı gec BTP104-H1 T.Ü. Tunca M.Y.O (Uzaktan Eğitim) DeğiĢken adı sayi1 sayi2 içerik 10 15 adres 1002 1006 p1 p2 gec 1006 1002 1002 olarak değiĢir. Gösterici değiĢkenlere ilk değer atama iĢlemleri programın tanımlama veya iĢlem bölümlerinde yapılmaktadır. int sayi1; int *ptr=&sayi1; Yukarıdaki tanımlama ile ptr gösterici değiĢkeni tamsayı bir değer tutmak için tanımlanmıĢ olan sayi1 değiĢkeninin saklayacağı değerin bellek adresini göstermektedir. ÖRNEK: Girilen iki karakter değerini bir gösterici değiĢkene aktardıktan sonra bunlardan küçük olanın adresini ve kendisini ekrana görüntüleyen program yazılmak istendiğinde; int *iptr; float *fptr; Bu tanımla sonucunda bellekte iptr değiĢkeni mevcuttur. Ancak iĢaret ettiği veri bloğu yoktur. Bunun için iki yol vardır. Kullanılan herhangi bir değiĢkeni iĢaret etmek T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 Veri bloğunu boĢ belleği kullanarak oluĢturmak 2.1.ĠġARETÇĠ DEĞĠġKENĠN VAR OLAN BĠR DEĞĠġKENĠN BULUNDUĞU ADRESĠ GÖSTERMESĠ Bu iĢlemi yapabilmek için var olan değiĢkenin adresinin bilinmesi gerekmektedir. & iĢleci: Bir değiĢkenin adresinin belirlenmesi için kullanılır. Kullanım biçimi: &değiĢken &i : i değiĢkenin adresini verir. 3. DĠNAMĠK BELLEK KULLANIMI Bu yöntemde veriler için dinamik yer ayrılmaktadır (rezerve edilmektedir). Bunun için malloc fonksiyonu kullanılır. Kullanım Ģekli; void *malloc(n) Bu fonksiyon bellekten n byte yer ayırıp baĢlangıç adresini döndürmektedir. Örneğin; iptr = (*int) malloc(2); satırı ile iptr değiĢkeni tamsayı olmak üzere bellekte 2 tamsayı veriyi saklayacak yer ayrılmaktadır. C dilinde bir dizi tanımlandığı zaman, bu dizi için derleyici tarafından bellekte yer ayrılır. Örneğin: int a[100]; Derleme sırasında yukarıdaki gibi bir dizi tanımlaması ile karĢılaĢan derleyici bellekte (eğer kullanılan sistemde int türü uzunluğunun 4 byte olduğu varsayılırsa) toplam 400 byte yer ayıracaktır. Programın çalıĢması sırasında bir dizinin uzunluğunu değiĢtirmek mümkün değildir. T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 Dizi tanımlama ifadelerinde dizi boyutunu gösteren ifade (köĢeli parantezin içerisindeki ifade) sabit değer olmalıdır, değiĢken içeremez. Çünkü derleyicinin bellekte yer ayırması için, dizi boyutunu bilmesi gerekir. Oysa pratikte birçok uygulamada açılması gereken dizinin boyutu programın çalıĢması sırasında (runtime) belirlenmektedir. Birtakım sayıların kullanılmak üzere klavyeden girildiğini düĢünülsün yani kullanıcının kaç tane sayı gireceğinin belli olmadığı düĢünülsün. Kullanıcının girdiği sayıları tutmak için açılan bir dizinin boyutu ne olmalıdır? Ya da bir dizindeki dosyaları sıraya göre dizmek için dosya bilgilerinin geçici olarak bir dizide saklanacağı düĢünüldüğünde dizinin uzunluğu ne olmalıdır? Bu baĢlangıçta belli değildir. Çünkü dizin içinde kaç dosya olduğu belli değildir. Bu tür örnekleri çoğaltmak mümkündür. Bu tip durumlara özellikle veri tabanı uygulamalarında sıklıkla rastlanır. Bazı uygulamalarda dizilerin gerçek uzunluğu programın çalıĢması sırasında, ancak birtakım olaylar sonucunda kesin olarak belirlenebilir. Bu durumda dizilerle çalıĢan programcı herhangi bir gösterici hatasıyla karĢılaĢmamak için dizileri en kötü olasılığı gözönünde bulundurarak açmak zorundadır. Bu da belleğin verimsiz bir Ģekilde kullanılması anlamına gelmektedir. Üstelik açılan diziler yerel ise ilgili blok sonlanana kadar, global ise programın çalıĢmasının sonuna kadar bellekte tutulacaktır. Oysa, dizi ile ilgili iĢlem biter bitmez, dizi için ayrılan bellek bölgesinin boĢaltılması verimli bellek kullanımı için gereklidir. Programın çalıĢma zamanı sırasında belli büyüklükte ardıĢıl (contigious) bir bellek bölgesinin programcı tarafından ayırılmasına ve istenildiği zaman serbest bırakılmasına olanak sağlayan yöntemlere dinamik bellek yönetimi denir. C dilinde dinamik bellek yönetimi dinamik bellek fonksiyonlarıyla yapılmaktadır. Dinamik bellek yönetiminde kullanılan standart C fonksiyonları incelenirse; 3.1. Malloc Fonksiyonu malloc fonksiyonu programın çalıĢma zamanı sırasında bellekte dinamik yer ayırmak için kullanılmaktadır. Fonksiyonun prototipi; void *malloc(size_t n byte); size_t türünü derleyiciyi yazanların seçimine bağlı olarak unsigned int ya da unsigned long türlerinden birinin yeni tür ismi olarak tanımlanması gerektiği, ve sistemlerin hemen hemen hepsinde size_t türünün unsigned int türü olduğu bilinmektedir. Fonksiyona gönderilecek argüman ayrılmak istenen bloğun byte olarak uzunluğudur. Böylece ayrılan alanın sürekli (contigous) olması garanti altına alınmıĢtır. malloc fonksiyonunun geri dönüĢ değeri ayrılan bellek bloğunun baĢlangıç adresidir. Bu adres void türden olduğu için, herhangi bir türden göstericiye sorunsuz bir Ģekilde atanabilir. Bu adres herhangi bir türden göstericiye atandığı zaman artık ayrılan blok gösterici yardımıyla bir dizi gibi kullanılabilir. malloc fonksiyonunun istenilen bloğu ayırabilmesi garanti altında değildir. Birçok nedenden dolayı malloc fonksiyonu baĢarısız olabilir. Bellekte ayrılmak istenen alan kadar boĢ bellek bulunmaması sık görülen baĢarısızlık nedenidir. malloc fonksiyonu baĢarısız olduğunda NULL adresine geri döner. malloc fonksiyonu bellekten yer ayırdıktan sonra iĢleminin baĢarılı olup olmadığı mutlaka kontrol edilmelidir. malloc fonksiyonu ile bellekte bir blok ayırılmasına iliĢkin aĢağıda bir örnek verilmiĢtir. T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 malloc fonksiyonu baĢarısız olduğunda programı sonlandırmak gerekmeyebilir. Atama ve kontrol bir defada da yapılabilir. malloc fonksiyonu ile yapılan dinamik yer ayırmanın baĢarılı olup olmadığı mutlaka kontrol edilmelidir. Fonksiyonun baĢarısız olması durumunda, geri dönüĢ değerinin aktarıldığı gösterici aracılığı ile belleğe bir Ģey yazılmaya çalıĢılırsa, atama NULL adrese yapılmıĢ olur. (NULL pointer assignment). Programın yanlıĢ çalıĢması kaçınılmazdır. Programcılar çoğu kez, küçük miktarlarda ve çok sayıda bloğun ayrılması durumunda, kontrolü gereksiz bulma eğilimindedir. Oysa kontrolden vazgeçmek yerine daha kolaylaĢtırıcı yöntemler denenmelidir. Örneğin p1, p2, p3, p4, p5 gibi 5 ayrı gösterici için 10'ar byte alan ayrılmak istensin. Bu durumda kontrol mantıksal operatörler ile tek hamlede yapılabilir. char *p1, *p2, *p3, *p4, *p5; ... p1 = (char *)malloc(10); p2 = (char *)malloc(10); p3 = (char *)malloc(10); T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 p4 = (char *)malloc(10); p5 = (char *)malloc(10); if (!(p1 && p2 && p3 && p4 && p5)) { printf("bellekte yer ayrılamadı!..\n"); exit(EXIT_FAILURE); } malloc fonksiyonu blokların herhangi birinde baĢarısız olursa bu durum if deyimi içinde tespit edilmektedir. malloc fonksiyonunun geri dönüĢ değeri void türden bir adres olduğu için, bu adres sorunsuzca her türden göstericiye atanabilir. Ancak okunabilirlik açısından malloc fonksiyonunun geri dönüĢ değeri olan adresin, tür dönüĢtürme operatörü yardımıyla, kullanılacak göstericinin türüne dönüĢtürülmesi tavsiye edilir. Böylece malloc fonksiyonu ile ayrılan bloğun ne türden bir diziymiĢ gibi kullanılacağı bilgisi de açıkça okuyucuya verilmiĢ olabilir. int türden bir dizi için dinamik olarak yer ayrılsın. Örneğin bir kullanıcı klavyeden int türden sayılar gireceği düĢünülsün. Kullanıcıdan, kaç tane sayı gireceği bilgisi alınsın ve istenilen miktardaki sayıyı saklayabilecek bir alan dinamik olarak ayrılsın. Yukarıdaki kod parçasında int türü uzunluğunun 4 byte olduğu varsayılmıĢtır. Kaynak kod int türü uzunluğunun 2 byte olduğu bir sistemde derlenirse problemler ortaya çıkacaktır. Bu taĢınabilirlik problemi sizeof operatörünün kullanılmasıyla çözülür. ptr = (int *) malloc(number * sizeof(int)); Artık çalıĢılan sistem ne olursa olsun number sayıda tamsayı eleman için alan ayırmıĢ olacaktır. malloc fonksiyonu birden fazla çağrılarak birden fazla alan ayrılabilir. malloc fonksiyonun farklı çağırımlarıyla ayrılan blokların bellekte ardıĢıl olması garanti altına alınmıĢ değildir. Bu yüzden fonksiyonun geri dönüĢ değeri olan adres mutlaka bir göstericide T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 saklanmalıdır. AĢağıdaki kod parçası ardıĢık olarak çağırılan malloc fonksiyonlarının ardıĢık bellek blokları ayıracağını varsaydığı için yanlıĢtır. malloc fonksiyonu ile ayrılan bloğun içinde rasgele değerler vardır. AĢağıdaki kod parçası ile bu test edilebilir. Dinamik bellek fonksiyonları kullanılarak ayırılabilecek bellek bölgesi heap olarak isimlendirilmiĢtir. heap alanı donanımsal bir kavram olmayıp sistemden sisteme değiĢebilmektedir. (C++ dilinde bu alan free store olarak isimlendirilmektedir.) malloc fonksiyonunun parametre değiĢkeni unsigned int (size_t) türünden olduğuna göre, DOS altında en fazla 65535 byte (64K) ardıĢıl yer ayırma yapılabilir. Oysa UNIX, WINDOWS ve diğer 32 bitlik sistemlerde unsigned int türü 4 byte uzunluğund olduğuna göre, bu sistemlerde teorik olarak, malloc fonksiyonu ile 4294967295 byte (4 MB) uzunluğunda ardıĢıl bir yer ayırma yapılabilir. 3.2. AYRILMIġ OLAN BLOĞUN SERBEST BIRAKILMASI T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 malloc ya da diğer dinamik bellek fonksiyonları "heap" diye isimlendirilen bir bellek bölgesinden yer ayırır. Ancak heap alanı da sınırlıdır ve sürekli bu fonksiyonların çağırılması durumunda, belirli bir noktadan sonra fonksiyonlar baĢarısız olarak NULL adresine geri dönecektir. heap alanının büyüklüğünü aĢağıdaki kod ile test etmek mümkündür; Dinamik bellek fonksiyonlarıyla ayrılan bir blok free fonksiyonu kullanılarak sisteme iade edilebilir. free fonksiyonunun prototipi de diğer dinamik bellek fonksiyonlarınınkiler gibi stdlib.h baĢlık dosyası içindedir. Kullanımı; void free(void *ptr); free fonksiyonuna gönderilecek olan arguman, daha önce malloc, calloc ya da realloc fonksiyonlarıyla ayırılmıĢ olan bellek bloğunun baĢlangıç adresidir. Bu blok heap alanına iade edilmiĢ olur. Böylece malloc, calloc ya da realloc fonksiyonunun bundan sonraki bir çağırımında iade edilen blok, tekrar ayrılma potansiyelindedir. free fonksiyonuna arguman olarak daha önce ayrılan bir bellek bloğunun baĢlangıç adresi yerine baĢka bir adres gönderilmesi Ģüpheli kod oluĢturur (undefined behaviour) yapılmamalıdır. char *p1; char s[100]; ptr = (char *)malloc(20); .... free(ptr) /* Legal */ free(p1) /* Bu adreste dinamik bellek fonksiyonları ile ayırılmıĢ bir alan yok. Hata. */ free(s) /* Hata s dizisi için yer ayırma dinamik bellek fonksiyonları ile yapılmamıĢtır. */ free fonksiyonu ile daha önce ayrılan blok sisteme iade edilir, ama bu bloğun baĢlangıç adresini tutan gösterici herhangi bir Ģekilde değiĢtirilmez. Bloğun baĢlangıç adresini tutan ve T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 free fonksiyonuna arguman olarak gönderilen gösterici, free fonksiyonun çağırılmasından sonra artık güvenli olmayan bir adresi göstermektedir. char *ptr = malloc(100); ... free(ptr); ... strcpy(ptr, "C Kodu"); /* yanlıĢ, bir gösterici hatası!! */ 3.4. DĠNAMĠK OLARAK AYIRILAN BĠR ALANIN BAġLANGIÇ ADRESĠNE GERĠ DÖNEN FONKSĠYONLAR Dinamik olarak ayırılan bir blok, free fonksiyonuyla serbest bırakılarak sisteme iade edilene kadar güvenli olarak kullanılabileceğine göre, bir fonksiyon böyle bir bloğun baĢlangıç adresine geri dönebilir. AĢağıdaki fonksiyon tasarımı incelendiğinde; Yukarıdaki fonksiyonda kullanıcıdan isim önce yerel bir diziye alınıyor. Daha sonra strlen fonksiyonu kullanılarak ismin uzunluğu tespit ediliyor ve malloc fonksiyonu ile bu ismi ve sonuna gelecek NULL karakteri içine alacak büyüklükte bir alan dinamik olarak ayrılıyor. Daha sonra da strcpy fonksiyonu kullanılarak, isim dinamik olarak ayırılan alana kopyalanaıyor ve bu bloğun baĢlangıç adresine geri dönülüyor. T.Ü. Tunca M.Y.O (Uzaktan Eğitim) BTP104-H1 Dinamik yer ayırma fonksiyonun çağırılması neticesinde yapılacak ve ayırılan bloğun serbest bırakılması fonksiyonu çağıranın sorumluluğunda olmaktadır.
© Copyright 2024 Paperzz