Bugün:   Şuanda Aktif: kişi.  Giriş Sayfan  -  Sık Kullan!  -  Ana Sayfa  -   Bize Ulaşın

 

   Günün Sözü:

Sevgimix  Menü


Ana Sayfa
Aşk ve Sevgi
Aşk Testi
Astroloji
Ps Oyunları
Araba Resimleri
Burçlar
Biyografiler
Bebek Resimleri
Ödev İndir
Cep Menü
Cinsellik
Canlı Tv
Gül Resimleri
Hazır Mesajları
itiraf Et
Diziler
Msn Avatarları
Müzik Haberleri
Oyun
Kadınca
Sağlıklı Yaşam
Sinema
Sohbet
Kız Tavlama
Lazer Epilasyon
Flashlı Şiirler
İddaa Sonuçları
Videolar
Şarkı Sözleri
Bilgisayar
Rüya Tabirleri
Partner Ara
Yıllık Planlar
Programlar

Hazır Mesajlar
14 Şubat Sevgililer Günü
Anneler Günü
Aşk Sözleri
Asker ve Askerlik
Babalar Günü
Bayram Mesajları
Doğum Günü
2007 Yeni Yıl Mesajları
Kurban Bayramı
Ramazan Bayramı
Kandil Mesajları
Önemli Linkler

Şehirler Arası Tel. Kodları
Tc Kimlik No
Ehliyet Sınav Sonuçları
Bağkur
Milli Piyango Sonuçları
SSK
Üniversiteler
Sayısal Loto
Açık Lise Sınav Sonuçları
M.E.B. Sınav Sonuçları
Araç Sorgulama
İL Hava Durumu
Ösym Sınav Sonuçları
Telefon Rehberi
Cep Imei Sorgulama
Posta Kodu
Açıkögretim Fakültesi

Programlar
Windows Live
Winamp Surround
WinRAR 3.61
Norton Antivirus
Java Sanal Makinesi
Messenger Plus Live
Çoklu MSN
FlashGet 1.73
Google Earth
Okey+ 2.1

- Bilgisayar Hakkında Herşeyi Bulabilirsiniz

C++ Nedir??

Programlarımızın kolay yazılır, doğru, bakımı kolay, ve belli sınırlar içerisinde verimli olmalarını isteriz. Bundan, doğal olarak C++'ı (ve başka dilleri de) bu amaca olabildiğince yakın olarak kullanmamız gerekliliği ortaya çıkar. C++ kullananların hâlâ Standart C++'ın getirdiği olanakları benimsemeyerek, C++ kullanım biçemlerini değiştirmediklerine; ve bu nedenle, değindiğim amaca yönelik büyük adımların atılamadığına inanıyorum. Bu yazı, Standart C++'ın getirdiği olanakların değil, bu olanakların desteklediği programlama biçemlerinin üzerinde durmaktadır.
Büyük gelişmelerin anahtarı, kod büyüklüğünü ve karmaşıklığını kitaplıklar kullanarak azaltmaktır. Bunları aşağıda, C++'a giriş kurslarında karşılaşılabilecek birkaç örnek kullanarak gösteriyor ve nicelendiriyorum.
Kod büyüklüğünü ve karmaşıklığını azaltarak hem geliştirme zamanını azaltmış oluruz, hem program bakımını kolaylaştırırız, hem de program sınamanın bedelini düşürürüz. Daha da önemlisi, C++'ın öğrenilmesini de kolaylaştırmış oluruz. Önemsiz veya bir dersten yalnızca geçer not almak için yazılan programlarda bu basitleştirme yeterlidir. Ancak, verimlilik, profesyonel programcılar için çok önemli bir konudur. Programlama biçemimizi, ancak günümüz bilişim hizmetlerinde ve işyerlerinde karşılaşılan boyutlardaki verilerle ve gerçek zaman programlarıyla uğraşırken verimlilik kaybına neden olmayacaksa değiştirebiliriz. Onun için, karmaşıklığın azaltılmasının verimliliği düşürmeden elde edilebileceğini gösteren ölçümler de sunuyorum.
Son olarak, bu görüşün C++'ın öğrenilmesi ve öğretilmesine olan etkilerini tartışıyo


KARMAŞIKLIK

Bir programlama dilini öğrenirken görülen ilk çalışma programlarından birisi olabilecek şu örneği ele alalım:

"Lütfen adınızı girin" yazın
adı okuyun
"Merhaba " yazın


Standart C++ çözümü şöyledir:

#include // standart giris/cikis
#include // standart dizgi

int main()
{
using namespace std; // standart kitapliga erisim

cout << "Lütfen adinizi girin:\n";
string ad;
cin >> ad;
cout << "Merhaba " << ad << '\n';
}

 Programcılığa yeni başlayan birisine bazı temelleri anlatmamız gerekir: 'main()' nedir? '#include' ne demektir? 'using' ne işe yarar? Ek olarak, '\n'in ne yaptığı ve noktalı virgülün nerelerde kullanıldığı gibi ayrıntıları da anlamamız gerekir. Yine de bu programın temeli kavramsal olarak kolay, ve soru metninden ancak gösterim açısından farklı. Tabii dilin gösterimini de öğrenmemiz gerekir. Ama bu da kolay: 'string' bir dizgi, 'cout' çıkış, '<<' çıkışa yazı göndermekte kullanılan bir işleç. Karşılaştırmak için, geleneksel C biçemiyle yazılmış çözüme bakalım. (Hoş göründükleri için değişmez bildirilerini ve yorumları C++ türünde yazdım. ISO standardına uygun C yazmak için '#define' ve '/* */' yorumları kullanılmalıdır.)

#include // standart giris/cikis

int main()
{
const int encok = 20;
char ad[encok];

printf("Lutfen adinizi girin:\n");
scanf("%s", ad); // ady oku
printf("Merhaba %s\n", ad);

return 0;
}

 Dizileri ve '%s'i de açıklamak gerektiği için bu programın içeriği, C++ eşdeğerinden az da olsa daha karmaşık. Asıl sorun, bu basit C çözümünün düşük nitelikli olması. Eğer birisi sihirli sayı 19'dan (belirtilen 20 sayısından C dizgilerinin sonlandırma karakterini çıkartarak) daha fazla harfli bir ad girerse program bozulur.
Daha sonradan uygun bir çözüm gösterildiği sürece bu niteliksizliğin zararsız olduğu öne sürülebilir. Ancak bu ifade "iyi" olmak yerine, olsa olsa "kabul edilebilir" olabilir. Yeni bir programcıya bu kadar kırılgan bir program göstermemek çok daha iyidir.
Peki davranış olarak C++ eşdeğerine yakın bir C programı nasıl olurdu? İlk deneme olarak dizi taşmasını 'scanf()'i daha doğru kullanarak engelleyebilirdik:

#include // standart giris/cikis

int main()
{
const int encok = 20;
char ad[encok];

printf("Lutfen adinizi girin:\n");
scanf("%19s", ad); // adi en fazla 19 harf olarak oku
printf("Merhaba %s\n", ad);

return 0;
}

 'scanf()'in biçim dizgisinde ad dizisinin boyutunu gösteren 'encok'un simgesel şeklini kullanmanın standart bir yolu olmadığı için, tamsayı '19'u yazıyla yazmak zorunda kaldım. Bu hem kötü bir programlama biçemi, hem de program bakımı için bir kabustur. Bunu önlemenin oldukça ileri düzey sayılacak bir yolu var; ama bunu programlamaya yeni başlayan birisine açıklamaya yeltenmem bile:

char bicim[10];
sprintf(bicim, "%%%ds", encok-1); // bicim dizgisini hazirla; %s tasabilecegi icin
scanf(bicim, ad);

 Dahası bu program, fazladan yazılan harfleri de gözardı eder. Asıl istediğimiz, dizginin girdiyle orantılı olarak büyümesidir. Bunu sağlayabilmek için daha alt düzey bir soyutlamaya inip karakterlerle tek tek ilgilenmek gerekir:

#include
#include
#include

void cik() // hatayi ilet ve programdan cik
{
fprintf(stderr, "Bellekte yer kalmadi\n");
exit(1);
}

int main()
{
int encok = 20;
char * ad = (char *)malloc(encok); // arabellek ayir
if (ad == 0) cik();

printf("Lütfen adýnýzý girin:\n");

while (true) { // bastaki boþluklari atla
int c = getchar();
if (c == EOF) break; // kutuk sonu
if (!isspace(c)) {
ungetc(c,stdin);
break;
}
}

int i = 0;
while (true) {
int c = getchar();
if (c == '\n' || c == EOF) { // sonlandirma karakterini ekle
ad[i] = 0;
break;
}
ad[i] = c;
if (i==encok-1) { // arabellek doldu
encok = encok+encok;
ad = (char*)realloc(ad,encok); // daha buyuk yeni bir arabellek ayir
if (ad == 0) cik();
}
i++;
}

printf("Merhaba %s\n", ad);
free(ad); // arabellegi birak
return 0;
}

 Bir öncekiyle karşılaştırıldığında bu program çok daha karmaşık. Çalışma programında istenmediği halde baştaki boşlukları atlayan kodu yazdığım için kendimi biraz kötü hissediyorum. Ne var ki, olağan olan, boşlukları atlamaktır; zaten programın eşdeğerleri de bunu yapıyorlar.
