RAM'imi/ini Boşa Harca(t)ma / C ve Dinamiklik

ZuL-RaA

Kadim Üye
9 Ara 2017
5,552
839
Semerkant
Selamlar arkadaşlar,

GİRİŞ

Ram boşa harcatmak derken?
Dinamik?

C öyle bir dil ki fakirlik zamanlarının zenginliği gibi...
Çıktığı zamana göre ihtiyaçlara odaklı, ram dostu ve verimli.

Konu da genel olarak ram verimi için fonksiyonlara değinirken, kullanıma da değineceğiz. Dinamik yapıyı dizilerde görme işlemine de bakmış oluyoruz diyelim.
Biraz C hakkında bilgi gerekebilir ancak genel kitleye hitap edecektir.


Önce C hakkında biraz bilgi verip daha sonra bahsettiğim "dinamik bellek yönetimi" hususuna değineceğim. Biliyorsunuz C ileri seviye bir programlama dili olsa da alt seviye programlama diline benzer bir yapısı da var. Nesne tabanlı değil ama nesnelerin atası struct yapısına sahip.

Dil genel yapı itibariyle statiktir ve derleme usulü çalışır. Statik olması özellikle hız konusunda belirgin bir fark göstermekte olur. "Syntax" dediğimiz söz dizimi açısından da hızdan kar sağlar. Ben statik yapısı kısmında duracağım.

Statik yapıya sahip C'miz; değişken türlerinin belirtilmesi, değişkenlerin yerinin bellekte hazır tutulması, fonksiyonların kütüphanelere dağıtılması, fonksiyonların da döndüğü verinin türünün verilmesi, statik yani sonradan boyutta değişme yapılamayan dizi oluşturması, dizilerin boyutu belirli oluşması veyahut elemanların ram'de sıralı tutulması gibisinden özellikler sayesinde hızını kazanmış olur...

Üstteki paragraf açıklayıcı değildi farkındayım ve bilerek öyle bıraktım. Örnek bir C kodunu sizlere verip demek istediklerimizden ufak bir açıklamayla bahsedeceğim.

46mjMKR53.png


C:
#include <stdio.h> // ekrana yazı bastırmak için kullanılan fonksiyon için gerekli kütüphane.
#include <stdlib.h>

int fact(int x);
// fonksiyonunun ön tanımı, int main() aşağıda kalmasın diye fonksiyonun int main altına yazıldığı için ondan bahsedilmesidir.

int main() {

    int al; // değişken tipi tam sayı.
    char metin[40] = "Deneme metnim 40 hane olmayabilir.";
    // karakter dizisi ifadesi burada anlam bulur. her şey bir char, karakterdir. 1 byte yer tutarlar. ingiliz alfabesine ait
    //olmalı ancak. olmayanlar 2 byte.
    // 40 karakterli bir metin dedim ama o kadar tutmayabilir. ancak yerini ayırtmış oldum.

    printf("Factoriyel al say gir:");
    // ne girdisi alınacak onu sordum.

    scanf_s("%d", &al, sizeof(int)); // alınan girdi int cinsinden olduğu için %d şeklinde int girdisi alıyoruz.
    // farklı formatların farklı girdi alma şekilleri var. & ifadesi ramdeki yerini belirtiyor değişkenin.
    // sizeof(int) ise aldığım bu belirsiz değişkenin bir int gibi 4 byte kaplayacağını belirtiyor.

    printf("faktoriyeli: %d \n", fact(al));
    printf("adres %p \n", &al);
    // adresi basmak için %p kullandım.

    printf("%s", metin);

    // karakter dizisinin basmak için %s kullandım.

    return 0;
}

int fact(int x) // yukarı da bahsedilen fonksiyon burada tanımlandı.
{
    if (x == 1)
        return 1;

    return x * fact(x-1);
}

Koddaki açıklamaları okumak belki size neden hızlı olduğu konusunda fikir vermiştir. Her şey Alman düzeninde gibi ve israf yok. Çıktısı:

Factoriyel al say gir:5
faktoriyeli: 120
adres 0000002bb9dffd1c
Deneme metnim 40 hane olmayabilir.

Farklı türlerde çıktı için bile farklı yazım vardı. %d, %s, %p gördünüz. %f, %c, %lf, %ld de var.
Adres ram'deki yer. Kodu farklı çalıştıran cihazlar farklı yerde tutacak, 16'lık tabanda bir adres o . Benim ram 16x2, olduğu için adres gördüğünüz gibi 16 hane. Ona göre de uzunluğu değişir...

Dinamik Bellek Yönetimi Kısmı

Diziler statik demiştim. Eğer tam sayı dizisi ise her verinin arasında, 4 byte fark ile ram'de tutulur. Görelim.

Nb4m0ivkd6V.png


C:
#include <stdio.h>


int main()
{
    int dizi[5] = {0,1,2,3,4};
    for(int i; i < 5; i++)
    {
        printf("%p ", &dizi[i]);
    }


    return 0;
}

0x7ffe63b98770 0x7ffe63b98774 0x7ffe63b98778 0x7ffe63b9877c 0x7ffe63b98780

4, 4 artıyor, 16'lık tabanda. Bu diziye artık yeni bir eleman eklenemez, çoktan ramdeki 0x7ffe63b98784 adresi farklı bir veriyle dolmuştur. Ekleyecek olsaydık tanımlarken eklememiz gerekirdi.

