C++'ta belleğin heap kısmında veri tutmak (new keyword'ü)

Merhabalar herkese!

Bugün sizlere biraz "new" keyword'ü hakkında konuşacağım. Bu keyword ile (ve bir pointer ile), bir veriyi belleğin heap kısmında tutabilirsiniz.

Bu tekniğe aynı zamanda "dynamic memory allocation" da denir.

Öncelikle heap ve stack hakkında biraz konuşabiliriz.

Stack, İngilizce'de yığın anlamına gelir. Veriler aynı bir dolaptaki kutular gibi üst üste dizilidir. Yüksek adresten düşük adrese veri depolar.

Heap ise, az önce dediğimiz gibi, dinamiktir. Düzensiz bir şekilde veri depolar. Düşük adresten yüksek adrese veri depolar.

1596301980011.png


Dynamic memory allocation işlemi ise, stack'te pointer oluşturup, oradan heap'e bağlamak ve nesneyi (veya değişkeni) orada oluşturmaktır.

C ve C++'ta normalde yazdığımız değişkenler stack'te, düzenli bir şekilde depolanır. Ve program, işi bitince, bu değişkenleri siler. Ama heap'te kendimiz silmeliyiz. Silmezsek güvenlik açıkları (memory leak) ile uğraşırız.

Hadi, bir örnek kod yazalım!



C++:
#include <iostream>

using namespace std;

int main(){
    int j = 1;
    int *ptr = new int[5]; //5 elemanlı bir dizi
    for(int i = 0; i < 5; i++){
        j+=2;
        ptr[i] = j;
      
        cout<<"Dizinin "<<i<<". elemaninin degeri : "<<ptr[i]<<endl;
      
    }
  
    /*Ve tabii ki de memory leak'i önlemeliyiz.*/
    delete[] ptr;
    ptr = nullptr;
  
  
    return 0;
}

Bu kodumuzda, pointer yardımı ile heap'te 5 elemanlı bir dizi oluşturduk. Sonra dizi elemanlarına tek tek "for döngüsü" ile eleman atadık.

Kodumuzun sonunda da, güvenlik açıklarına karşın pointer'ımızın gösterdiği dizideki verileri sildik ve pointer'ımızı da "nullptr" yaptık, yani hiç bir şeyi göstermiyor.


Kodu derleyip deneyebilirsiniz.

Yorumlar

Makine diline çok yakın gibi, zor olsa gerek. Elinize sağlık.
Açıkçası C++'ın programcıya büyük bir güç verdiği hissediliyor fakat önyargılı olmayın derim. Öğrenme hevesiniz varsa zaten ister istemez öğrenirsiniz kendisini. Ayrıca, yeni çıkan standartlar ile C++, sürekli modernize edilmeye devam ediyor. Akıllı göstericiler (smart pointers) bunun en iyi örneği olabilir belki de. Daha üst seviye dillerdeki gibi yapıyor pointerları. Memory leak gibi açıkları kendisi çözüyor... Açıkçası C-style programlama yapmak hoşuma gidiyor, C++11'in sadece auto keyword'ünü ve foreach döngüsünü kullandım.
 
For döngüsü bu şekilde de yapılabiliyor. Keza uniform initialization da yaygınlaşmış durumda. Kullanmanızı tavsiye ederim.
Bunun dışında güzel bir anlatım olmuş.

Kod:
#include <iostream>

using namespace std;

int main() {
    auto j{ 1 };
    auto* ptr = new int[5]; //5 elemanlı bir dizi

    for (auto i{ 0 }; i < 5; ++i, j += 2) {
        ptr[i] = j;

        cout << "dizinin " << i << ". elemaninin degeri: " << ptr[i] << endl;

    }

    /*ve tabii ki de memory leak'i önlemeliyiz.*/
    delete[] ptr;
    ptr = nullptr;

    return 0;
}
 
For döngüsü bu şekilde de yapılabiliyor. Keza uniform initialization da yaygınlaşmış durumda. Kullanmanızı tavsiye ederim.
Bunun dışında güzel bir anlatım olmuş.

Kod:
#include <iostream>

using namespace std;

int main() {
    auto j{ 1 };
    auto* ptr = new int[5]; //5 elemanlı bir dizi

    for (auto i{ 0 }; i < 5; ++i, j += 2) {
        ptr[i] = j;

        cout << "dizinin " << i << ". elemaninin degeri: " << ptr[i] << endl;

    }

    /*ve tabii ki de memory leak'i önlemeliyiz.*/
    delete[] ptr;
    ptr = nullptr;

    return 0;
}

Çok teşekkürler hocam. Bu daha pratik bir döngü olmuş. Beğenmenize çok sevindim. :)
 
ptr = j; yerine ptr pointerına direk erişmek mümkün mü? Yani şöyle ptr'nin kendi adres değerini arttırırsak diyelim ki ptr'nin değeri 100 ileride tuttuğu değişkenin pointeri ise 104. ptr[0],ptr[1],ptr[2] gibi erişimlerde aslından biz ptr'nin değerini arttırıyoruz diyebilir miyiz? C++ cahili olduğumdan soruyorum.
 
