Bu proje, C++ dilinde temel programlama becerilerini geliştirmek için hazırlanmıştır. Veri türleri, kontrol yapıları ve fonksiyonlar üzerine uygulamalı çalışmalar yapılır. Ayrıca, sınıf tanımlamaları ve bellek yönetimi gibi konular da ele alınır.
- Bellek Tahsisi Türleri
- Pointer ve Referans
- Npos Nedir?
- Switch Nedir Ve Nasıl Kullanılır?
- ifstream Ve Ofstream Nedir?
Bellek yönetimi, C++ programlamada verimli yazılım geliştirme için hayati bir konudur. C++'ta bellek yönetimi, iki ana bellek bölgesi olan stack ve heap üzerinde gerçekleşir.
Statik bellek, programın derleme zamanında tahsis edilen ve programın tüm çalışma süresi boyunca varlığını sürdüren bellek alanıdır. Statik bellek, genellikle global değişkenler, statik değişkenler ve sabit boyutlu veri yapıları için kullanılır. Bu tür bellek, program kapandığında otomatik olarak serbest bırakılır.
Dinamik bellek, programın çalışma zamanında ihtiyaç duyulduğunda tahsis edilen bellek alanıdır. Bu bellek, new operatörü kullanılarak ayrılır ve delete operatörü ile manuel olarak serbest bırakılır. Dinamik bellek, esnek boyutlarda veri yapıları ve değişkenler için kullanılır, ancak doğru yönetilmezse bellek sızıntılarına yol açabilir.
Özellik | Stack Bellek | Heap Bellek |
---|---|---|
Bellek Tahsisi | Statik bellek tahsisi için kullanılır. Derleme zamanında belirlenir. | Dinamik bellek tahsisi için kullanılır. Çalışma zamanında new operatörü ile tahsis edilir. |
Kullanım Alanları | Yerel değişkenler ve geçici veriler. | Büyük ve değişken boyutlu veri yapıları. |
Bellek Yönetimi | Otomatik olarak yönetilir; fonksiyon tamamlandığında serbest bırakılır. | Manuel olarak yönetilmelidir; delete operatörü ile serbest bırakılmalıdır. |
Performans | Hızlı ve verimlidir, sınırlı bir boyuta sahiptir. | Daha yavaş çalışır ve daha fazla işlem süresi gerektirir. |
Tahsis Zamanı | Derleme zamanında tahsis edilir. | Çalışma zamanında tahsis edilir. |
Boyut | Sabit boyut; çalışma sırasında değiştirilemez. | Esnek boyut; çalışma zamanında belirlenebilir ve değiştirilebilir. |
- new: Dinamik bellek tahsisi yapar ve bir nesne oluşturur.
- delete: new ile tahsis edilen belleği serbest bırakır.
- new[]: Dinamik diziler için bellek tahsisi yapar.
- delete[]: new[] ile tahsis edilen dizilerin belleğini serbest bırakır.
#include "Zombie.hpp"
int main()
{
Zombie *zombie1 = newZombie("Foo"); // Dinamik bellek tahsisi: new operatörü ile heap'te bir Zombie nesnesi oluşturulur.
zombie1->announce(); // Zombie nesnesinin announce() fonksiyonu çağrılır.
randomChump("Bar"); // Statik bellek tahsisi: randomChump fonksiyonunda stack üzerinde bir geçici Zombie nesnesi oluşturulur.
delete zombie1; // Dinamik bellek serbest bırakma: heap'te tahsis edilen Zombie nesnesi serbest bırakılır.
return 0;
}
newZombie("Foo")
fonksiyonu ile heap üzerinde bir Zombie nesnesi oluşturulup, zombie1 işaretçisine atanır.
#include "Zombie.hpp"
Zombie* newZombie(std::string name){
return new Zombie(name); // Bu nesne dinamik olarak tahsis edilmiştir ve delete operatörü ile serbest bırakılmalıdır.
}
randomChump("Bar")
fonksiyonu çağrıldığında, stack üzerinde geçici bir Zombie nesnesi oluşturulur. Bu nesne fonksiyon tamamlandığında otomatik olarak serbest bırakılır.
#include "Zombie.hpp"
void randomChump(std::string name)
{
Zombie zombie(name);
zombie.announce();
}
delete zombie1
satırı, new operatörü ile tahsis edilen heap bellek alanını serbest bırakır. Bu işlem, bellek sızıntılarını önlemek için gereklidir.
delete zombie1;
Stack ve heap bellekleri, C++'ta bellek yönetiminin temel yapı taşlarıdır. Stack, hızlı ve otomatik bir bellek yönetimi sunarken, heap, esneklik ve dinamik bellek tahsisi gerektiren durumlar için uygundur. Her iki bellek türünün de doğru bir şekilde kullanılması, programın performansını ve güvenilirliğini artıracaktır.
C++ dilinde, pointer (işaretçi) bir değişkenin bellek adresini tutar ve bu adrese eri��im sağlar. Pointerlar, bellek yönetimi ve dinamik veri yapıları için kullanılırken, referans ise bir değişkenin başka bir adıdır ve orijinal değişkeni doğrudan gösterir. Referanslar, işaretçilerden daha güvenli bir kullanım sağlar çünkü referanslar oluşturulduklarında hemen bir değişkene bağlanır ve bu bağlama daha sonradan değiştirilemez.
Pointer (işaretçi), bir değişkenin bellek adresini tutan bir değişkendir. İşaretçilerin temel özellikleri şunlardır:
- Tanım: Bir işaretçi, bir değişkenin bellek adresini saklar ve bu adrese erişim sağlar.
- Tanımlama: İşaretçi değişkenleri
*
sembolü ile tanımlanır. - Kullanım: Bir işaretçiye bir adres atanabilir ve bu adres üzerinden veri erişilebilir.
Referans, bir değişkenin başka bir isimle ifade edilmesidir. Referanslar şu özelliklere sahiptir:
- Tanım: Referans, bir değişkenin başka bir adıdır. Referanslar, orijinal değişkeni doğrudan gösterir.
- Tanımlama: Referanslar & sembolü ile tanımlanır ve bir değişkene atanabilir.
- Kullanım: Referanslar, orijinal değişkenle aynı bellek alanını paylaşır ve bu yüzden referansa yapılan değişiklikler orijinal değişkeni de etkiler.
Özellik | Pointer | Referans |
---|---|---|
Bellek Yönetimi | Bellek adresini tutar. | Doğrudan bir değişkenin adıdır. |
Null Değeri | nullptr ile boş olabilir. |
Boş olamaz; her zaman geçerli bir değişkene bağlanır. |
Değer Atama | Yeni bir adres atanabilir. | Bir kez bağlanır ve bağlandığı değişken değiştirilemez. |
Kullanım | Dinamik bellek yönetimi gibi ileri düzey işlemler için kullanılır. | Genellikle fonksiyon parametreleri ve geri dönüş değerleri için kullanılır. |
#include <iostream>
#include <string>
int main()
{
// Bir string değişkeni tanımlanır ve değer atanır.
std::string string = "HI THIS IS BRAIN";
// 'string' değişkeninin adresini tutan bir işaretçi tanımlanır.
std::string *stringPTR = &string;
// 'string' değişkenine referans olarak bağlanan bir referans değişkeni tanımlanır.
std::string &stringREF = string;
// 'string' değişkeninin bellek adresi yazdırılır.
std::cout << "string address: " << &string << std::endl;
// 'stringPTR' işaretçisinin tuttuğu bellek adresi yazdırılır.
std::cout << "stringPTR address: " << stringPTR << std::endl;
// 'stringREF' referansının bellek adresi yazdırılır.
// Referans değişkenin adresi, bağlı olduğu 'string' değişkenin adresiyle aynı olacaktır.
std::cout << "stringREF address: " << &stringREF << std::endl;
// 'string' değişkeninin değeri yazdırılır.
std::cout << "string value: " << string << std::endl;
// 'stringPTR' işaretçisinin işaret ettiği adresin değeri yazdırılır.
std::cout << "stringPTR value: " << *stringPTR << std::endl;
// 'stringREF' referansının değeri yazdırılır.
// Referans, 'string' değişkeninin kendisini ifade eder, bu yüzden değer aynı olacaktır.
std::cout << "stringREF value: " << stringREF << std::endl;
}
kodun çıktısı şu şekiilde olucaktır.
string address: 0x7fffc8f5a800
stringPTR address: 0x7fffc8f5a800
stringREF address: 0x7fffc8f5a800
string value: HI THIS IS BRAIN
stringPTR value: HI THIS IS BRAIN
stringREF value: HI THIS IS BRAIN
yani kısaca, işaretçi ve referanslar, değişkenin bellekteki adresine erişimi sağlayarak, değişkenin değerini değiştirme veya okuma işlemleri yapabilir. Bu, işaretçiler ve referansların aynı veri üzerinde işlem yapabilme yeteneğini gösterir.
std::string::npos
, C++'ta std::string
sınıfının bir özelliğidir ve özellikle arama işlemleriyle ilgili olarak kullanılır. npos, genellikle bir arama sonucunun bulunmadığını belirtmek için kullanılır.
Tanım: std::string::npos
, std::string
sınıfında tanımlı bir sabittir ve size_t
türünde olup, "bulunamadı" durumunu belirtmek için kullanılır. Bu sabit, genellikle std::string::find
, std::string::rfind
, std::string::find_first_of
gibi metotlarda arama sonucunun bulunmadığını belirtmek için kullanılır.
Değer: npos, size_t
türünün maksimum değerine eşittir. Bu, npos'un en büyük size_t
değerini temsil ettiği anlamına gelir. Bu büyük değer, pratikte npos'un hiçbir geçerli konumu temsil etmediğini gösterir.
Kullanım: Genellikle bir arama veya bulma işleminin sonucunu kontrol etmek için kullanılır. Eğer arama sonucu npos ise, bu, aramanın başarısız olduğunu ve belirtilen alt dizinin bulunamadığını belirtir.
Örnek:
#include <iostream>
#include <string>
#include <fstream>
int main(int ac, char **av)
{
// Komut satırında doğru sayıda argüman olup olmadığını kontrol et
if(ac != 4)
{
std::cout << "*** You must enter 4 arguments." << std::endl ;
return 0;
}
// Girdi dosyasını aç
std::ifstream inputFile(av[1]);
if(!inputFile)
{
std::cout << "*** Entered file cannot open." << std::endl;
return 0;
}
// Aranacak ve değiştirilecek kelimeleri al
std::string s1 = av[2];
std::string s2 = av[3];
// Aranacak ve değiştirilecek kelimelerin aynı olup olmadığını kontrol et
if(s1 == s2)
{
std::cout << "*** Are you kidding me? Please enter different word or letter." << std::endl;
return 0;
}
// Girdi dosyası açık olduğunda işlemleri başlat
if(inputFile.is_open())
{
std::string line;
// Çıkış dosyası ismi oluştur
std::string r_file = av[1];
r_file += ".replace";
std::ofstream replace_file(r_file);
// Dosyadaki her bir satırı oku
while(std::getline(inputFile, line))
{
// Satır içinde s1'in konumunu bul
size_t found = line.find(s1);
// s1 bulundukça değiştir
while(found != std::string::npos)
{
// s1'i kaldır ve s2 ile değiştir
line.erase(found, s1.length());
line.insert(found, s2);
// Yeni satırda s1'in başka bir örneği olup olmadığını kontrol et
found = line.find(s1);
}
// Değiştirilmiş satırı çıkış dosyasına yaz
replace_file << line << std::endl;
}
// Dosyaları kapat
replace_file.close();
inputFile.close();
}
return 0;
}
Açıklama: Bu program, bir giriş dosyasındaki belirli bir kelimeyi başka bir kelimeyle değiştirmek için tasarlanmıştır. İşte nasıl çalıştığı:
Argüman Kontrolü: Program, komut satırında tam olarak dört argüman olup olmadığını kontrol eder. Eksik veya fazla argüman varsa hata mesajı verir.
Dosya Açma: İlk argüman olarak verilen dosya ismini kullanarak bir ifstream
nesnesi oluşturur ve dosyayı açar. Dosya açılamazsa, bir hata mesajı verir.
Kelimeleri Alma: İkinci ve üçüncü argümanlar, dosyada aranacak kelime (s1)
ve onunla değiştirilecek kelime (s2)
olarak alınır.
Aynı Kelime Kontrolü: Eğer s1
ve s2
aynıysa, bir hata mesajı verir çünkü aynı kelimeyi değiştirmek anlamsızdır.
Satır Satır İşleme: Dosyanın her satırını okur ve s1
kelimesini bulur. std::string::find
fonksiyonu ile s1
in bulunup bulunmadığını kontrol eder. std::string::find
fonksiyonu, aranan kelimeyi bulamazsa std::string::npos döner.
Kelime Değiştirme: s1
bulunursa, line.erase()
ve line.insert()
fonksiyonları ile s1
kelimesini s2
ile değiştirir. find fonksiyonu tekrar kullanılarak s1
in başka bir örneği olup olmadığı kontrol edilir.
Sonuçları Yazma: Değiştirilmiş satırı yeni bir dosyaya yazar ve işlemi tamamladıktan sonra dosyaları kapatır.
Not
std::string::npos
, std::string::find
fonksiyonunun aranan alt diziyi bulamadığı durumlarda döndürülen özel bir sabittir.
Bu sabit, size_t
türünün maksimum değerine eşittir ve arama sonucunun bulunmadığını belirtir.
Kodda line.find(s1)
çağrısı ile s1
kelimesinin satırda olup olmadığı kontrol edilir ve eğer npos dönerse, aranan kelime bulunamamış demektir.
switch ifadesi, bir değişkenin değerine göre programın belirli bir yol izlemesini sağlayan bir kontrol yapısıdır. switch, birden fazla durumu kontrol etmek ve her durum için farklı kod blokları çalıştırmak için kullanılır. Bu yapı, birden fazla if-else
ifadesi yazmaktan daha temiz ve anlaşılır bir alternatif sunar.
switch ifadesi
, bir anahtar kelime (değişken veya ifade) alır ve bu anahtar kelimenin değerine göre farklı case bloklarını çalıştırır. Her case, anahtar kelimenin belirli bir değeri ile eşleşir. Eğer hiçbir case ile eşleşmezse, isteğe bağlı olarak bir default bloğu çalıştırılır.
switch (değişken) {
case değer1:
// Değişken değer1 ile eşleşirse bu kod bloğu çalışır
break;
case değer2:
// Değişken değer2 ile eşleşirse bu kod bloğu çalışır
break;
// İstenilen kadar case eklenebilir
default:
// Hiçbir case ile eşleşmezse bu kod bloğu çalışır
}
void Harl::complain(std::string level)
{
std::string data[4] = {"DEBUG", "INFO", "WARNING", "ERROR"};
int i = 0;
while(!data[i].empty() && data[i] != level)
i++;
switch(i)
{
case 0:
this->Harl::debug();
case 1:
this->Harl::info();
case 2:
this->Harl::warning();
case 3:
this->Harl::error();
break;
default:
std::cout << "[ Probably complaining about insignificant problems ]" << std::endl;
break;
}
}
Açıklama:
Bu switch
yapısı, i
değişkenine bağlı olarak belirli fonksiyonları çağırır. i
değeri 0
ile 3
arasında olduğunda sırasıyla debug()
, info()
, warning()
, veya error()
fonksiyonları çağrılır. break
komutunun eksik olduğu durumlarda, belirtilen durumdan sonraki tüm fonksiyonlar da çalıştırılır. i
0-3
aralığında değilse, varsayılan bir mesaj gösterilir.
Bu yapı, özellikle belirli bir değişkenin birçok farklı değerine göre farklı işlemler yapmak gerektiğinde oldukça kullanışlıdır.
ifstream
ve ofstream
, C++ dilinde dosya işlemleri için kullanılan temel akış sınıflarıdır. ifstream dosyalardan veri okumak için, ofstream ise dosyalara veri yazmak için kullanılır. Her iki sınıf da <fstream>
başlık dosyasında tanımlanmıştır ve dosya akışı sırasında hata kontrolü ve veri işleme işlevlerini yerine getirir. Bu sınıflar, dosya tabanlı veri işleme uygulamalarında yaygın olarak kullanılır ve programcılara esnek bir dosya yönetim mekanizması sunar.
Amaç: Dosyadan veri okumak için kullanılır.
Kullanım: Bir dosya açılır ve bu dosya üzerinden veri okuma işlemi yapılır.
Örnek:
#include <fstream>
#include <string>
int main() {
std::ifstream file("example.txt");
std::string line;
if (file.is_open()) {
while (getline(file, line)) {
std::cout << line << std::endl;
}
file.close();
} else {
std::cout << "Dosya açılamadı." << std::endl;
}
return 0;
}
Açıklama: Bu program, example.txt
adındaki bir dosyayı açar ve dosyadaki her satırı okuyup ekrana yazdırır. Eğer dosya başarıyla açılırsa, her satır getline
fonksiyonu ile okunur ve std::cout
ile ekrana yazdırılır. Dosya okuma işlemi tamamlandıktan sonra dosya kapatılır. Eğer dosya açılamazsa, hata mesajı ekrana yazdırılır.
Amaç: Dosyaya veri yazmak için kullanılır.
Kullanım: Bir dosya açılır veya oluşturulur ve bu dosyaya veri yazma işlemi yapılır.
Örnek:
#include <fstream>
int main() {
std::ofstream file("example.txt");
if (file.is_open()) {
file << "Hello, World!" << std::endl;
file.close();
} else {
std::cout << "Dosya açılamadı." << std::endl;
}
return 0;
}
Açıklama: Bu program, example.txt
adında bir dosya oluşturur veya var olan dosyayı açar ve içine "Hello, World!"
yazdırır. Eğer dosya başarıyla açılırsa, yazma işlemi yapıldıktan sonra dosya kapatılır. Dosya açılamazsa, hata mesajı ekrana yazdırılır.
#include <iostream>
#include <fstream>
#include <string>
int main(int ac, char **av)
{
// Argüman sayısını kontrol et
if(ac != 4)
{
std::cout << "*** You must enter 4 arguments." << std::endl ;
return 0;
}
// Girdi dosyasını aç
std::ifstream inputFile(av[1]);
// Dosyanın açılıp açılmadığını kontrol et
if(!inputFile)
{
std::cout << "*** Entered file cannot open." << std::endl;
return 0;
}
// Aranacak ve değiştirilecek kelimeleri al
std::string s1 = av[2];
std::string s2 = av[3];
// Aranacak kelime ve değiştirilmiş kelimenin aynı olup olmadığını kontrol et
if(s1 == s2)
{
std::cout << "*** Are u kidding me? Please enter different word or letter." << std::endl;
return 0;
}
// Dosya açıldıysa işlemlere başla
if(inputFile.is_open())
{
std::string line;
// Çıktı dosyasının adını belirle
std::string r_file = av[1];
r_file += ".replace";
// Çıktı dosyasını aç
std::ofstream replace_file(r_file);
// Girdi dosyasını satır satır oku
while(std::getline(inputFile, line))
{
// Aranacak kelimeyi bul
size_t found = line.find(s1);
// Aranacak kelime bulunana kadar işlemi tekrarla
while(found != std::string::npos)
{
// Aranacak kelimeyi sil
line.erase(found, s1.length());
// Değiştirilen kelimeyi ekle
line.insert(found, s2);
// Bir sonraki arama için pozisyonu güncelle
found = line.find(s1);
}
// Değiştirilen satırı çıktı dosyasına yaz
replace_file << line << std::endl;
}
// Dosyaları kapat
replace_file.close();
inputFile.close();
}
return 0;
}
Açıklama: Bu program, komut satırından üç argüman alarak bir dosya üzerinde metin değiştirme işlemi yapar.
-
Argüman Sayısını Kontrol Etme: Program, dört argüman (program adı ve üç ek argüman) bekler. Argüman sayısı doğru değilse hata mesajı verir ve sonlanır.
-
Dosya Açma: Girdi dosyası
(av[1])
ifstream kullanılarak açılır. Dosya açılamazsa hata mesajı verilir ve program sonlanır. -
Aranacak ve Değiştirilecek Kelimeler: s1 ve s2 isimli iki string değişken, ikinci
(av[2])
ve üçüncü(av[3])
argümanlardan alınır. Bu iki kelime arasında eşitlik kontrolü yapılır; eğer aynı ise kullanıcıya hata mesajı verilir. -
Dosya Okuma ve Değişiklik Yapma: Girdi dosyası açıldıysa, satır satır okunur. Her satırda
s1
kelimesi aranır. Bulunan tüm s1 kelimeleri,s2
ile değiştirilir. -
Sonuçların Yazılması: Değiştirilen her satır yeni bir dosyaya
(<original_filename>.replace)
yazılır. Bu dosya, ofstream kullanılarak oluşturulur ve yazma işlemi tamamlandığında kapatılır. -
Dosya Kapatma: Girdi ve çıktı dosyaları kapatılır.
2025 This project was created by Derya ACAR.