Veri Yapıları ve Programlama

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.