Değişme gerektiğinde kullanacağımız fonksiyonlar farklı bir kütüphanede. #include <stdlib.h>

malloc()

Pointer kavramına hakimseniz okumaya devam edebilirsiniz. Bunun sebebi yine adresler bir liste gibi tutulacağından ötürü yerleri bellek adresleri olur. int örnek ile yola devam ediyorum.

Kod:
int* ptr;

isimli bir değişkenim var. Yer atamasını yapalım,

Kod:
ptr = (int*) malloc(100 * sizeof(int));

sizeof(int) kısmı int 4 byte olduğu için 4'e eşit. 400 byte yer eder. Adres olacakları için ve int olduğu için (int*) ifadesi başına ekledik. Bu şekilde bir şeyin başına eklemek yapıyorsak, tür dönüşümü biliyorsunuz. Yani o adresin işaret ettiği değeri int olarak kabul ettik. Başlangıçta veri ataması yoktu. Bazı derleyiciler varsayılan olarak 0 kabul edebilir.
Pointer cinsinden 100 adet 4 byte'lık int yeri ayarladık kısaca.

* ptr isimli değişkenim 100 tane olan 4 byte'lık int adreslerimden ilkini tutucaktır.
* ptr isimli değişken adres değilde "NULL" dönerse yer ayıramamıştır.
* Başlangıçta veri ataması yapılmaz.
* Tek blok şeklinde atama yapar.

Adresler dizi gibi tutuluyor demiştim. Onlara erişmek adına diyelim 5 tane yer ayırdım, ilk indis 0 olmak üzere;

Kod:
ptr[x] = veri..

Örnek kod:

hsHQLxVnkD.png


C:
#include <stdlib.h>
#include <stdio.h>


int main() {


    int* ptr = (int*) malloc(3 * 4);


    for(int i= 0; i < 3; i++){
        printf("%p - %d, ", &ptr[i], ptr[i]);
    }


    free(ptr);
    return 0;
}

Çıktısı da böyledir.

0000022054561470 - 1414945136, 0000022054561474 - 544, 0000022054561478 - 1414922576,

Birinci ifade ram adresi, diğeri ise değeridir. Rastgele değer içeriyor çünkü henüz müdahale etmedik ve malloc ile oluşturuldu.

calloc()

Aynı işlevi ama biraz farklılıkla. Direkt onları verelim istiyorum;

* Varsayılan her eleman 0 değeri ile başlar.
* Birden fazla blok atar.

Tanımında ufak bir değişiklik var ama yine pointer bir değişken atayalım.

Kod:
int* ptr = (int*) calloc(x, 4);

Buradaki x 0'dan itibaren eleman numarası.

Yine benzer şekilde ptr[x] - x 0'dan itibaren - atadığınız değişkenlere erişmek için kullanılabilir.

Örnek kod:

1-VCl.png


C:
#include <stdlib.h>
#include <stdio.h>


int main() {


    int* ptr = (int*) calloc(3, 4);


    for(int i= 0; i < 3; i++){
        printf("%p - %d, ", &ptr[i], ptr[i]);
    }


    free(ptr);
    return 0;
}

Çıktısı:

00000217f7591470 - 0, 00000217f7591474 - 0, 00000217f7591478 - 0,

Varsayılan değerleri 0'dı.

free()

free(x) şeklindeki fonksiyon x isimli pointer malloc / calloc fonksiyonunun ayırdığı alanı iptal eder, boşaltır.
Bendeki derleyici free() kullanmadığımda "leaded." şeklinde belirtiyor. Dikkate değer.

realloc()

Bu fonksiyon malloc ile calloc ile oluşturulmuş bir yerin değerini güncellemek için kullanılır. Arttırma yaptığınızı kabul edersek yeni açtığınız alanlar boş olur. Eski alanlar verisini korur.

Kod:
int* ptr = (int*) malloc(4 * 4);

ise

Kod:
ptr = realloc(ptr, 5 * 4);

artık 5'lik bir yer oldu.

Malloc ile Calloc Arasındaki Fark ve Bu Bellek Tasarrufu Meselesi

Yazım şekilleri vs. hakkında zaten genel farkları verdik. Hız konusunda malloc daha hızlı olacaktır çünkü calloc bellek ayırma kadar içlerine "0" versini de yazıyor. Bunu da ekleyelim.

Bu fark meselesi kafanıza yatmadı değil mi? :D Açıkçası birçok kişi için tam yatmıyor. Bu bellek tasarruf meselesi ile alacağım.

C çıktığı yıllarda ne ram ne de depolama bu kadar fazla değildi. Küçük işlemciler küçük bellekler ile işlem yürütüyordu. C'nin hızının değeri ne güzel... Lakin array bile statik ve değişmiyor. Onu dinamik etmenin belleğe müdahaleden
başka yapılacak bir şeyi yok. Haliyle bellekte bir yerden başlamak ve iş bitince onu bırakmak o zamanlar için çok önemli. Şu zamanlar için pek değil. Bu iki fonksiyon da aynı işi yapar biri sadece 0 ile doldurduğu için daha yavaş.

Günümüzde bir farkı yoktur bizler için. Bellek tasarrufu da dediğim gibi o zamanlardan kalma bir sorun. Yine verimlilikte önemlidir ama. Bugün temel sistemlerde hız gerektiğinden gereksiz veya önemsiz denemez.

#C , #Malloc , #Calloc

Okuduğunuz için teşekkürler.
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.