Bu örneğin o kadar da kötü olmadığı öne sürülebilir. Zaten birçok deneyimli C ve C++ programcısı gerçek bir programda herhalde (umarız?) buna benzer birşey yazmıştır. Daha da ileri giderek, böyle bir programı yazamayacak birisinin profesyonel bir programcı olmaması gerektiğini bile ileri sürebiliriz. Bu programın yeni başlayan birisini ne kadar zorlayacağını düşünün. Program bu şekliyle dokuz değişik standart kitaplık işlevi kullanmakta, oldukça ayrıntılı karakter düzeyinde giriş işlemleriyle uğraşmakta, işaretçiler kullanmakta, ve bellek ayırmayla ilgilenmektedir. Hem 'realloc()'u kullanıp hem de uyumlu kalabilmek için 'malloc()'u kullanmak zorunda kaldım ('new'ü kullanmak yerine). Bunun sonucu olarak da işin içine bir de arabellek boyutları ve tür dönüşümleri girmiş oldu. (C'nin bunun için tür dönüşümünü açıkça yazmayı gerektirmediğini biliyorum. Ama onun karşılığında ödenen bedel, 'void *'dan yapılan güvensiz bir örtülü tür dönüşümüne izin vermektir. Onun için C++, böyle bir durumda tür dönüşümünün açıkça yapılmasını gerektirir.) Bellek tükendiğinde tutulacak en iyi yolun ne olduğu bu kadar küçük bir programda o kadar açık değil. Konuyu fazla dallandırmamak için kolay anlaşılır bir yol tuttum. C biçemini kullanan bir öğretmen, bu konuda ilerisi için temel oluşturacak ve kullanımda da yararlı olacak uygun bir yol seçmelidir.
Özetlersek, başta verdiğimiz basit örneği çözmek için, çözümün özüne ek olarak, döngüleri, koşulları, bellek boyutlarını, işaretçileri, tür dönüşümlerini, ve bellek yönetimini de tanıtmak zorunda kaldım. Bu biçemde ayrıca hataya elverişli birçok olanak da var. Uzun deneyimimin yardımıyla bir eksik, bir fazla, veya bellek ayırma hataları yapmadım. Ama bir süredir çoğunlukla C++'ın akım giriş/çıkışını kullanan birisi olarak, yeni başlayanların çokça yaptıkları hatalardan ikisini yaptım: 'int' yerine 'char'a okudum ve EOF'la karşılaştırmayı unuttum. C++ standart kitaplığının bulunmadığı bir ortamda çoğu öğretmenin neden düşük nitelikli çözümü yeğleyip bu konuları sonraya bıraktığı anlaşılıyor. Ne yazık ki çoğu öğrenci düşük nitelikli biçemin "yeterince iyi" olduğunu ve ötekilerden (C++ olmayan biçemler içinde) daha çabuk yazıldığını hatırlıyor. Sonuçta da vazgeçilmesi güç bir alışkanlık edinip arkalarında yanlışlarla dolu programlar bırakıyorlar.
İşlevsel eşdeğeri olan C++ programı 10 satırken, son C programı tam 41 satır. Programların temel öğelerini saymazsak fark, 30 satıra karşın 4 satır. Üstelik C++ programındaki satırlar hem daha kısa, hem de daha kolay anlaşılır. C++ ve C programlarını anlatmak için gereken toplam kavram sayısını ve bu kavramların karmaşıklıklarını nesnel olarak ölçmek zor. Ben C++ biçeminin 10'a 1 daha kazançlı olduğunu düşünüyorum.

 


VERİMLİLİK

Yukarıdaki gibi basit bir programın verimliliği o kadar önemli değildir. Böyle programlarda önemli olan, basitlik ve tür güvenliğidir. Verimliliğin çok önemli olduğu parçalardan oluşabildikleri için, gerçek sistemler için "üst düzey soyutlamayı kabul edebilir miyiz" sorusu doğaldır.
Verimliliğin önemli olduğu sistemlerde bulunabilecek türden basit bir örneği ele alalım:

belirsiz sayıda öğe oku
öğelerin her birisine bir şey yap
öğelerin hepsiyle bir şey yap


Aklıma gelen en basit örnek, girişten okunacak bir dizi çift duyarlıkla kayan noktaya sanyınyan ortalama ve orta değerlerini bulmak. Bunun geleneksel C gibi yapılan bir çözümü böyle olurdu:

// C biciminde cozum

#include
#include

int karsilastir(const void * p, const void * q) // qsort()'un kullandigi karsilastirma islevi
{
register double p0 = *(double*)p; // sayilari karsilastir
register double q0 = *(double*)q;
if(p0>q0) return 1;
if (p0 return 0;
}

void cik() // hatayi ilet ve programdan cik
{
fprintf(stderr, "Bellekte yer kalmadi\n");
exit(1);
}

int main(int argc, char* argv[])
{
int boyut = 1000; // ayrimin baslangic boyutu
char* kutuk = argv[2];

double* arabellek = (double*)malloc(sizeof(double)*boyut);
if (arabellek==0) cik();

double orta = 0;
double ortalama = 0;
int adet = 0; // toplam öge sayisi

FILE* giris=fopen(kutuk, "r"); // kutugu ac
double sayi;
while(fscanf(giris, "%lg", &sayi) == 1) { // sayiyi oku, ortalamayi deðistir
if (adet==boyut) {
boyut += boyut;
arabellek = (double*)realloc(arabellek, sizeof(double)*boyut);
if (arabellek==0) cik();
}
arabellek[adet++] = sayi;
// olasi yuvarlatma hatasi:
ortalama = (adet==1) ? sayi : ortalama + (sayi - ortalama) / adet;
}

qsort(arabellek, adet, sizeof(double), karsilastir);

if (adet) {
int ortadaki = adet / 2;
orta = (adet % 2) ? arabellek[ortadaki] : (arabellek[ortadaki - 1] + arabellek[ortadaki]) / 2;
}

printf("toplam öge = %d, orta deger = %g, ortalama = %g\n", adet, orta, ortalama);

free(arabellek);
}

 Karşılaştırmasını yapabilmek için C++ biçimini de veriyorum:

// C++ standart kitapligini kullanan cozum

#include
#include
#include
#include

using namespace std;

int main(int argc, char * argv[])
{
char * kutuk = argv[2];
vector arabellek;

double orta = 0;
double ortalama = 0;

fstream giris(kutuk, ios::in); // kutugu ac
double sayi;
while (giris >> sayi) {
arabellek.push_back(sayi);
// olasý yuvarlatma hatasý:
ortalama = (arabellek.size() == 1) ? sayi : ortalama + (sayi - ortalama) / arabellek.size();
}

sort(arabellek.begin(), arabellek.end());

if (arabellek.size()) {
int ortadaki = arabellek.size() / 2;
orta = (arabellek.size() % 2) ? arabellek[ortadaki] : (arabellek[ortadaki-1]+arabellek[ortadaki]) / 2;
}

cout << "toplam öge = " << arabellek.size()
<< ", orta deger = " << orta << ", ortalama = " << ortalama << '\n';
}

 Program büyüklüklerindeki fark bir önceki örnekte olduğundan daha az: boş satırları saymayınca, 43'e karşılık 25. Satır sayıları, 'main()'in bildirilmesi ve orta değerin hesaplanması gibi ortak satırları (13 satır) çıkartınca 20'ye karşılık 12 oluyor. Okuma ve depolama döngüsü ve sıralama gibi önemli bölümler C++ çözümünde çok daha kısa: okuma ve depolama için 9'a karşılık 4, sıralama için 9'a karşılık 1. Daha da önemlisi, düşünce şekli çok daha basit olduğu için, C++ programının öğrenilmesi de çok daha kolay.
Tekrar belirtirsem, bellek yönetimi C++ programında örtülü olarak yapılıyor; yeni öğeler 'push_back'le eklendikçe 'vector' gerektiğinde kendiliğinden büyüyor. C gibi yazılan programda bu işin 'realloc()' kullanılarak açıkça yapılması gerekir. Aslında, C++ programında kullanılan 'vector'ün kurucu ve 'push_back' işlevleri, C gibi yazılan programdaki 'malloc()', 'realloc()', ve ayrılan belleğin büyüklüğüyle uğraşan kod satırlarının yaptıkları işleri örtülü olarak yapmaktadırlar. C++ gibi yazılan programda belleğin tükenme olasılığını C++'ın kural dışı durum işleme düzeneğine bıraktım. Belleğin bozulmasını önlemek için C gibi yazılan programda bunu açıkça yazdığım sınamalarla yaptım.
C++ programına doğru olarak oluşturmak da daha kolaydı. İşe bazı satırları C gibi yazılan programdan kopyalayarak başladım. kütüğünü içermeyi unuttum, iki yerde 'adet'i 'arabellek.size()'la değiştirmeyi unuttum, derleyicim yerel 'using' yönergelerini desteklemediği için 'using namespace std;' satırına 'main()'in dışına taşıdım. Program bu dört hatayı düzeltmemin ardından hatasız olarak çalıştı.
Programlamaya yeni başlayanlar 'qsort()'u biraz "garip" bulurlar. Öğe sayısının belirtilmesi neden gereklidir? (Çünkü C dizileri bunu bilmezler.) 'double'ın büyüklüğünün belirtilmesi neden gereklidir? (Çünkü 'qsort()' 'double'ları sıralamakta olduğunu bilmez.) O hoş gözükmeyen 'double' karşılaştırma işlevini neden yazmak zorundayız? (Çünkü 'double' sıraladığını bilmeyen 'qsort()'a karşılaştırmayı yaptırması için bir işlev gerekir.) 'qsort()'un kullandığı karşılaştırma işlevinin bağımsız değişkenleri neden 'char*' türünde değil de 'const void*' türündedir? (Çünkü 'qsort()'un sıralaması dizgi olmayan türden değişkenler üzerinedir.) 'void*' nedir ve 'const' olmasa ne anlama gelir? (E, şey, buna daha sonra değineceğiz.) Bunu yeni başlayanın boş bakışlarıyla karşılaşmadan anlatmak oldukça zordur. Bununla karşılaştırıldığında, sort(v.begin(), v.end())'in ne yaptığını anlatmak çok kolay: "Bu durumda 'sort(v)' kullanmak daha kolay olurdu ama bazen bir kabın yalnızca bir aralığındaki öğeleri sıralamak istediğimiz için, daha genel olarak, sıralanacak aralığın başını ve sonunu belirtiriz."
Programların verimliliklerini karşılaştırmadan önce, bunu anlamlı kılmak için kaç tane öğe kullanılması gerektiğini belirledim. Öğe sayısı 50.000 olduğunda programların ikisi de işlerini yarım saniyenin altında bitirdiler. Onun için programları 500.000 ve 5.000.000 öğeyle çalıştırdım.

 

Kayan noktalı sayıları okumak, sıralamak, ve yazmak

 

Eniyileştirmeden

Eniyileştirerek

 

C++

C

C/C++ oranı

C++

C

C/C++ oranı

500.000 öğe

3.5

6.1

1.74

2.5

5.1

2.04

5.000.000 öğe

38.4

172.6

4.49

27.4

126.6

4.62

 Burada önemli olan değerler, oranlardır: birden büyük değerler C++ programının daha hızlı olduğu anlamına geliyor. Dil, kitaplık, ve programlama biçemi karşılaştırmalarının ne kadar güç olduğu bilinen bir gerçektir. Onun için, bu basit denemeden kesin sonuçlar çıkartmayın. Değerler, üzerinde iş yapılmayan bir bilgisayarda birçok değerin ortalaması alınarak bulundu. Değişik değerler arasındaki sapma %1'den daha azdı. Ayrıca C gibi yazılan programların ISO C'ye sadık olan uyarlamalarını kullandım. Bekleneceği gibi, bu programların hızları C gibi yazılan C++ programlarının hızlarından farklı çıkmadı.
C++ gibi yazılan programların çok az farkla daha hızlı çıkacaklarını bekliyordum. Ama başka gerçeklemeler kullandığım zaman sonuçlarda büyük oynamalar gördüm. Hatta bazı durumlarda, küçük sayıda öğeler kullanıldığında, C gibi yazılan program C++ gibi yazılan programdan daha hızlı çıktı. Ancak, bu örneği kullanarak, üst düzey soyutlamaların ve hatalara kaşı daha iyi korunmanın günümüz teknolojisiyle kabul edilir hızlarda elde edilebileceğini göstermeye çalıştım. Salt araştırma konusu olmayan, yaygın, ve ucuz olarak elde edilebilen bir gerçekleme kullandım. Daha da yüksek hızlara ulaştığını söyleyen gerçeklemeler de var.
Kolaylık elde etmek ve hatalara karşı daha iyi korunmak için; 3, 10, hatta 50 kat fazla ödemeyi kabul eden insanlar bulmak güç değildir. Bunlara ek olarak iki kat, dört kat gibi bir hız kazancı da olağanüstü. Bence bu değerler, bir C++ kitaplık firması için kabul edilir en düşük değerler olmalıdır.
Programların kullandıkları sürenin nerelerde geçirildiğini anlamak için birkaç deneme daha yaptım:

 

500.000 öğe

 

Eniyileştirmeden 

Eniyileştirerek

 

C++

C

C/C++ oranı

C++

C

C/C++ oranı

okuma

2.1

2.8

1.33

2.0

2.8

1.40

üretme 

.6

.3

.5

.4

.3

.75

okuma-sıralama 

3.5

6.1

1.75

2.5

5.1

2.04

üretme-sıralama

2.0

3.5

1.75

.9

2.6

2.89

 Doğal olarak, "okuma" yalnızca okumayı, "okuma ve sıralama" hem okumayı hem de okumanın sıraya dizilmesini gösteriyor. Ayryca, veri girişine ödenen bedeli daha iyi görebilmek için "üretme," okumak yerine sayıları rasgele üretiyor.

 

5.000.000 öğe

 

Eniyileştirmeden 

Eniyileştirerek

 

C++

C

C/C++ oranı

C++

C

C/C++ oranı

okuma

21.5

29.1

1.35

21.3

28.6

1.34

üretme 

7.2

4.1

.57

5.2

3.6

.69

okuma-sıralama 

38.4

172.6

4.49

27.4

126.6

4.62

üretme-sıralama

24.4

147.1

6.03

11.3

100.6

8.90

 Başka örneklerden ve gerçeklemelerden gördüklerime dayanarak C++'yn akım giriş/çıkışının C'nin standart giriş/çıkışından daha yavaş olacağını bekliyordum. Bu programın 'fstream' yerine standart giriş 'cin'i kullanan daha önceki bir uyarlamasında gerçekten de böyle olmuştu. Bunun bir nedeni, standart giriş 'cin'le, standart çıkış 'cout' arasındaki bağın kullandığım gerçeklemede kötü işlemesiydi. Yine de bu değerler, C++ giriş/çıkışının C giriş/çıkışı kadar hızlı olabileceğini gösteriyor.
Programları kayan noktalı sayılar yerine tamsayılar kullanacak şekilde değiştirmek hız oranlarında bir değişiklik yapmadı. Yine de, bu değişikliğin C++ gibi yazılan programda C gibi yazılandan çok daha kolay olduğunu görmek güzeldi: 2 değişikliğe karşılık 12 değişiklik. Bu, program bakımı açısından çok çok iyi.
"üretme" denemelerinde görülen fark, bellek ayırma bedellerindeki farkları yansıtıyor. 'vector' ve 'push_back()'in hızının, bir dizi ile birlikte kullanılan 'malloc()' ve 'free()'nin hızıyla aynı olması beklenirdi; ama değil. Bu, boş işlevlere yapılan çağrılar, eniyileştirme sırasında atlanmadıkları için olmalı. Neyse ki bellek ayırmanın bedeli, bu bedeli doğuran girişin bedelinin yanında yok sayılacak kadar küçük.
Beklendiği gibi, 'sort()' 'qsort()'tan oldukça hızlı çıktı. Bunun ana nedeni, 'qsort()'un sıralamayı yaparken bir işlev çağırmasına karşın, 'sort()'un karşılaşıtırmayı kendi içinde yapmasıdır.
Verimlilik konularını gösterecek örnekler seçmek zor. Bir çalışma arkadaşım, sayı okuma ve sıralamanın doğal olmadığı yönünde bir yorum yaptı. Ona göre, okumayı ve sıralamayı dizgilerle yapmalıydım.Bunun üzerine aşağıdaki programı denedim:

#include
#include
#include
#include

using namespace std;

int main(int argc, char* argv[])
{
char* gkutuk = argv[2]; // giris kutugu adi
char* ckutuk = argv[3]; // çikis kutugu adi

vector arabellek;
fstream giris(gkutuk, ios::in);
string dizgi;
while(getline(giris, dizgi)) arabellek.push_back(dizgi); // giristen arabellege ekle

sort(arabellek.begin(), arabellek.end());

fstream cikis(ckutuk, ios::out);
copy(arabellek.begin(), arabellek.end(), ostream_iterator(cikis, "\n")); // cikisa kopyala
}

 Bunu C'ye çevirdim ve karakter girişini deneme yanılmayla hızlandırdım. C++ gibi yazılan program, dizgilerin kopyalanmasını engellemek için elle eniyileştirilmiş C programyıla karşılaştırıldığında yine de fena değildi. Az sayıda veri için aralarında belirgin bir fark yok; çok sayıda veri için ise 'sort()', yine karşılaştırmaları kendi içinde yaptığı için burada da 'qsort()'tan daha hızlı.

 

Dizgi okuma, sıralama, ve yazma

 

C++

C

C/C++ oranı

C (dizgi kopyalamadan)

Eniyileştirilmiş C/C++ oranı

500.000 öğe

8.4

9.5

1.13

8.3

.99

2.000.000 öğe

37.4

81.3

2.17

76.1

2.03

 Bilgisayarımda beş milyon öğeyi sayfalamaya geçmeden barındıracak kadar bellek olmadığı için iki milyon öğe kullandım.
Nerede ne kadar süre geçtiğini anlamak için programı bir de 'sort()'u çıkartarak çalıştırdım.

 

Dizgi okuma ve yazma

 

C++

C

C/C++ oranı

C (dizgi kopyalamadan)

Eniyileştirilmiş C/C++ oranı

500.000 öğe

2.5

3.0

1.20

2.0

.80

2.000.000 öğe

9.8

12.6

1.29

8.9

.91

 Kullandığım dizgiler kısa sayılırdı: ortalama yedi karakter.
'string'in standart kitaplıkta bulunmasına rağmen aslında ek bir tür olduğuna dikkat edin. 'string' kullanarak yapabildiğimiz bu verimli ve güzel şeyleri başka ek türlerle de yapabiliriz.
Verimliliği neden programlama biçemi ve öğretimi bağlamında tartışıyorum? Öğrettiğimiz biçemler ve teknikler gerçek programlarda da uygulanabilmelidir. Büyük ölçekli ve belirli verimlilik ölçütleri olan sistemler de C++'ın hedeflediği sistemlerin arasındadır. Bundan dolayı, C++'ın insanları yalnızca basit programlarda kullanılabilecek biçemler ve teknikler kullanmaya yöneltecek şekilde öğretilmesini kabul edemiyorum. Bu, onları başarısızlığa ve öğrendiklerinden vazgeçmeye götürür. Yukarıdaki ölçümler, genel programlamaya ve somut türlere dayanarak basit ve tür güvenliği içeren C++ programları üretme biçeminin, geleneksel C biçemlerine göre daha verimli olduğunu gösteriyor. Nesneye dayalı programlama biçemleriyle de benzer sonuçlar elde edilmiştir.
Değişik standart kitaplık gerçeklemeleri arasında büyük hız farklarının olması oldukça önemli bir sorun. Standart kitaplığa veya yaygın olarak kullanılan başka kitaplıklara dayalı olarak program yapan bir programcı için, bir sistemde yüksek hızlar getiren programlama biçemlerinin, başka sistemlerde de hiç olmazsa kabul edilir düzeyde hızlar getirmesi önem taşır. C++ biçeminde yazılan programlarımın, C biçeminde yazılan eşdeğerlerinden bazı sistemlerde iki kere daha hızlı çalışmalarına rağmen, başka sistemlerde onların yarısı hızında çalıştıklarını görmek beni çok şaşırttı. Programcılar, sistemler arasında dört gibi yüksek bir hız katsayısını kabul etmek zorunda kalmamalıdırlar. Bu farklılığı getirecek görebildiğim hiçbir temel neden olmadığı için, kitaplık gerçekleyenlerin fazla uğraşa girmeden bu tutarlılığı sağlayabileceklerine inanıyorum. Standart C++'ın hem algılanan hem de gerçek hızını geliştirmenin en kolay yolu, belki de eniyileştirilmiş kitaplıklar kullanmaktır. Derleyici gerçekleyenler, başka derleyicilere karşı küçük hız kazançları sağlamak için yoğun bir çaba içindeler. Ben, standart kitaplık gerçeklemelerindeki gelişme kapsamının daha büyük olduğuna inanıyorum.
Yukarıdaki C++ çözümünün C çözümünden daha kolay oluşunun nedeni, standart C++ kitaplığını kullanmasıdır. Peki bu, karşılaştırmayı geçersiz veya haksız yapar mı? Sanmıyorum. C++'ın en önemli özelliklerinden birisi, düzenli ve verimli kitaplıkları desteklemesidir. Buradaki basit örneklerle gösterilen üstünlükler, düzenli ve verimli kitaplıkların olduğu veya yazılabileceği her uygulama alanında da geçerlidir. C++ topluluğunun karşısındaki güçlük, bu yararları sıradan programcıların kullanabilecekleri başka alanlara yaymaktır. Yani, başka birçok uygulama alanına yönelik düzenli ve verimli kitaplıklar tasarlamalı, gerçekleştirmeli, ve yaygınlaştırmalıyız.

 

C++ 'I ÖĞRENMEK

Bir programlama dilinin tümünü birden öğrenip sonra da kullanmaya çalışmak profesyonel programcılar için bile çok zordur. Programlama dilleri, getirdikleri olanaklar küçük örneklerle denenerek parça parça öğrenilir. Onun için, bir dili her zaman için bir dizi altkümesinde ustalaşarak öğreniriz. Doğru soru, "Önce bir altkümesini mi öğrenmeliyim?"den çok, "Önce hangi altkümesini öğrenmeliyim?"dir.
"C++'ın önce hangi altkümesini öğrenmeliyim?" sorusunun geleneksel bir yanıtı, "C++'ın C altkümesini"dir. Benim kanımca, bu iyi bir seçim değil. Önce C'ye yönelmek, beraberinde alt düzey ayrıntılara fazla erkenden odaklanmayı getirir. Ayrıca programlama biçem ve tasarım konularını da öğrenciyi bir sürü teknik güçlükle yüz yüze bıraktığı için bulandırır. İkinci ve üçüncü bölümlerdeki örnekler bu noktayı açıklıyor. C++'ın kitaplık desteğinin, gösteriminin, ve tür denetiminin daha iyi olması, önce C'ye yönelmememiz gerektiği sonucunu doğurur. Ancak, benim önerimin "önce saf nesneye dayalı programlama" olmadığına da dikkat edin. Bence bu da başka bir uç nokta olur.
Bir dili öğrenme şekli, programlamaya yeni başlayanlara etkin programlama tekniklerini de öğretecek şekilde olmalıdır. C++'a yeni başlayan deneyimli programcılar için ise, etkin programlama tekniklerinin C++'ta nasıl kullanıldıklarına ve programcının ilk defa gördüğü tekniklerin anlatılmalarına odaklanmalıdır. Deneyimli programcıların karşılaştıkları en büyük engel, başka bir dilde etkin olarak kullandıklarını C++'ta dile getirmeye çalışmalarıdır. Hem yeni başlayanlar hem de deneyimliler için üzerinde durulacaklar, kavramlar ve teknikler olmalıdır. C++'ın desteklediği programlama tasarım ve tekniklerini anlamada, C++'ın sözdizimi ve anlamsal ayrıntıları ikinci derecede önemlidir.
Öğretmenin en iyi yolu, iyi seçilmiş somut örneklerden başlayıp daha genel ve daha soyut örneklere geçmektir. Bu hem çocukların öğrenme şekli, hem de bizim yeni düşünceleri kavrama şeklimizdir. Dilin olanakları her zaman için kullanıldıkları kapsamda sunulmalıdır. Yoksa programcının ilgisi, sistem üretmek yerine anlaşılması güç teknik ayrıntılara yönelir. Dilin teknik ayrıntılarıyla ilgilenmek eğlencelidir ama etkin bir öğretim biçimi değildir.
Öte yandan, programlamayı salt çözümleme ve tasarıma yardımcı olarak görmek de işe yaramaz. Kod üzerine yapılacak görüşmeleri üst düzey konuların sunulmasından sonraya bırakma hatasının bedeli, defalarca çok pahalıya ödenmiştir. Bu yaklaşım, insanları programlamadan uzaklaştırmaya ve üretim düzeyi niteliklerinde kod yazmanın getirdiği güçlükleri küçümsemeye yöneltmektedir.
"Önce tasarım" yaklaşımının tam karşıtı da, bir C++ gerçeklemesini alıp hemen kodlamaya geçmektir. Bir sorunla karşılaşıldığında tıklayarak yardım ekranlarında neler bulunacağına bakılır. Buradaki yaklaşımdaki sorun, özelliklerin ve olanakların, birbirlerinden ayrı olarak anlaşılmalarına dayalı olmasıdır. Genel kavramlar ve teknikler bu şekilde öğrenilemezler. Bu yaklaşımın getirdiği ek bir sorun, C++ sözdizimi ve kitaplıkları kullansalar bile, deneyimli programcıları daha önceden bildikleri bir dilde düşünmeye yönlendirmesidir. Sonuçta yeni başlayanların kodu, program örneklerinden kopyalanmış satırların bir sürü 'if-else' arasına serpiştirilmesinden oluşmaktadır. Yeni başlayanlar kopyalanan satırlardaki kodun amacını ve nasıl işe yaradığını çoğu zaman anlayamazlar. Kişi ne kadar akıllı olursa olsun durum değişmez. Bu "kurcalama yöntemi" aslında iyi bir öğretim ve iyi bir kitapla birlikte olduğunda çok yararlıdır ama tek başına kullanıldığında felakete davettir.
Ben özetle şöyle bir yöntem öneriyorum;

somuttan soyuta yönelmeli
dilin özelliklerini, destekledikleri programlama ve tasarım teknikleri kapsamında sunmalı
kodu, kuruldukları alt düzey ayrıntılara girmeden üst düzey kitaplıklara dayalı olarak sunmalı
gerçek programlara taşınamayacak tekniklerden kaçınmalı
ayrıntılara girmeden önce, benimsenmiş ve kullanışlı teknikler sunmalı; ve
dilin özelliklerinden çok, kavramlara ve tekniklere odaklanmalı.


Hayır, bu yöntemin yeni veya değişik olduğunu düşünmüyorum. Herkesin akla yakın bulacağını düşünüyorum. Ne yazık ki bu akla yakınlık; C'nin C++'tan önce öğrenilmesinin doğru olup olmadığı, nesneye dayalı programlamanın tam olarak anlaşılması için Smalltalk'un gerekip gerekmediği, programlamanın saf nesneye dayalı olarak mı (her ne demekse) öğretilmesinin iyi olduğu, ve kod yazmaya geçmeden önce yazılım geliştirme sürecinin iyice anlaşılmasının ne kadar önemli olduğu gibi tartışmalar arasında yok olup gitmektedir.
Neyse ki benim koyduğum ölçütler doğrultusunda biraz deneyimimiz var. Benim en sevdiğim yöntem; dilin değişkenler, bildiriler, döngüler gibi temel kavramlarını iyi bir kitaplık şeklinde öğretmektir. Öğrencilerin ilgilerini C dizgileri gibi karmaşıklıklar yerine programlamaya yönlendirmek için kitaplıklar gerekir. Ben standart C++ kitaplıklarını veya bir altkümelerini öneririm. Bu yöntem, Amerikan liselerinde 'bilgisayar bölümlerine hazırlama' derslerinde de kullanılmaktadır [Horwitz, 1999]. O yöntemin deneyimli programcılara yönelen daha geliştirilmiş bir şekli de başarıyla uygulanmıştır [Koenig, 1998].
Bu yöntemlerin bir zayıflığı, görsel programlamaya hemen girmemeleridir. Bunu karşılamanın bir yolu, arabirimi kolay olan görsel bir kitaplığı tanıtmaktır. Bu arabirim, öğrencilere C++ dersinin ikinci gününde verilebilecek kadar kolay olmalıdır. Ne yazık ki bu şartı sağlayan yaygın bir C++ görsel kitaplığı yok.
Baştaki bu kitaplıklara dayalı öğretimden sonra, öğrencilerin ilgileri doğrultusunda çok değişik konulara geçilebilir. Bir noktada, C++'ın düzensiz ve alt düzey bazı özelliklerine de değinmek gerekecektir. İşaretçi, tür dönüşümü, ve bellek ayırma gibi özellikleri anlatmanın bir yolu, temelleri öğretirken kullanılan sınıfların nasıl gerçekleştirildiklerini incelemektir. Örneğin 'string', 'vector', 'list' gibi sınıflar, C++'ın ilk derslerde gözardı edilen C altkümesini anlatmak için çok uygundur.
'vector' ve 'string' gibi değişken sayıda öğe barındıran sınıfları gerçeklerken, bellek yönetimi ve işaretçiler kullanılması gerekir. Sınıf gerçekleme tanıtılırken, önce gerçeklenmelerinde bu kavramların kullanılmalarına gerek olmayan 'Tarih', 'Nokta', ve 'SanalSayi' gibi sınıflar tanıtılabilir.
Ben soyut sınyfları ve sınıf hiyerarşilerini tanıtmayı genelde kapların ve kap gerçeklemenin anlatılmasından sonraya bırakıyorum ama bu konuda başka seçenekler de var. Konuların verildiği sıra, kullanılan kitaplıklara göre değişir. Örneğin sınıf hiyerarşilerine dayalı görsel kitaplıklar kullanan bir kurs, çok şekilliliği ve sınıf türetmeyi daha önce işlemelidir.
Son olarak, lütfen C++ dilini ve onun tasarım ve programlama tekniklerini anlatmanın birden fazla yolu olduğunu unutmayın. Öğrencilerin olduğu kadar öğretmenlerin ve ders kitapları yazarlarının da hedefleri ve çıkış noktaları farklıdır.

ÖZET

Programlarımızın kolay yazılır, doğru, bakımı kolay, ve belli sınırlar içerisinde verimli olmalarını isteriz. Bunu başarabilmek için, programlarımızı C'de ve eski C++'ta kullanılanlardan daha üst düzey soyutlamalar kullanarak tasarlamalyız. Bu amaca, alt düzey biçemlerle karşılaştırıldığında verimlilik kaybı olmadan, kitaplıklar kullanarak ulaşabiliriz. Yani, standart C++ kitaplığı gibi kitaplıklarla tutarlı yeni kitaplıklar geliştirmenin ve bunları yaygınlaştırmanın C++ kullanıcıları için yararı büyüktür.
Eğitim, daha düzgün ve üst düzey programlama biçemlerine geçişte büyük rol oynar. Yersiz verimlilik kaygılarıyla alt düzey kitaplık olanaklarını kullanan yeni bir programcı kuşağının C++ kullanıcıları arasına girmesine gerek yoktur. Yeni başlayanlar kadar deneyimli olan programcılar da Standart C++'ı yeni ve üst düzey bir dil olarak öğrenmeliler ve alt düzey soyutlamalara ancak gerçekten gerek olduğunda inmelidirler. Standart C++'ı daha üstün ve sınıflar eklenmiş bir C gibi kullanmak, onun sunduğu olanakları harcamak anlamına gelir.

DEĞİŞKEN TANIMLAMA VE KULLANMA

Programlarımızda işlemlerimizi yaparken verileri kullanırız. Mesela herhangi iki sayıyı toplarız veya iki tane karakter dizisini (string) karşılaştırırız. Bu işlemler için kullandığımız verilerimizi değişkenler içinde tutarız. Değişkenler bilgisayar hafızasında verileri depolayan ve isimleri olan programlamının en temel elementleridir.
Değişkenlerin isimlerinin olmasını gerektiğini söyledik. Bir değişkeni kullanmadan önce onu tanımlamalıyız. Tanımlamayı değişkene uygun bir isim verme ve değişkenin hangi tipten olduğunu bildirmeyle yaparız.
Önce isterseniz değişleri C++ dili kuralların uygun bir biçimde nasıl isimlendireceğimizi görelim. Değişken isimlerini verirken C++'ın bir takım sıkı kurallarına uymamız gerekir. Bu kurallar:
Değişkenlerin isimleri alfabede bulunan karakterlerle başlamalı. Ama ilk harf hariç diğer karakterler sayı olabilir. C++ büyük ve küçük harf duyarlıdır. Yani Sayi, sayi ve SAYI hepsi ayrı değişken olarak algınalırlar. Değişken isimleri birden fazla kelime olduğu zaman; kelimelerin arasına boşluk konmaz. Bu tür değişkenleri ya kelimeleri birleştirerek veya kelimeler arasına _ (alt çizgi) karakteri koyararak isimlendiririz. Değişkenlerin isimleri !, ?, {, ] gibi karakterler içeremezler. C++'ın anahtar kelimelerini de değişken isimleri olarak kullanamayız. sayi, tamsayi1, toplam, Fark, KullaniciAdi, isim, _Adres, sinif_ortalaması, kurallar göre adlandırılmış değişkenlerdir. Diğer taraftan 1.sayi, tamsayi 1, fark!, 3.sinif_ortalamasi geçersiz değişken isimleridir. Böyle yanlış adlandırılmış değişkenleri içeren programlar derlenmez!
Anahtar kelimeler C++ dilinde bulunan komutların isimleridir. Bunları direk olarak değişken ismi olarak kullanamayız. Ayrıca alt çizgi ile başlayan değişken tanımlamadan kaçınmalıyız. Çünkü genelde C++ kütüphanelerini yazan programcılar değişkenlerini alt çizgi ile başlayan isimler verirler. Bu da isimler arasında çakışma yaratabilir. Değişkenleri isimlendirmeyi öğrendikten sonra sonra sıra C++ dilindeki temel veri türlerini öğrenmeye geldi.
Verileri bilgisayarda program çalışırken bellekte(RAM) depolanır. Bilgisayar belleği bitlerden oluşmuştur. Bir bit temel olarak 1 veya 0 değerini alır. Sekiz tane bit bir byte eder. Bilgisayarın hafızasında verilerin kapladıkları alanlar byte türünden ifade ederiz (bir çok sistemde bu böyledir). C++ verileri ihtiyacımıza göre değişik tiplerde tanımlarız kullanırız.
C++ dilinde hazır bulunan temel veri tipleri şunlardır:

 

Değişken

Boy

Açıklaması

Değer Aralığı

char

1

karakter veya 8 bit uzunluğunda tamsayı

signed: -128 ile 127 arasında
unsigned: 0 ile 255

short

2

16 bit uzunluğunda tamsayı

signed: -32768 ile +32767 arasında
unsigned: 0 ile 65535 arasında

long

4

32 bit uzunluğunda tamsayı

signed: -2147483648 ile +2177483647 arasında
unsigned: 0 ile 65535 arasında

int

 

Tamsayı tipidir. DOS'ta ve Win3.1'de 16 bit uzunluğunda ama Windows9x, WinNT, Win200 ve WinXP 32 bit.

short ve long türlerine bakınız.

float

4

Kesirli sayı.

3.4e +/- 38 (7 basamak)

double

8

Geniş ve fazla duyarlıklı kersirli sayı.

1.7e +/- 308 (15 basamak)

long double

10

double tipinin daha genişidir.

1.2e +/- 4932 (19 basamak)

bool

1

true(doğru) veya false(yanlış) değerini alır. Eski derleyiciler bu türü desteklemeyebilir. Yeni ANSI C++ standardında eklenmiştir.

doğru veya yanlış.

wchar_t

2

char tipinden geniş olur Unicode tipinde değişkenleri destekler.

geniş karakterler (unicode)

 Yalnız platform ve işletim sistemine göre değişkenlerin boyutları yukarıdakilerden farklı olabilir. Ama ANSI C++ standart derleyicilerinin hepsi yukarıdaki veri tiplerini desteklerler. Yukarıda dikkate ederseniz değişkenlerin çoğunun unsgined ve signed versiyonları var. Bunlardan signed olanları hem pozitif hem de negatif değerler alırken; unsigned versiyonlar ise sadece pozitif değerler alırlar.
Değişkenleri isimlendirdik ve onların tiplerini öğrendik. Şimdi değişkenleri bildirmeyi ve onları kullanmayı öğrenelim. Genel olarak temel veri tiplerinden olan değişkenleri şu şekilde tanımlarız:

<veri_tipi> <deðiþken_isimi> ;

Yukarıdaki kurala uygun olarak aşağıda bununla ilgili örnekler vardır:

int sayi;
unsgined int a; char karakter;
float sayi_2;
bool dogru_yanlis;
unsigned long uzunTamsayi;


Yukarıdaki değişken tanımlamalarının hepsi kurallara uygundur. İstersek birden fazla değişkeni bir satırda tanımlama olanağımız vardır:

int sayi1, sayi2, sayi 3;
char karakter, baskabir_karakter;


Örnekte int tipinden üç değişkeni tek bir satırda tanımlamayı ve aynı şekilde char tipinden iki değişkeni tek bir satırda tanımlıyoruz. Burda dikkat edilmesi gereken nokta değişkenlerin arasına virgül koymamız gerektiğidir.
Değişkenlere değer atama işlemi için eşittir (=) operatörünü kullanırız. Mesela aşağıdaki kod parçasında önce x değişkenini sonra da y değişkenini tamsayı (int) tipinde bildirdik. Sonra programın herhangi bir yerinde x'in içeriğini 25 yaptık. Bunun hemen ardından y'nin değerini 14 yaptık. En son kısımda x'in değerini y'de depoladık.

int x;
int y;
......
x=25;
y=14;
....
y=x;


Değişkenlerin değerlerini ilk tanımladığımız anda da atayabiliriz. Aşağıda bununla ilgili örnekler verelim:

double t=3.25;
bool dogru_mu=false;
long int s1=12345, s2=-694312978425;
double t=3.25;

Uygulama Örneği:

// Iki tamsayi alan ve toplamini bulan program
#include <iostream.h>
int main()
{
int sayi1;
int sayi2;
int toplam;
cout << "\n Lutfen birinci tamsayiyi giriniz: ";
cin >> sayi1;
cout <<"\n Lutfen ikinci tamsayiyi giriniz: ";
cin >> sayi2;
toplam = sayi1 + sayi2;
cout << "\n " << sayi1 << " + " << sayi2 << " = " << toplam << endl;
return 0;
}

Son olarak yukarıdaki programı yazalım. Programda int tipinden sayi1, sayi2 ve toplam değişkenlerimizi tanımladık. Sırası ile kullanıcıdan bu değişkenlerin değerlerini aldık ve sonucu ekrana yazdırdık. Program basit gibi görünebilir ama mutlaka yazın, derleyin ve çalıştırın.

 


C++ İLE İLK PROGRAMIMIZ


// Bu bizim ilk C++ programimizdir.
// Ekrana "Merhaba Dunya" yazdiriyoruz:
# include <iostream.h>

int main()
{
cout << "Merhaba Dunya !";

return 0; // Programimizin basari ile tamamlandigini ifade eder.
}

İsterseniz yukarıdaki porgramın kodunu satır satır açıklayalım. Böylece her satırda bulunan ifadelerin anlamını daha iyi anlamış oluruz. İlk iki satır // ile başlıyor. Bu şekilde başlayan satırlara kod hakkında yorum ya da açıklama yaparız. Yapılan açıklamalar siz veya başka birisi programı okurken daha rahat anlamasını ve ileride büyük programlarda hata ayıklama ya da yeni özellikler eklerken kodun kolayca anlaşılmasını sağlar. İstediğiniz kadar açıklama/yorum satırını programım koduna ekleyebiliriz. Bu satırlar derleyiciler tarafından derleme işlemi sırasında dikkate alınmazlar ve programın perfromansına hiçbir etkileri de yoktur.

#include <iostream.h> satırı ise C++ derleyicimizin ön işlemcisine dilimizin kütüphanesinde bulunan iostream.h kitaplığını programımızda kullanacağımızı ifade eder. (C++ ön işlemcileri konusunu ileride daha ayrıntılı olarak inceleyeceğiz.)
Daha sonraki satır her C++ programında mutlaka bulunması gereken bir satırdır. Her C++ programında main() fonksiyonu olmak zorundadır; bu fonksiyonumuzun önünde ise o fonksiyonun döndürdüğü değişkenin veri tipi olmalıdır. Tabi ki C++ fonksiyonlar ve onların döndürdükleri değerler konusunu da ileride işleyeceğiz.

C++ fonksiyonlar ve kod blokları { } parantezleri arasında bulunmalıdır. mainde bir fonksiyon ise onun içindeki kodlar doğal olarak { } parantezleri arasındadır.

Programımızı derleyip, çalıştırdığımızda çıkan sonucun kodunun olduğu satır : cout << " Merhaba Dunya ! "; satırıdır. Bu satırda, iostream.h kitaplığında bulunan cout fonksiyonu sayesinde ekrana bir şeyler yazdırıyoruz. C++ dilinde her satır ifadenin sonuna ; koymak zorundayız. Bu duruma aykırı olan satırlar #include ile başlayanlar, ve fonksiyonlar başlangıç satırlarıdır. Bir kaç tane daha satır tipi de ; ile bitmez ama onları sonra göreceğiz. Aslında programımızı birkaç satırda da yazabilirdik. Sadece farklı ifadelerin sonuna ; koyarak. Mesela : # include <iostream.h> int main() { "Merhaba Dunya !"; return 0; } gibi..

return 0; ile programımızın (aynı zamanda main fonksiyonumuzun) çıkış noktasıdır. Eğer return ile 0 değeri döndürürsek programımızın güvenle çıktığını işletim sistemine bildirmiş oluruz.

ŞABLON FONKSİYONLAR YAZMAK


C++ programlama dili, C'den aldığı çok hoş sözdimi (elegant syntax) ve alt seviyelerde ileri derecede esnek programlar yazmaya uygun olması ile gerçekten birçok bilgisayar programcısının favorisi olmuştur. Bütün bunların yanında büyük çapta yazılım geliştirirken gerçek dünyayı iyi bir şekilde modelleyen Nesne Yönemlimli Programlama özelliklerini de programcıya sunması onu gerçekten bir numara yapmıştır diyebiliriz.

Bu yazımızda C++ dilinin esnek programlamayı destekleyen bir özelliğinin, fonksiyon şablonlarının (function templates) üzerinde duracağız. Diyelimki bir programın içinde hem tamsayıları, hem de kesirli sayıları toplayan fonksiyonlara ihtiyacımız var. Bu durumda bir C programcısı muhtemelen tamsayi_topla(int sayi_1, int sayi_2) ve kesirlisayi_topla(double sayi_1,double sayi_2) şeklinde iki farklı fonksiyon yazardı. Aynı durumda bir C++ programcısı topla() isimli fonsiyonlara aşırı yükleme (method overloading) ile topla(int sayi1, int sayi2) ve topla(double sayi1,double sayi2) gibi aynı isimli iki tane fonksiyon yazar. İkinci durumda programcı yine 2 fonksiyon yazar ama burda sadece bu fonksiyonların ait olduğu sınıfın bir örneğini (instance) kullanan programcı rahat eder çünkü iki farklı fonksiyon ismi bilmek yerine sadece bir fonksiyon ismi bilir ve bunların aldıklar parametrelerin faklılıklarını bilir ve ona göre kullanır.

Yukarıdakilerin yanında aynı işi yapan ve farkları aldıkları ve/veya dönderdikleri değerlerin tipleri farklı olan n tane farklı fonksiyonu ayrı ayrı yazmak yerine bunlar için şablon fonksiyon şeklinde sadece bir metod yazıp bu fonksiyonları ihtiyacımıza göre çağırmak daha kolay olur. Hem böylelikle modern programlamadaki code-reuse (kodun tekrar kullanılması) ilkesini sonuna kadar kullanmış oluruz.

Şablon fonksiyon yazmak için öncelikle template< class Tip > böyle bir satırı fonksiyonumuzdan önce yazarız. Burdaki tip fonksiyomuzun çalışacağı veri tipidir ki bu temel veri tipi veya bir sınıf tipi de olabilir. Sonrai satır da ise Tip topla(Tip sayi1 , Tip sayi2 ) önce, fonksiyonun döndereceği veri tipini (bu void veya standart birşey de olabilir.), fonksiyon adını ve parametreleri yazarız. Parametrelerin bir veya birkaçı da temel bir veri tipi veya Tip'ten farklı bir sınıf tipi veya struct olablir. Sonra ise normal fonksiyon yazımı ile aynıdır.

Aşağıdaki programda topla() isimli şablon bir fonksiyonumuz var. Fonksiyon aldığı iki değişkeni toplayıp, toplamı geriye dönderiyor. Fonksiyonu denemek için iki tane tamsayı, kesirli sayı ve karakteri toplayıp sonuçlarını ekrana yazan kodları main() fonksiyonu içinde yazıyoruz. Tabi enson dummy değişkenini enson neden aldığmızı da tahmin ederseniz sanırım.

#include <iostream.h>
template< class Tip >
Tip topla(Tip sayi1 , Tip sayi2 )
{
return (sayi1+sayi2);
}
int main()
{
int tamSayi1=5, tamSayi2=10;
double kesirliSayi1=22.33, kesirliSayi2=55.26;
char karakter1='A', karakter2='B';
char dummy;
cout << "Iki tamsayý : "<< tamSayi1 << " ve " << tamSayi2;
cout << " toplayýnca = " << topla(tamSayi1, tamSayi2)<< endl <<endl;
cout << "Iki double : "<< kesirliSayi1 << " ve " << kesirliSayi2;
cout << " toplayýnca = " << topla(kesirliSayi1, kesirliSayi2) << endl<<endl;
cout << "Iki karakteri : "<< karakter1 << " ve " << karakter2;
cout << " toplayýnca = " << topla(karakter1, karakter2)<< endl <<endl;
cin >> dummy;
return 0;
}

 VERİ DÖNÜŞÜM FONKSİYONLARI


Stdlib.h kütüphanesinde bulunan veri dönüşüm fonksiyonları şunlardır;

 

Dönen tip

Fonksiyon Adi

Argumanlar

double

atof

(const char*str)

int

atoi

(const char*str)

long

atol

(const char*str)

char*

ecvt

(double num, int n,int*dec,int*sign)

char*

fcvt

(double num, int n,int*dec,int*sign)

char*

gcvt

(double num, int n,char*buf)

char*

itoa

(int num,char*str,int radix)

char*

ltoa

(long num,char*str,int radix)

double

strtod

(const char*str ,char**endptr)

long

strtol

(const char*str ,char**endptr,int radix)

unsigned long

strtoul

(const char*str ,char**endptr,int radix)

char*

ultoa

(unsigned long num char*str ,int radix)

 Şimdi örnek olması açısından fcvt fonksiyonunun kullanımına örnek verelim . fcvt fonksiyonu float olan sayıyı karakter katarına dönüştürmekte kullanılır. Aşağıda bunun kullanımına bir örnek görmektesiniz.

#include <stdlib.h>
#include <iostream.h>

void main(void)
{
char *ConvertedFloattoString;

float ANegativeValue = -2.121,
APositiveValue = 3.14159,
AScientificValue = 1.0239E4;

int float_sign, decimal, precision = 6;

//degiskenleri ilk degerlerini de vererek tanimliyoruz.
//Stdlib.h library' de belirtildiði sekilde
//fcvt(float olan sayiyi karakter katarina donusturen fonksiyon) fonksiyonunu kullaniyoruz.
//char* fcvt (double num, int n,int*dec,int*sign) sekline gore kullaniyoruz.


ConvertedFloattoString = fcvt(ANegativeValue,
precision,
&decimal,
&float_sign);

cout <<"\n\n Float sayinin gercek degeri:"
<<ANegativeValue
<<"\n Float sayýyý stringe degistir:"
<<ConvertedFloattoString
<<"\n Ondalýk deger : "
<<decimal
<<"\n Float sayinin isaret(sign) degeri:"
<<((float_sign?"-":"+"));

ConvertedFloattoString = fcvt(APositiveValue,
precision,
&decimal,
&float_sign);

cout <<"\n\n Float sayinin gercek degeri:"
<<APositiveValue
<<"\n Float sayýyý stringe degistir:"
<<ConvertedFloattoString
<<"\n Ondalýk deger :"
<<decimal
<<"\n Float sayinin isaret(sign) degeri:"
<<((float_sign?"-":"+"));

ConvertedFloattoString = fcvt(AScientificValue,
precision,
&decimal,
&float_sign);
cout <<"\n\n Float sayinin gercek degeri:"
<<AScientificValue
<<"\n Float sayýyý stringe degistir:"
<<ConvertedFloattoString
<<"\n Ondalýk deger : "
<<decimal
<<"\n Float sayinin isaret(sign) degeri:"
<<((float_sign?"-":"+"));
}

 Tabi stdlib.h kütüphanesi 'nde sadece veri dönüşümleri değil aynı zamanda arama ve sıralama gibi fonksiyonlar da bulunur.

 GÖSTERİCİLER (POINTER)


Göstericiler C ve C++ dillerinin en zor konusu olarak ün salmışlardır. Ama konu üzerinde biraz çalışırsak ve göstericileri kullanırken dikkatli olursak gerçekten de programlarımızın hızını oldukça artıran araçlar olarak karşımıza çıkarlar.

Normalde bir değişken tanımladığımızda aslında sadece o değişkene hafızada yer ayırmış oluruz. Bu değişken ismiyle değişkenimizin hafızadaki yerine ulaşabiliriz. Değişken ismiyle değişkene ulaşmaya direkt referans (directly referance) denir. Göstericiler ise bir değişkenin hafızadaki yerini saklarlar. Bu şekilde göstericinin işaret ettiği değişkene de ulaşabiliriz. Buna dolaylı referans (indirectly reference) denir.

 Göstericileri tanımlamak ile diğer değişkenleri tanımlamak arasında küçük bir fark vardır. Göstericileri tanımlarken değişken isminden önce * işareti konur:

int *sayiPtr, sayi;

Yukarıda tamsayı tipinde bir gösterici bir de normal değişken tanımladık. Aynı satırda birden fazla gösterici tanımlarken herbirinin önüne ayrı ayrı * işareti koymamız gerekir. Aksi halde sadece ilk değişkenimiz gösterici olur. Birden fazla göstericiyi aynı satırda şöyle tanımlarız:

char *aPtr, *bPtri;

C++'da göstericiler için iki tane işleç(operator) kullanılır. Bunlardan birincisi: & adres işlecidir. Adres işleciyle gösterici ile aynı tipteki bir değişkenin adresine ulaşabiliriz.

int sayi=9;
int *sPtr;
sPtr=&sayi;


Yukarıdaki kodun ilk satırında bir tamsayı değişkeni tanımladık ve ona 9 değerini atadık. İkincisinde tamsayı tipinde bir adres tutmak için sPtr göstericimizi tanımladık. Son satırda ise sayi değikenimizin adresini sPtr değişkenimize yükledik. Artık sPtr, sayi değişkenini gösteriyor deriz.

sayi değişkenimizin bilgisayarın hafızasında 1800 adresli yerde saklandığını düşünelim. sPtr göstericisinin ise hafızadaki yeri 2300 olsun. Yukarıdaki kodun son satırı çalıştıktan sonra sPtr'nin içerisindeki değer 1800 olur.

 Diğer gösterici işlecimiz *'dir ve dolaylı referans işleci olarak bilinir. Bu işleç, kendisinden sonra gelen göstericinin gösterdiği değişkenin değerini döndürür. Aşağıdaki kod parçasını incelersek:

cout << *sPtr << endl;

bu kod ekrana sayi değişkenimizin değeri olan 9'u yazdırır. Çünkü, sPtr göstericisi sayi değişkenini işaret ediyor ve *sPtr ifadesi ile sPtr göstericisinin işaret ettiği değişkene ulaşıyoruz.
Dolaylı referans işlecimiz ile ayrıca, göstericinin gösterdiği değişkenin değerini de değiştirebiliriz :

*sPtr=23;
cout<< *sPtr << endl;
cout<< sayi << endl;


Yukarıdaki kod parçasında önce sPtr göstericisinin gösterdiği değişkenin (yani "sayi" değişkenini) değerini 23 yaptık. Sonraki satırda sPtr göstericisinin gösterdiği değişkenin değerini ekrana yazdırdık. Son olarak sayi değişkenin değerini ekrana yazdırdık. Son iki satırda bulunan kodlar ekrana aynı değerleri yani 23 değeri basacaktır.

GÖSTERİCİLER (POINTER)


Hata yakalama (Exception Handling) başlıbaşına büyük bir konu olmasına rağmen Hata Yakalama ile ilgili temel bilgileri basit örneklerlerle anlatmaya çalışacağım. C dili bize çok az hata yakalama mekanizması sunar. Aşağıdaki kodu inceleyerek hata oluşma durumlarından neyi kastettiğimizi anlayabilirsiniz.

int BirseylerYap()
{
int *a, c;
FILE *dosya;
a = malloc(sizeof(int) * 10);
if (a == NULL)
return 1;
dosya = fopen("cpp.txt", "rb");
if (dosya == NULL) {
free(a);
return 2;
}
fread(a, sizeof(long), 10, b);
if (a[0] != 0x10) {
free(a);
fclose(dosya);
return 3;
}fclose(b);
c = a[1];
free(a);
return c;
}

Bu fonksyionla yapmak istediğimiz, birtakım geri dönüş değerlerine göre hatanın ne olduğunu anlamaktır. Eğer geri dönüş değeri 1 ise alan tahsisatı yapılamadığını, 2 ise cpp.txt dosyasının açılamadığını anlıyoruz. Aslında burada hata ayıklaması gibi özel bir kavram yoktur.Kendimiz if-else bloklarıyla hatayı bulmaya çalışıyoruz. Ama c++ 'ın bunların ötesinde yapabildiği şeyler vardır. C++ dili hata yakalama için özel anahtar sözcükler içerir. Şimdi sırayla bu anahtar sözcükleri anlayabilmek için basit bir c++ programı yazalım. Hata denetlemesi yapabileceğimiz programımız şöyle olsun. Kullanıcıdan iki değer alacağız.Ve ilk alınan değeri ikinci alınan değere böleceğiz. Eğer biraz matematik bilgisine sahipsek kullanıcı ikinci değer olarak sıfır girdiğinde hata olacaktır. Çünkü bir sayının sıfıra bölünmesi matematiksel olarak sonsuzu ifade eder.Bilgisayar programcılığında ise sonsuz diye bir şey yoktur, herşey sonludur.(siz sonsuz döngüler yaptığımıza bakmayın)

Şimdi C++ 'da exception handling nasıl yapılır ona bakalım. C++ 'da hata yakalama mekanizması try,catch ve throw anahtar sözcükleriyle yapılır. try ve catch birer komut bloklarıdır. Hatanın ayıklanmasını istediğimiz bölgeyi try blokları içine almamız gerekir. Hata yakalandığında işletilecek kodlar ise catch blokları içinde olmalıdır. Peki try bloku ile catch bloku arasındaki Şarkı Sözlerinasıl sağlanacak, bunun cevabı ise throw anahtar sözcüğüdür. Hatanın oluşmasına sebeb olacak ifadeden sonra catch bloğuna hatanın türü ile ilgili bilgi göndeririz. Aşağıdaki programda throw ile atılan bir int bilgidir. catch bloğu ise bu bilgiyi alarak bir hata mesajı verir. Unutmayın throw ile atılan mesajdan sonra programımızı eğer exit() gibi bir fonksiyonla bitirmezsek catch bloğundan sonra programın akışı devam edecektir. Bu yüzden eğer programımızla ilgili hayati bir hata yakalarsak catch bloğu içinde exit() ile programı tamamen sonlandırmamız gerekir.

int main(void){
float a,b,c;
try{
cin >> b >> c ;
if (c==0) throw 1
a=b/c;
}
catch(int i)
{
cout << i<< " Hata olustu"
}
return 0;
}

 Gördüğünüz gibi yukarıdaki programda eğer kullanıcı ikinci değer olarak sıfır girerse programımız catch bloğuna gelir ve ekrana "1 Hata oluştu" mesajı yazılır. Elbette exception handling mekanizması bu kadar basit işler için değildir. Asıl amacımız sınıflar ile ilişki kurarak hata ayıklamak.Hatta throw ile kullanmak için her sınıf için ayrı birer hata sınıfları bile oluşturabiliriz. Hata diye bir sınıfımızın olduğunu düşünelim. Şu ifade son derece legal bir durumdur. " throw(Hata err); ". Hatta, Hata sınıfına ait bir varsayılan kurucu(constructor) işlevinin de olduğunu düşünürseniz şöyle bir kod da yazabiliriz. " throw Hata(); ". Catch bloğuna gönderdiğimiz Hata adlı sınıf nesnesini Catch bloğunda ise şöyle yakalarız. "catch(Hata err);" Şimdi bu söylediklerimizi bir örnekle gösterelim. Örneğimizde MetreSantim diye bir sınıfımız olacak. Amacımız bir uzunluk ölçüsünü iki değer olarak tutmak(Metre ve santim). Sınıfımızın iki tane m(metre) ve cm(santim) olacak şekilde iki tane üye değişkeni olacak. Sınıfımızın biri kurucu olmak üzere put ve show gibi 3 tane de üye işlevi olacaktır. Amacımız put() ya da kurucu işlevi ile oluşturulacak nesnelerin santimetre değerini 100 'den küçük olacak şekilde tutmak.(Not: 4 metre 150 santim yerine 5 metre 50 santim demek daha mantıklı bence:)) Tabi bunu yaparken yukarıdaki örnekten daha gelişmiş bir hata ayıklama mekanizması kullanacağız. Bir Hata sınıfımız olacak ve bu hata sınıfı ile cm olarak girilen değeri ve bu değerin hangi fonksiyon tarafından gönderildiğini saklayacağız. Hata sınıfının MetreSantim sınıfına özgü olduğunu vurgulamak için ise iç içe(nested) sınıf tanımlaması yapacağız. Yani Hata sınıfının bildirimini MetreSantim sınıfının içinde yapacağız. Hata sınıfı, hatanın(throw işleminin) hangi fonksiyondan geldiğini tutacak char türden bir dizi ve hataya sebep olan değeri tutan int türden elemanlardan oluşacaktır.


Aşk ve Sevgi

Aşk Nedir
Seni Seviyorum
Çiçeklerin Dili
Evlilik Kurtarma
100 Dilde Sevgi
Aşkın 50 işareti
Sevgi Nedir
Erkek Severse
Platonik Aşk
4 Mevsim Aşk
Aşkın Türleri
Flört
İlk Adım
Aşk Kuralları

Online Oyunlar

Okey
Tavla
Bilardo
Batak
King
Satranç

Şarkı Sözleri

Probably Built In The Fifities - The Gath..
Locked Away - The Gath..
Illuminating - The Gath..
Travel - The Gath..
Marooned - The Gath..
The Big Sleep - The Gath..
Red Is A Slow Colour - The Gath..
Liberty Bell - The Gath..
My Electricity - The Gath..
Rescue Me - The Gath..
Annie - Happy Wi..
Devamı

Kadınca - Bayan

 Var mı bekarlık gibisi?
 Düğüne çeyrek var
 Erkek halleri...
 Şşşt, sakin ol!
 Evliliğin düşmanları
 Kocanızı Romeo'ya
 Neler oluyor bize?
 Erkek aldatılırsa...
 Önce seni çözerim sonra
 Kusursuz bir gelinim...
Devamı

Erkekçe - Erkek

 Iktidarsizlik
 Androloji
 Kisirlik
 Erkek Neleri Sever
 Kadinlarin Gerçek Yüzü
 Erkekleri Çildirtan 7 Soru
 Erkek ve Yemek
 Erkek Severse
 Erkek Asik Olursa
Devamı
 

Oyunlar

 Street fighter..
 Turbo motor..
 Mario..
 Fireman..
 Serbest vuruş..
 Süper mario super ma..
 Metal slug3 metal sl..
 world cup oyna world..
 Sudoku su doku..
 Varmısın yokmusun oy..
 Kim 1 milyon ister..
Devamı

Videolar

 brezilya arjantin ..
 seyyar züccaciye müb..
 ronaldo rakibini çyl..
 Yntizar - büyük Ynsa..
 yyldyz tilbe-ben bir..
 çok güzel hareketler..
 model masörü olmak i..
 fyrlama yine yapty y..
 Yukardaki kitaby ban..
 bu kyz tamirci dükka..
 hadise eurovision ..
 recep ivedik 2 fragm..
 avrupa yakasi yemekt..
Devamı
 

Telif Hakkı Saklıdır.

2006 - 2008 © Sevgimix.Com

Sayfa Üretimi: [0,10 saniye.]

Şiirler - Oto deri döşeme - Oyun - Şarkı Sözleri - Videolar Oturma Grupları - Kadınca - Ateşli kızlar - Lolita kızlar - Videolar - Bikinili Kızlar - Aşk sözleri - Güzel Kızlar - Rüya tabirleri  İtiraf et - Gelinlikler - Sektör  -  Oturma grupları - Güzel Sözler - Sağlık - msnletter
 Sitemap

domain