4 - Dinamik Bellek Yönetimi
2025
Bellek yönetimi, yazılımcıların en önemli görevlerinden biridir. Özellikle C gibi dillerde, yazılımcılar belleği manuel olarak yönetmek zorundadır. Bu, karmaşık ve hataya açık bir işlem olabilmektedir.
Statik (Sabit) Bellek Yönetimi Yetersizlikleri:
Dinamik Bellek Yönetimi Çözümü:
Yüksek seviyeli dillerde (Java, Python vb.) dinamik bellek yönetimi otomatik olarak yapılır. Ancak C dilinde yazılımcı bu yönetimi kendisi yapmalıdır.
| Özellik | Statik Bellek Yönetimi | Dinamik Bellek Yönetimi |
|---|---|---|
| Bellek Ayırma | Derleme zamanında (compile-time) | Çalışma zamanında (runtime) |
| Bellek Miktarı | Sabit, program başında belirlenir | Değişken, program sırasında değişebilir |
| Esneklik | Düşük | Yüksek |
| Kontrol | Otomatik (derleyici tarafından) | Manuel (programcı tarafından) |
| Kullanım Alanı | Yerel değişkenler, global değişkenler | Değişken boyutlu veri yapıları, runtime boyut belirleme |
C dilinde dinamik bellek yönetimi için standart kütüphanede (stdlib.h) bulunan bazı fonksiyonlar kullanılır:
malloc(): Bellek ayırmacalloc(): Bellek ayırma ve sıfırlamarealloc(): Ayrılmış belleği yeniden boyutlandırmafree(): Ayrılmış belleği serbest bırakmamalloc() - Bellek AyırmaGörev: Belirtilen boyutta ham (initialize edilmemiş) bellek bloğu ayırır.
Sözdizimi:
size: Ayrılacak bellek bloğunun boyutu (byte cinsinden).void* işaretçi döner.NULL işaretçi döner. Dönüş değerini kontrol etmek çok önemlidir!int için bellek ayırma#include <stdio.h>
#include <stdlib.h>
int main() {
int *dizi;
int boyut = 10;
// 10 int için bellek ayır (10 * sizeof(int) byte)
dizi = (int*)malloc(boyut * sizeof(int));
// Bellek ayrılıp ayrılamadığını kontrol et
if (dizi == NULL) {
printf("Bellek ayırma başarısız!\n");
return 1; // Hata kodu ile çıkış
}
printf("Bellek başarıyla ayrıldı.\n"); // Diziyi kullan... (örneğin değer atama)
for (int i = 0; i < boyut; i++) {
dizi[i] = i * 2;
}
// Diziyi yazdır
for (int i = 0; i < boyut; i++) {
printf("%d ", dizi[i]);
}
printf("\n");
// Belleği serbest bırakmayı UNUTMA!
free(dizi);
dizi = NULL; // Serbest bırakılan işaretçiyi NULL yapmak iyi bir uygulamadır.
return 0; // Başarılı çıkış
}calloc() - Bellek Ayırma ve SıfırlamaGörev: Belirtilen sayıda ve boyutta bellek bloğu ayırır ve belleği sıfırlar (0 ile doldurur).
Sözdizimi:
num: Ayrılacak eleman sayısı.size: Her bir elemanın boyutu (byte cinsinden).malloc() ile aynı şekilde, başarılıysa adres, başarısızsa NULL.Temel Fark: calloc() ayrılan belleği sıfırlar, malloc() sıfırlamaz.
int için bellek ayırma ve sıfırlamarealloc() - Belleği Yeniden BoyutlandırmaGörev: Önceden ayrılmış bir bellek bloğunun boyutunu değiştirir (büyütür veya küçültür).
Sözdizimi:
ptr: Yeniden boyutlandırılacak önceden ayrılmış bellek bloğunun işaretçisi.new_size: Yeni istenen boyut (byte cinsinden).void* işaretçi döner. Bu adres ptr ile aynı olmayabilir!NULL işaretçi döner. Orijinal bellek bloğu değişmeden kalır.realloc() yeni bir bellek bloğu ayırabilir ve içeriği eski bloktan yeni bloğa kopyalayabilir.new_size 0 ise ve ptr NULL değilse, realloc() free(ptr) gibi davranır (belleği serbest bırakır).ptr NULL ise, realloc(NULL, size) malloc(size) gibi davranır (yeni bellek ayırır). printf("Başlangıç dizisi: ");
for (int i = 0; i < boyut; i++) {
printf("%d ", dizi[i]);
}
printf("\n");
// Dizinin boyutunu 10'a çıkar
boyut = 10;
int *yeni_dizi = (int*)realloc(dizi, boyut * sizeof(int)); // realloc'un dönüş değerini kontrol et!
if (yeni_dizi == NULL) {
printf("Bellek yeniden boyutlandırma başarısız!\n");
free(dizi); // Orijinal belleği serbest bırak
return 1;
}
dizi = yeni_dizi; // İşaretçiyi güncelle (önemli!)free() - Belleği Serbest BırakmaGörev: Dinamik olarak ayrılmış bir bellek bloğunu sisteme geri verir (serbest bırakır). Bu bellek, başka dinamik bellek istekleri için tekrar kullanılabilir hale gelir.
Sözdizimi:
ptr: Serbest bırakılacak bellek bloğunun başlangıç adresini gösteren işaretçi. Bu işaretçi daha önce malloc(), calloc() veya realloc() tarafından döndürülmüş olmalıdır.ptr NULL ise, free(NULL) hiçbir şey yapmaz (güvenlidir).#include <stdio.h>
#include <stdlib.h>
int main() {
int *dizi;
dizi = (int*)malloc(10 * sizeof(int));
if (dizi == NULL) {
printf("Bellek ayırma başarısız!\n");
return 1;
}
// ... Diziyi kullan ...
// Belleği serbest bırak
free(dizi);
dizi = NULL; // İşaretçiyi NULL yapmak iyi bir uygulama
return 0;
}Bellek Sızıntısı (Memory Leak):
free() ile serbest bırakılmaması durumunda oluşur.Sarkan İşaretçi (Dangling Pointer):
Çift Serbest Bırakma (Double Free):
free() ile serbest bırakmaya çalışmak.İyi Uygulamalar:
free() ile serbest bırakın.malloc(), calloc(), realloc() dönüş değerlerini kontrol edin. NULL dönmüşse bellek ayırma başarısız olmuştur.NULL yapın (sarkan işaretçileri önlemek için).Dinamik Diziler (Resizable Arrays):
malloc() ile başlangıç boyutu kadar bellek ayır, realloc() ile boyutu gerektiğinde büyüt.Dinamik Karakter Dizileri (Strings):
malloc() ile yeterli bellek ayır, realloc() ile metin uzadıkça belleği büyüt.Bağlı Listeler, Ağaçlar, Grafikler gibi Veri Yapıları:
malloc(), calloc(), realloc(), free() fonksiyonları ile yapılır.