SINIFLAR VE DİNAMİK BELLEK YÖNETİMİ

Slides:



Advertisements
Benzer bir sunumlar
Dizi Kullanan Örnekler
Advertisements

Bölüm 12 ÜST DÜZEY KONULAR Dinamik Bellek Ayırma Önişlemci
Nesnelerin Özellikleri. - Üye nesneler - friend belirtesi - Nesnelerin operatörlere yüklenmesi - this yerel (lokal) değişkeni - inline tanımlı üye fonksiyonlar.
Göstericiler (Pointers)
SINIFLAR Yılmaz Kılıçaslan.
NESNEYE YÖNELİK PROGRAMLAMA SINIFLAR
Yığın ve Kuyruk.
Nesneye Yönelik Programlama
void medyan(int cevap[]) { int j; siralama(cevap);
Nesneye Dayalı Programlama
String Diziler(Katarlar)
Tanım Birbirleriyle ilişkili ve bitişik iki ya da daha fazla bellek hücresinden oluşan yapı Örnek dizi tanımı: int tamsayiDizi[10]; tamsayiDizi[0] /*ilk.
Değişken Bildirimleri
Yeni C++ Standartları: C++0x
Nesneye Dayalı Programlama
BPR152 ALGORİTMA VE PROGRAMLAMA - II
SANAL FONKSİYONLAR VE ÇOK BİÇİMLİLİK
String Kütüphanesindeki Arama Fonksiyonları
Bölüm 10 Yapılar ve Birleşimler
KOPYA YAPICI FONKSİYON, STATİK ELEMANLAR, ARKADAŞ SINIF VE FONKSİYONLAR, NESNE DİZİLERİ Yılmaz Kılıçaslan.
Nesneye Yönelik Programlama
SINIFLAR GİRİŞ Yılmaz Kılıçaslan.
Diziler.
Soru1: Bir tanesi tam sayı diğeri string olan iki elemanlı bir struct’ı bir başka struct’a direk kopyalama, memcpy kullanarak kopyalama ve tek tek elemanlarını.
DİZİLER.
Erişim Denetimi, Fonksiyon
While Döngüsü Tekrarlama deyimidir. Bir küme ya da deyim while kullanılarak bir çok kez yinelenebilir. Yinelenmesi için koşul sınaması döngüye girilmeden.
Nesneye Yönelik Programlama
C++ Temelleri C++ genel amaçlı, nesne tabanlı, yüksek seviye programlama dilidir.
Nesne Yönelimli Programlama Dersi
FONKSİYONLAR.
SABİT NESNE VE ELEMAN FONKSİYONLAR VE ELEMAN NESNELER
Bölüm 7 - Göstericiler İndeks 7.1 Giriş
Diziler Adres Kavramı Nesnelerin Adresleri sizeof Operatörü
NESNEYE YÖNELİK PROGRAMLAMA
Kalıtım , Sınıf Asli Ergün.
Nesneye Dayalı Programlama
C++’a Giriş Yılmaz Kılıçaslan.
Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü C ++ Veri.
SINIFLAR VE DİNAMİK BELLEK YÖNETİMİ VE SINIFLARIN DİĞER ÖZELLİKLERİ Yılmaz Kılıçaslan.
Trees, Vectors, Iterators. ADT Abstract Data Type (ADT) vs implementation -Soyut Veri Türleri - Uygulamaları.
Bölüm 3: Diziler BTEP 102 – Veri Yapıları ve Programlama
KALITIM Yılmaz Kılıçaslan.
SANAL FONKSİYONLAR VE ÇOKBİÇİMLİLİK Yılmaz Kılıçaslan.
Bölüm 5 Nesneler ve Metotlar
Bil 102 Bölüm 3 Java’da Program Akış Denetimi Bil 1021.
SINIFLAR GİRİŞ Yılmaz Kılıçaslan. Sunum Planı  Bu derste sınıf mekanizmasını şu yönleriyle inceleyeceğiz: –Sınıf kavramının evrimine kısa bir bakış –Bir.
SINIFLAR ve NESNELER. İlk sınıfımızı ekleyelim class KrediHesap { public ulong HesapNo; public double Limit; public string KartSahibi; }
Pointer (İşaretçi) Yapısal Veri Tipleri (Struct)
Celal Bayar Üniversitesi Hasan Ferdi Turgutlu Teknoloji Fakültesi
SINIFLAR VE DİNAMİK BELLEK YÖNETİMİ Yılmaz Kılıçaslan.
VERİ YAPILARI İşaretçi Nedir? Nesne Tabanlı Programlama.
SAÜ Bilgisayar Mühendisliği Dr. Cemil Öz
Veri yapıları Hafta3 Dizi Yapıları.
1 7. HAFTA. 2 Referanslar  Referanslar adres temsilcisidir  İşaretçilerin görevlerini kısmi olarak yapabilirler  Değişken değildirler.  Bellekte yer.
C Programlamada, benzer tipte tanımlaman değişkenleri kontrol etmede bize en çok yardım eden dostlarımız dizilerdir. Örneğin: 100 Öğrencinin bilgilerini.
BİLGİSAYAR programlama II
Hafta2 Rekürsif Algoritmalar
BİLGİSAYAR PROGRAMLAMA Ders 11: İşaretçi (Pointer) Kullanımı Yrd. Doç. Dr. Altan MESUT Trakya Üniversitesi Bilgisayar Mühendisliği.
JAVA 1. GİRİŞ & TARİHÇE Java, Sun Microsystems mühendislerinden James Gosling tarafından geliştirilmeye başlanmıştır. Açık kodlu. Nesneye yönelik. Düzlemden.
İbrahim Olgaç PROGRAMLAMA DİLLERİ SUNUMU C#
YAPISAL PROGRAMLAMA Hafta-5
5- class & object Nesne Yönelimli Programlama - i
C Programlama Yrd.Doç.Dr. Ziynet PAMUK BMM211-H11
PROGRAM KONTROL KOMUTLARI 1. if koşulu 2. if else koşulu
YAPISAL PROGRAMLAMA Hafta-7
Kurucular(Yapıcılar), Yıkıcılar
Nesneye Dayalı Programlama 1
NİŞANTAŞI ÜNİVERSİTESİ
Karakter dizi fonksiyonları
Sunum transkripti:

SINIFLAR VE DİNAMİK BELLEK YÖNETİMİ Yılmaz Kılıçaslan

Sunum Planı Bu derste aşağıdaki konuları inceleyeceğiz: “Free store” Atama operatörü this işaretçisi

C ve C++’da Dinamik Bellek Yönetimi <-uzun_ömürlü, -esnek> •   STATİK OTOMATİK <+uzun_ömürlü, -esnek> <-uzun_ömürlü, +esnek> • • DİNAMİK <+uzun_ömürlü, +esnek>

“Heap” C’de çalışma zamanında alınıp kullanılabilen bellek bölgesine “heap” denir. C’de heap’ten bellek istemek için malloc fonksiyonu kullanılır: struct t *t_ptr; t_ptr = (struct t *) malloc(sizeof(struct t)); C++ için malloc fonksiyonu istenmeyen sonuçlar üretebilir. Neden? //Ornek Tarih *tarihPtr; int i; tarihPtr = (Tarih *)malloc(sizeof(Tarih)); i = tarihPtr->aySoyle(); //Tanimsiz ay degeri //dondurur

“Free Store” - 1 C++ “free store” olarak adlandırılan bir bellek bölgesinden dinamik olarak nesne yaratmak ya da yok etmek için bellek kullanımına izin verir. Tarih *Ptr1, *Ptr2; int i; Ptr1 = new Tarih; //Varsayilan yap. fonk. cagrilir i = Ptr1->aySoyle(); //1 (varsayilan deger) doner Ptr2 = new Tarih(2,15,1985);//Yap. Fonk. cagrilir i = Ptr2->aySoyle(); //3 doner

“Free Store” - 2 Derleyici new operatörünün döndürdüğü işaretçinin kendisi için bellek ayrılan nesne için olup olmadığını kontrol eder: void *Ptr; Ptr = new Tarih; // Tip uyumsuzluğu

“delete” - 1 Nasıl malloc fonksiyonunun eşleniği olan bir free fonksiyonu varsa, new operatörünün de eşleniği olan bir delete operatörü vardır. delete operatörü ayrılan bellek bölgelerini daha sonra kullanılabilmek üzere “free store” bölgesine iade eder: Tarih *Ptr1; İnt i; Ptr1 = new Tarih(3, 15, 1985); İ = Ptr1->aySoyle(); delete Ptr1;

“delete” - 2 delete operatörü belleği geri vermeden önce otomatik olarak yıkıcı fonksiyonu çağırır. delete operatörünü yalnızca new ile döndürülen işaretçilere ve yalnızca bir kez uygulamalısınız. delete operatörünü, 0 değerli bir işaretçiye (“null pointer”) uygulayabilirsiniz.

“Free store” ve diğer veri tipleri - 1 new ve delete operatörlerini yalnızca sınıflarla değil diğer derleyici ile birlikte gelen veri tipleri ile de kullanabilirsiniz: // Ornek 1 int *ip; ip = new int; // ... delete ip;

“Free store” ve diğer veri tipleri - 2 // Ornek 2 int uzunluk; char *cp; // uzunluk degiskenine bir deger atanir cp = new char[uzunluk]; // ... delete [] cp;

“Free store” ve diğer veri tipleri - 3 // Ornek 3 int (*matrix)[10]; int boyut; // boyut degiskenine bir deger atanir matrix = new int[boyut][10]; // ... delete [] matrix;

İşaretçi Elemanlı Sınıflar - 1 new ve delete operatörlerini bir sınıfın eleman fonksiyonları içinde kullanabilirsiniz. Örnek: Her nesnesinin bir karakter katarı içereceği bir String sınıfı. #include <iostream>; #include <cstring>; class String { public: String(); String( const char *s ); String( char c, int n ); void belirle( int index, char yeniK ); char soyle( int index ) const; int uzunlukSoyle() const { return uzunluk; } void goruntule() const { cout << buf; } ~String(); private: int uzunluk; char *buf; };

İşaretçi Elemanlı Sınıflar - 2 // Varsayilan Yapici Fonksiyon String::String() { buf = 0; uzunluk = 0; } // const char * alan Yapici Fonksiyon String::String( const char * s ) { uzunluk = strlen( s ); buf = new char[uzunluk + 1]; strcpy( buf, s ); } // char ve int alan Yapici Fonksiyon String::String( char c, int n ) { uzunluk = n; memset( buf, c, uzunluk ); buf[uzunluk] = ‘\0’; }

İşaretçi Elemanlı Sınıflar - 3 // String içinde bir karakterin belirlenmesi void String::belirle( int index, char yeniK) { if( (index > 0) && (index <= uzunluk) ) buf[index - 1] = yeniK ; } // String içinden bir karakterin okunmasi char String::soyle( int index ) const return buf[index - 1]; else return 0; } // Yikici Fonksiyon String::~String() { delete [] buf; }

İşaretçi Elemanlı Sınıflar - 4 int main() { String string1(“birinci Karakter Katari”); string1.belirle(1, ‘B’); return 0; }

İşaretçi Elemanlı Sınıflar - 5 Her String nesnesi, birisi uzunluk ve buf eleman sahalarını içeren ve diğeri karakterlerin kendilerini depolayan iki bloktan oluşur. Nesnelerin içeriğini dinamik olarak değiştirmek mümkündür: void String::ekle( const char *ek ) { char *temp; uzunluk += strlen( ek ); temp = new char[uzunluk + 1]; strcpy( temp, buf ); strcat( temp, ek ); delete [] buf; buf = temp; } int main() { String string1(“birinci karakter katari”); string1.ekle(“ ve devami”); return 0; }

İşaretçi Elemanlı Sınıflar - 6 Bir String nesnesi kapsam alanının dışına çıkınca, uzunluk ve buf değerlerinin içeren bellek bloğu otomatik olarak serbest bırakılır. Fakat, karakter bloğu new ile alındığı için, açıkça serbest bırakılmalıdır. delete operatörünü kullanan yıkıcı fonksiyon bu işlevi yerine getirir. Yine de String sınıfı bazı problemlere potansiyel olarak açıktır. main fonksiyonuna aşağıdaki kod parçasını eklediğimizi varsayalım: String string2(“ikinci karakter katari”); string2 = string1; Bir nesnenin bir diğerine atanmasını istediğimizde derleyici eleman bazında atama yapar. Yani, yukarıdaki atama deyimi aşağıdaki koda denktir: string2.uzunluk = string1.uzunluk; string2.buf = string1.buf; Böyle bir atama işlemi sonucunda doğabilecek problemleri belirleyin.

İşaretçi Elemanlı Sınıflar - 7 Bir String nesnesini diğerine doğrudan atamamız neticesinde karşılaşacağımız problemler şunlardır: String nesnelerinden herhangi birine yapılacak bir değişiklik diğerini de etkileyecektir; bu muhtemelen arzu edilir bir durum olmayacaktır. string1 ve string2 nesnelerinin buf işaretçisi yıkıcı fonksiyonları üzerinden ayrı ayrı silinecektir. İşaretçiler aynı değeri taşıdığı için bu tahmin edilemeyen sorunlara yol açabilir. “ikinci karakter katari” değerini taşıyan string2 nesnesinin orijinal ‘buffer’ bloğu serbest bırakılmadan kaybolmuştur.

ATAMA OPERATÖRÜ - 1 Nasıl fonksiyon isimleri aşırı yüklenebiliyorsa (gerçekte birer fonksiyon olan) operatör isimleri de aşırı yüklenebilir. Aşağıda atama operatörünün aşırı yüklenmesini görmekteyiz: #include <iostream> #include <cstring> class String { public: String(); String( const char *s ); String( char c, int n ); void operator=( const String &digeri ); // ... }; void String::operator=(const String &digeri) { uzunluk = digeri.uzunluk; delete [] buf; buf = new char[uzunluk+1]; strcpy( buf, digeri.buf ); }

ATAMA OPERATÖRÜ - 2 int main() { String string1(“birinci karakter katari” ); string1.goruntule(); cout << ‘\n’; String string2(“ikinci karakter katari” ); string2.goruntule(); string2 = string1; return 0; } Derleyici deyimini aşağıdaki fonksiyon çağrımı gibi yorumlayacaktır: string2.operator=( string1 );

ATAMA OPERATÖRÜ - 3 Programcının yanlışlıkla String sınıfından bir nesneyi kendisine atadığını varsayalım: string1 = string1; Elbette çok az programcı böyle bir ifade yazacaktır. Fakat kendi kendine atama işlemi daha dolaylı yollardan da gerçekleştirilebilir: String *stringPtr = &string1; // ... string1 = *stringPtr; operator= fonksiyonunun böyle bir atama işlemi esnasında ne yapacağını belirleyin.

this İŞARETÇİSİ - 1 this işaretçisi statik eleman fonksiyonlar haricindeki eleman fonksiyonların erişebildiği özel bir işaretçidir: Eleman fonksiyonu çağıran nesneye işaret eder. Daha açıkçası bir eleman fonksiyonu bir nesne için çağırdığınız zaman, derleyici önce bu nesnenin adresini this işaretçisine atar ve ardından fonksiyonu çağırır. Eleman fonksiyon sınıfın eleman sahalarına her erişiminde örtük olarak this işaretçisini kullanır. Örneğin, void Tarih::ayBelirle( int mn ) { ay = mn; } // ... tarih1.ayBelirle( 3 ); biçimindeki C++ kod parçasının C karşılığı şöyle olacaktır: void ayBelirle(Tarih *const this, int mn ) { this->ay = mn; } ayBelirle( &tarih1, 3 );

this İŞARETÇİSİ - 2 Bir eleman fonksiyonu yazarken herhangi bir eleman sahaya erişmek için this işaretçisini açıkça kullanmak ya da fonksiyonu çağıran nesneye referansta bulunmak için *this ifadesini kullanmak meşru yöntemlerdir. Aşağıdaki örnekteki üç deyim birbirine denktir: void Tarih::ay_goruntule() { cout << ay; cout << this->ay; cout << (*this).ay; }

this İŞARETÇİSİ - 3 this işaretçisi bir eleman fonksiyonu çağıran nesne ile bu fonksiyona parametre olarak gönderilen nesnenin aynı nesneler olup olmadığını anlamak için kullanılabilir ve bu şekilde örneğin nesneyi kendisine değer olarak atama probleminden kaçınılabilir: void String::operator=(const String &digeri) { if( &digeri == this ) return; delete [] buf; uzunluk = digeri.uzunluk; buf = new char[uzunluk+1]; strcpy( buf, digeri.buf ); }

this İŞARETÇİSİ - 4 Hem C’de hem C++’da bir atama deyimi atananı değer olarak alan bir ifade gibi düşünülebilir. Örneğin, i = 3; değeri 3 olan bir ifadedir. Bu durumun bir neticesi birden fazla atama deyiminin zincirleme olarak birbirine bağlanabilmesidir: a = b = c; Atama operatörü sağdan birleştirmeli olduğundan yukarıdaki ifade aşağıdakiyle denktir: a = (b = c);

this İŞARETÇİSİ - 5 Bu zincirleme atama özelliğini aşırı yüklenmiş nesne atama fonksiyonunuzun da kullanmasını istiyorsanız, fonksiyonun atama sonucunu değer olarak döndürmesini sağlamalısınız: String &String::operator=(const String &digeri) { if( &digeri == this ) return *this; delete [] buf; uzunluk = digeri.uzunluk; buf = new char[uzunluk+1]; strcpy( buf, digeri.buf ); return *this; } Artık cout ifadelerinin de nasıl birden fazla çıktı değeri aldığını açıklayabiliriz: cout << a << b << c; Aşırı yüklenmiş sola kaydırma operatörü *this değerini cout nesnesi olarak döndürmektedir.