ptr = j; yerine ptr pointerına direk erişmek mümkün mü? Yani şöyle ptr'nin kendi adres değerini arttırırsak diyelim ki ptr'nin değeri 100 ileride tuttuğu değişkenin pointeri ise 104. ptr[0],ptr[1],ptr[2] gibi erişimlerde aslından biz ptr'nin değerini arttırıyoruz diyebilir miyiz? C++ cahili olduğumdan soruyorum.
Estağfirullah. Deneye deneye bir yere varılıyor programlamada. Mesela söylediğiniz olayı biliyordum ama hiç denememiştim.


ptr++ işlemi yapınca, ortaya bozuk değerler çıkıyor.
ptrplusplus.PNG


Değer atayarak ptr++ yapınca ise, program hata vererek çıkış yapıyor ve değerler bozuk çıkıyor. Sadece 2 tanesi doğru, 5 ve 7.
eleman_atayip_ptrplusplus.PNG


Sadece değer atayınca ise çıktımız, tam beklediğimiz gibi oluyor.
with_valuew.PNG
 
Makine diline çok yakın gibi, zor olsa gerek. Elinize sağlık.
Estağfirullah. Deneye deneye bir yere varılıyor programlamada. Mesela söylediğiniz olayı biliyordum ama hiç denememiştim.


ptr++ işlemi yapınca, ortaya bozuk değerler çıkıyor.

Değer ayarak ptr++ yapınca ise, program hata vererek çıkış yapıyor ve değerler bozuk çıkıyor. Sadece 2 tanesi doğru, 5 ve 7.

Sadece değer atayınca ise çıktımız, tam beklediğimiz gibi oluyor.

Hocam şimdi standart int bellekte 4 byte yer kaplıyor. Biz int pointera erişip onun değerini bir arttırırsak aslında 4 arttırıyoruz. Bu bütün değişken tipleri için geçerli. Yani pointer bir birim arttırılınca aslında değişkenin hafızada ki standart kapladığı alan kadar artıyor.
Yani
int a = 12; int * pta = &a; // pta = 100 diyelim.
pta += 1; // pta = 104 oluyor.

Bu arada pointer değişkeninin gösterdiği adresteki datayı alabilmenin yoluna indirection diyorlar. Yani:
int b = *pta; // b=12 oluyor.
 
Hocam şimdi standart int bellekte 4 byte yer kaplıyor. Biz int pointera erişip onun değerini bir arttırırsak aslında 4 arttırıyoruz. Bu bütün değişken tipleri için geçerli. Yani pointer bir birim arttırılınca aslında değişkenin hafızada ki standart kapladığı alan kadar artıyor.
Yani
int a = 12; int * pta = &a; // pta = 100 diyelim.
pta += 1; // pta = 104 oluyor.

Bu arada pointer değişkeninin gösterdiği adresteki datayı alabilmenin yoluna indirection diyorlar. Yani:
int b = *pta; // b=12 oluyor.
Kod bu, pointer'a bağlı olan değişkenlerin değere sahip olduğundan emin olmak için de değer atadım.:

C++:
#include <iostream>



using namespace std;



int main(){

    int j = 1;

    int *ptr = new int[5]; //5 elemanlı bir dizi

    

    for(int i = 0; i < 5; i++){
        j+=2;
        ptr[i] = j;
      
}
    for(int i = 0; i < 5; i++){
      
        ptr+=sizeof(int);
      
        cout<<"Dizinin "<<i<<". elemaninin degeri : "<<*ptr<<endl; 
      
    }


    

  


    /*Ve tabii ki de memory leak'i önlemeliyiz.*/

    delete[] ptr;

    ptr = nullptr;





    return 0;
  
}
}
Öncelikle, sizeof(int) dememin sebebi ise int'in bazı derleyicilerde 2 byte da yer kaplayabilmesidir. Ben MinGW kullanıyorum ve 4 byte yer kaplıyor diye biliyorum.

Kodun çıktısı da şu şekilde oldu:

a.PNG


Demem o ki, adresi arttırarak heap'teki dizide gezinemiyoruz (iterate edemiyoruz). Rastgele sayıları çıktı olarak vermekte ve dönüş değeri olarak sıfır vermemekte.


Cahil hissediyorum burada.

Ya estağfirullah hocam, Python'da "abstraction" olayı çok ileri seviye. Yani demek istediğim, low-level şeyleri kendisi yaparak size yardım ediyor. Pointerlar orada yok, o yüzden anlamıyorsunuz sanırım. C veya C++ öğrenirseniz zamanla oturacaktır.
 
@TerabyteForever
Hocam sizeof(int) demeden arttırırsanız belki dediğim şeye yaklaşırsınız. Pointerın değerini 1 arttırırsanız o 4 artacak. Siz 4 arttırdınız ve 16 arttırmış oldunuz.
 
Son düzenleme:

Blog girdisi detayları

Ekleyen
TerabyteForever
Okuma süresi
1 dakika okuma
Görüntüleme
1.071
Yorumlar
12
Son güncelleme

Yazılım kategorisindeki diğer girdiler

TerabyteForever adlı kullanıcının diğer girdileri

Bu girdiyi paylaş

Geri
Yukarı