BİLGİSAYARLAR ve C++

Transkript

BİLGİSAYARLAR ve C++
Kaynak: Deitel&Deitel, C++ How To Program
YILDIZ TEKNİK ÜNİVERSİTESİ
BİLGİSAYAR ve ÖĞRETİM TEKNOLOJİLERİ EĞİTİMİ BÖLÜMÜ
DERS:
DERSİ VEREN:
SINIF:
DÖNEM:
PROGRAMLAMA DİLLERİ – 1
Öğr. Gör. Filiz Eyüboğlu
2
1
TÜM DERS NOTLARI: www.bto.yildiz.edu.tr, ders notları linkinde. Bu notlar aşağıdaki
1.no.lu kaynaktan yararlanılarak hazırlanmıştır.
DİĞER KAYNAKLAR:
1. Deitel & Deitel. (2000). C++ How To Program. Third Edition. New Jersey: Prentice Hall
2. http://www.bups.bilkent.edu.tr/ibcomp/cpp/cpp.html
KONU 1: BİLGİSAYARLAR ve C++ İLE PROGRAMLAMAYA GİRİŞ
HEDEFLER:
12345678-
Programlama dillerinin evrimi bakımından dil sınıflarını öğrenme
Tipik bir C++ program geliştirme ortamını anlama
C++ ile basit programlar yazabilme
Basit G/Ç cümleleri yazabilme
Temel veri türlerini tanıma
Aritmetik operatörleri kullanabilme
Aritmetik operatörlerin önceliklerini anlama
Basit karar verme cümleleri yazabilme
İÇERİK:
Giriş:
Bilgisayar nedir?
İşletim sistemlerinin evrimi
Kişisel, Dağıtık ve İstemci/Sunucu Ortamlar
Dil çeşitleri: Makine dili, “assembly” dili ve yüksek seviyeli diller
C ve C++’nın tarihçesi
Yapısal programlama
Nesne teknolojisi: Yazılımda yeni eğilim
C++ programı yürütmenin aşamaları
C++ ile programlamaya giriş
Basit bir program: bir satır yazma
Diğer bir basit program: 2 tamsayının toplanması
Bellek kavramları
Aritmetik
Karar verme: Eşitlik operatörleri ve ilişkisel operatörler
Filiz Eyüboğlu
YTÜ-BTB
1
Kaynak: Deitel&Deitel, C++ How To Program
GİRİŞ
BİLGİSAYAR NEDİR?: Bilgisayar, insanın yapabileceğinden milyonlarca hatta milyarlarca
kat hızlı hesaplama yapan ve/ya mantıksal kararlar verilebilen bir alettir. Süper bilgisayarlar
saniyede yüz milyarlarca toplama yapabilirler ki bu bir insanın basit bir hesap makinesiyle
onlarca yılda yapabileceği işlem miktarıdır.
Bilgisayarlar, bilgisayar programı denen komut setlerinin kontrolu altında verileri işlerler.
Bilgisayarda çalışan bilgisayar programlarına yazılım denir. Bunları geliştiren, yazan kişilere
de bilgisayar programcısı denir.
Bilgisayar 6 mantıksal bölümden oluşur:
123456-
Giriş birimi
Çıkış birimi
Bellek
Aritmetik mantık birimi
Kontrol birimi
İkincil bellek
Merkezi işlem birimi
İŞLETİM SİSTEMLERİNİN EVRİMİ
İlk bilgisayarlar bir anda bir iş yapabiliyorlardı. Delikli kartlarla yazılan programlar, kart
okuyucudan bilgisayara okutularak sırayla (bir anda bir iş) çalıştırıldı. Bir anda bir işin
çalıştığı bu ortamda bilgisayarın tüm kaynakları verimli biçimde kullanılmamış olmaktadır.
MİB çalışırken giriş ve çıkış birimleri boş beklemektedir. Daha verimli kaynak kullanımı için
giderek “çoklu programlama” ya izin veren işletim sistemleri geliştirilmiştir. Bu ortamlarda
bir anda birden fazla iş çalışır, ancak hala kullanıcılar programlarını kartlara delerek
bilgisayara girmektedir.
1960’larda “timesharing” işletim sistemleri geliştirilmiştir. Timesharing bir ortamda
kullanıcılar bilgisayara, terminaller (bir ekran ve klavye) aracılığıyla erişirler. Böylelikle
onlarca hatta yüzlerce kişi aynı anda tek bir bilgisayara erişebilmekte ve kullanmaktadır.
KİŞİSEL, DAĞITIK ve İSTEMCİ/SUNUCU İŞLEM
1977’de Apple şirketi kişisel bilgisayarları popülerleştirdi. İlk başta hobisel bir yaklaşım olan
kişisel bilgisayar kullanımı 1981’de IBM’in Personal Computer’ı tanıtmasıyla sadece evlerde
değil iş yaşamında da çok yoğun biçimde kullanılmaya başladı.
Fakat bu bilgisayarlar tek başına birimlerdi. Bilgisayardaki veriyi paylaşabilmek için başka
bir bilgisayara taşınabilir disklerle taşımak gerekiyordu. Tek başına, bağımsız üniteler halinde
bulunan bilgisayarların LAN veya büyük ağlar aracılığıyla birbirine bağlanmasıyla dağıtık
işlem (“distributed processing”) başladı. Bugün artık büyük miktarlarda veri, bilgisayar
ağlarında yer alan File Server denen ve ortak kullanılacak program ve verileri saklayan
bilgisayarlar aracılığıyla
istemci
bilgisayarlar tarafından kullanılabilmektedir
(istemci/sunucu ortam).
Filiz Eyüboğlu
YTÜ-BTB
2
Kaynak: Deitel&Deitel, C++ How To Program
C ve C++ günümüzde, bu ortamları (bilgisayar ağları, dağıtık istemci/sunucu ortamlar,
bunları destekleyen işletim sistemleri) yazmakta yaygın olarak kullanılan dillerdir.
PROGRAMLAMA DİLLERİ
Programlamanın evrimi bakımında 4 sınıftan bahsedebiliriz:
1- Makine dilleri (1.kuşak): sayılardan oluşan, sadece belirli bir makinenin anlayacağı , hata
yapmaya çok açık diller
2- Assembly dilleri (2.kuşak): İngilizce benzeri komutlardan oluşan diller. Assembly dili ile
yazılmış bir program, bir çevirici (translator) ile makine diline çevrilerek çalıştırılır.
Oldukça anlaşılabilir gözükmesine karşın çok basit bir iş için bile çok sayıda komut
yazmak gerekmektedir.
3- Yüksek seviyeli diller (3.kuşak) - “procedural” diller. “NASIL” yapılacağını ayrıntılı
olarak bildirdiğimiz diller. İngilizceye benzer, aritmetik işlemlerde kullandığımız işaretleri
kullanır, daha hızlı ve kolay program yazılır. C ve C++ bu gruptadır. Çok sayıda dil
geliştirilmiştir. Yaygın kabul görenler:
Fortran
Cobol
Pascal
IBM
1954 Mühendislik uygulamalarında hala yaygın olarak kullanılır.
1959 Günümüz ticari uygulamalarının yarısı Cobol ile yazılmıştır.
Niklaus Wirth 1971 Akademik kullanım için
4- Çok yüksek seviyeli diller (4.kuşak): “NE” yapılacağını söyledğimiz diller: LISP,
SNOBOL, FORTH, SQL...
C ve C++’nin TARİHÇESİ
BCPL 1967 Martin Richards
B
1970 Ken Thompson
Bell Laboratuarları
C
1972 Dennis Ritchie
Bell “
UNIX işletim sisteminin yazılmasında kullanıldı. Makineden bağımsız bir dil.
C++ 1980 Bjarne Stroustrup
AT&T
1983 – 1989 ANSI C’nin standart tanımını yaptı, 1990’da yayımlandı: ANSI/ISO 9899:1990
C++, C’ye birtakım ek özellikler ile nesne-yönelimli programlama (“object-oriented
programming”) yetenekleri getirmiştir. Nesneler tekrar tekrar kullanılabilir yazılım
bileşenleridir; yazılım geliştirmede büyük kolaylık (verimlilik) sağlarlar.
Diğer nesne-yönelimli diller:
Smalltalk
Java
Xerox’s Palo Alto Araştırma Merkezi
Sun Microsystems-James Goslin 995 (1993 WWW popülerliği)
C++ STANDART KİTAPLIK
C++ programları sınıflar (“classes”) ve fonksiyonlardan (“functions”) oluşur. Bunlar program
parçalarıdır. Bunların bir kısmını programcı yazar, bir kısmı da standart kitaplıkta hazır
bulunur.
Filiz Eyüboğlu
YTÜ-BTB
3
Kaynak: Deitel&Deitel, C++ How To Program
YAPISAL PROGRAMLAMA
1960’lara kadar programlama çok karmaşık, zor, maliyetli...
1960’larda yapısal programlama ortaya çıkmaya başladı. Yapısal programlama, daha açık,
net, anlaşılabilir, okuması, izlemesi, sınaması kolay programlar yazmak için bir yaklaşımdır.
3 temel yapı kullanılır: sıra, tekrar yapısı ve karar verme yapısı. Goto kullanılmaz ya da
mümkün olduğunca az kullanılır. Buna uygun ilk dillerden biri (ve en popüleri diyebiliriz)
Pascal (Niklaus Wirth,1971). Akademik ortamlarda yapısal programlamayı öğretmek için
geliştirildi. Pek çok okulda yaygın olarak kullanıldı. Ancak, ticari uygulamalarda ve her türlü
iş ortamına uygun uygulamalarda gereksinilen pek çok olanağı içermemesi, üniversite
dışında yaygın kabul görmemesine neden olmuştur.
Ada – 1970’ler – 1980’lerin başı - US Dept. Of Defense
ANAHTAR YAZILIM TRENDİ: NESNE TEKNOLOJİSİ
Yazılım teknolojisindeki gelişme ve ilerlemeler; yapısal programlama, yapısal tasarım,
yapısal analiz ile başladı. Ancak nesne yönelimli analiz, tasarım ve programlama ile daha çok
gelişme elde edildi. Nesne yönelimli ile çevremizdeki tüm nesneleri (araba, öğrenci, ders,
insan, uçak, sınıf vb) modelleriz. Modellediğimiz bu yazılım parçalarını tekrar tekrar
kullanabildiğimiz gibi, bu tarz yazılan yazılımlar, daha iyi organize ve anlaşılır oldukları için
bakımları da çok kolay olmakta ve programcıya zaman ve maliyetten büyük tasarruf
sağlamaktadır (Yazılım maliyetinin %80’i programlamanın başında ve yazımındaki emeğe
değil sonradan yapılan sürekli bakıma aittir).
C++, nesne yönelimli bir dil olarak anılmasına karşın hibrid bir dildir. Yani hem yapısal hem
de nesne yönelimli program yazmayı mümkün kılar
Classes and Data Abstraction konusuna kadar C++ ile “procedural” programlama
kavramlarını göreceğiz: kontrol yapıları, fonksiyonlar, veri türleri, giriş/çıkış, diziler, pointer
ve stringler. Bu bölümlerde C++’ın C kısmı, C++ procedural enhancements to C
kapsanacaktır.
C++ PROGRAMI YÜRÜTME AŞAMALARI
Unix ortamında bir C++ programının yürütülmesi için 6 aşamadan geçilir:
1234-
Edit :
kaynak programın bir editör program ile yazılması. Uzantısı .cpp, .cxx veya .c
Ön işleme (“preprocess”):
derleme öncesi bazı işlemler
Derleme: derlemenin çıktısı: amaç program
Link:
programımızda kullanacağımızı belirttiğimiz standart kitaplık veya özel
kitaplıklarda bulunan fonksiyonların amaç programla bir araya getirilmesi (link edilmesi)
5- Yükleme (“load”) – programın ve varsa gerekli bazı modüllerin (paylaşılan kitaplıklardan)
diskten alınıp belleğe yüklenmesi
6- Yürütme
Şema: s. 15 (Deitel)
Filiz Eyüboğlu
YTÜ-BTB
4
Kaynak: Deitel&Deitel, C++ How To Program
TAŞINABİLİRLİK (“portability”)
Taşınabilir programlar yazmak mümkünse de değişik sistemler ve değişik derleyiciler
arasında birtakım problemler çıkmaktadır. Taşınabilirlikle ilgili konular ANSI C Standart
dokümanında yer almaktadır: www.ansi.org Doküman adı: Information Technology –
Programming languages – C++. Doküman numarası: ISO/IEC 14882-1998.
Daha eski taslak versiyonu (ücretsiz): www.cygnus.com/misc/wp/
İYİ PROGRAM YAZMA TAVSİYELERİ:
C++ programlarınızı basit ve straightforward biçimde yazın: KIS (“Keep It Simple”).
Kullandığınız C++ sürümünün kılavuzu elinizin altında olmalı.
En iyi öğretici bilgisayarınızdır. Kitaplarda veya derslerde işlenen konuları, verilen örnekleri,
bilgisayarda çalıştırarak, çıkan hata mesajlarını okuyup, tekrar deneyerek öğrenebilir ve
tecrübe kazanabilirsiniz.
C++ İLE PROGRAMLAMAYA GİRİŞ
BASİT BİR PROGRAM: BİR SATIR METNİN YAZDIRILMASI
// C++ ile ilk programım
#include <iostream>
int main()
{
std::cout << “Herkese Merhaba!\n”;
return 0;
// program sonu
}
Herkese Merhaba!
C++’de açıklama satırının başına konur. Bu satırlar için derleyici bir iş yapmaz; bu
satırlar program dökümünde aynen yer alan; programın okunabilirliği, anlaşılabilirliği için
gerekli açıklama satırlarıdır. İyi bir programcı gerekli yerlere gerekli açıklamaları koyar.
//
C dilinde ise açıklama /*
*/
arasına konur.
# ile başlayan satırlar ön derleyici (“preprocessor”) içindir. Örnek programımızda # ile
başlayan satır ön derleyiciye giriş/çıkış ile ilgili iostream başlık dosyasını (“header file”)
programa dahil etmesini söyler.
int main ()
her C++ programında olması gerekir.
Filiz Eyüboğlu
YTÜ-BTB
5
Kaynak: Deitel&Deitel, C++ How To Program
Her C++ programı bir veya birkaç fonksiyondan oluşur. ()’ler main’in bir fonksiyon
olduğunu; “main” sözcüğü de bunun ana fonksiyon olduğunu belirtmektedir.
int
integer (tamsayı) anlamında.
int main ()’in anlamı: bu ana fonksiyonun çalıştıktan sonra verdiği değer, bir tamsayıdır.
(return 0 ile dönen sıfır )
Bir fonksiyonun gövdesi (“body”) köşeli sol parantez ile { başlar,
köşeli sağ parantez
ile } biter.
std::cout
ekrana çıkış almak için. İlerki bölümlerde daha ayrıntılı göreceğiz.
std::cin
klavyeden girileni okumak için
<<
“stream insertion operator”
\n
karakterlerinin çıktıda yer almadığına dikkat edin!
“escape” karakteri
imlecin alt satıra konumlanmasını söyler.
\
n
\n
\t
\r
\a
yeni satır
bir “tab” ileri gitmek için
imleç yeni yazılan sol başına konumlanır (“carriage return”)
uyarı sesi
Herkese Merhaba! cümlesini başka nasıl yazdırabilirdik?
std::cout << “Herkese “;
std::cout << “Merhaba!\n”;
ŞÖYLE YAZARSAM ÇIKTI NASIL OLUR???
std::cout <<”Herkes\ne\nMerhaba!\n”;
Herkes
e
Merhaba!
BAŞKA BİR BASİT PROGRAM:
iki tamsayının toplanması
// İKİ TAMSAYIYI TOPLAYAN PROGRAM
#include <iostream>
int main()
{
int tamsayi1, tamsayi2, toplam; //tanımlamalar
std::cout << “Birinci tamsayıyı giriniz\n”;
std::cin >> tamsayi1; //klavyeden girilen sayıyı oku
Filiz Eyüboğlu
YTÜ-BTB
6
Kaynak: Deitel&Deitel, C++ How To Program
std::cout << “İkinci tamsayıyı giriniz\n”;
std::cin >> tamsayi2; // klavyeden girilen sayıyı oku
toplam = tamsayi1 + tamsayi2;
std::cout << “Toplam = “ << toplam << std::endl;
return 0; // programın başarıyla bittiğini gösterir
}
std::endl
=Î endl
“end line” yani satır sonu demektir. Yaptığı iş, yeni satırı
yazdıktan (ekrana yolladıktan sonra) çıkış buffer’larını temizlemektir. Bilindiği gibi, çıkışa
gönderilecek veriler, gönderilmeden önce çıkış buffer’larında biriktirilir. Çıkış işleminden
sonra buffer’ların boşaltılması/temizlenmesi için endl kullanırız.
ÖNEMLİ NOTLAR:
C++, büyük ve küçük harfe duyarlı bir dildir.
Cümleler ; (noktalı virgül) ile biter.
İYİ PROGRAM YAZMA TAVSİYELERİ:
1234-
Bir fonksiyonun gövdesinin içine yazılan satırlar 3 boşluk içerden yazılır
(“indentation”)
Tanımlamalar ile yürütülebilir cümleler arasında bir satır boşluk bırakınız.
Anlamlı değişken isimleri kullanınız.
İkili (“binary”) operatörlerin sağ ve solunda birer boşluk bırakınız.
ARİTMETİK OPERATÖRLER
C++ işlemi
Aritmetik operatör Cebirsel ifade C++ ifadesi
Toplama
Çıkarma
Çarpma
Bölme
Modulus
+
*
/
%
f+7
p-c
bm
x/y
r mod s
f+7
p–c
b*m
x/y
r%s
C++’da aritmetik işlemlerde operatörlerin öncelik sırası kuralları:
1- Parantez içleri en önce hesaplanır.
2- Daha sonra, çarpma, bölme, modulus işlemleri yapılır. Bir aritmetik ifadede birden fazla
çarpma, bölme, modulus işlemi varsa, bu işlemlerdeki operatörler SOLDAN SAĞA doğru
uygulanır. Çarpma, bölme, mod operatörlerinin önceliği aynıdır.
3- En son toplam ve çıkarma işlemleri yapılır. Bir ifade, birden fazla toplama ve çıkarma
işlemi içeriyorsa, bunlara ait operatörler SOLDAN SAĞA uygulanır.
ÖRNEKLER: ss. 31 – 33 (Deitel)
Filiz Eyüboğlu
YTÜ-BTB
7
Kaynak: Deitel&Deitel, C++ How To Program
İYİ PROGRAM YAZMA TAVSİYELERİ:
Cebirde olduğu gibi, gereksiz parantezler konmayabilir. Ancak, özellikle uzun ifadelerde alt
ifadeleri parantez içlerin alarak anlaşılabilirliği artırmak iyidir.
İLİŞKİSEL OPERATÖRLER ve EŞİTLİK OPERATÖRLERİ
İlişkisel operatörler
C++ karşılığı
C++ örneği
Anlamı
>
<
>
<
>=
<=
x>y
x<y
x >= y
x <= y
x, y’den büyüktür
x, y’den küçüktür
x, y’den büyüktür veya y’ye eşittir
x, y’den küçüktür veya y’ye eşittir.
==
!=
x ==y
x != y
x, y’ye eşittir
x, y’ye eşit değildir
Eşitlik operatörleri
=
SIK YAPILAN HATALAR:
==, >=, <=, != operatörlerini yazarken iki karakter arasında boşluk bırakılmamalıdır veya
iki karakterin yeri değiştirilmemelidir.
Eşitlik operatörü ==’ yi, atama için kullanılan = ile karıştırmayınız.
EŞİTLİK VE BAĞINTI OPERATÖRLERİNİ KULLANAN BİR PROGRAM ÖRNEĞİ
// if cümlesi ile eşitlik ve ilişki/bağıntı operatörlerini kullanan bir
program
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
// program cout kullanır
// program cin kullanır
// program endl kullanır.
int main ()
{
int sayi1, sayi2;
cout << “İki tamsayi giriniz.\n”
<< “Ben aralarındaki ilişkiyi söyleyeceğim: “;
cin >> sayi1 >> sayi2;
endl;
if (sayi1 == sayi2)
cout << sayi1
if (sayi1 != sayi2)
cout << sayi1
if (sayi1 < sayi2)
cout << sayi1
if (sayi1 > sayi2)
cout << sayi1
if (sayi1 <= sayi2)
cout << sayi1
Filiz Eyüboğlu
<< sayi2 << “’ye eşittir.” << endl;
<< sayi2 << “’ye eşit değildir.” << endl;
<< “, “ << sayi2 << “’den küçüktür.” << endl;
<< “, “ << sayi2 << “’den büyüktür.” << endl;
<< “, “ << sayi2 << “’den küçük veya eşittir.” <<
YTÜ-BTB
8
Kaynak: Deitel&Deitel, C++ How To Program
endl;
if (sayi1 >= sayi2)
cout << sayi1 << “, “ << sayi2 << “’den büyük veya eşittir.” <<
return 0;
}
İki tamsayı giriniz.
Ben size aralarındaki ilişkiyi söyleyeceğim: 3 7
3, 7’ye eşit değildir.
3, 7’den küçüktür.
3, 7’den küçük veya eşittir.
İki
Ben
22,
22,
22,
tamsayı giriniz.
size aralarındaki ilişkiyi söyleyeceğim: 22 12
12’ye eşit değildir.
12’den büyüktür.
12’den büyük veya eşittir.
İki tamsayı giriniz.
Ben size aralarındaki ilişkiyi söyleyeceğim: 7 7
7, 7’ye eşittir.
7, 7’den küçük veya eşittir.
7, 7’den büyük veya eşittir.
using cümleleri: cout ve cin’den önce std:: kullanımını ortadan kaldırır. Hatırlanacağı gibi
ilk basit örneğimizde std::cout kullanmıştık. Çok sayıda giriş / çıkış yapılacağı zaman her
cout ve cin’den önce std:: kullanmak çok pratik olmayacaktır. Bu nedenle using kullanmakta
fayda vardır.
İYİ PROGRAM YAZMA TAVSİYELERİ:
1- Programın okunabilirliğini artırmak için if yapısının içinde yer alan cümleleri 3 boşluk
içerden yazınız.
2- Bir satırda birden fazla cümle yer almamalı.
3- Bir cümle bir satıra sığmayıp alt satırdan devam edecekse, cümleyi anlamlı bir yerinden
bölmeye özen gösteriniz.
*** Konu 1’in sonu ***
YILDIZ TEKNİK ÜNİVERSİTESİ
BİLGİSAYAR ve ÖĞRETİM TEKNOLOJİLERİ EĞİTİMİ BÖLÜMÜ
DERS:
Filiz Eyüboğlu
PROGRAMLAMA DİLLERİ – 1
YTÜ-BTB
9
Kaynak: Deitel&Deitel, C++ How To Program
DERSİ VEREN:
SINIF:
DÖNEM:
Öğr. Gör. Filiz Eyüboğlu
2
2002-2003 güz dönemi
TÜM DERS NOTLARI: www.bto.yildiz.edu.tr, ders notları linkinde. Bu notlar aşağıdaki
1.no.lu kaynaktan yararlanılarak hazırlanmıştır.
DİĞER KAYNAKLAR:
3. Deitel & Deitel. (2000). C++ How To Program. Third Edition. New Jersey: Prentice Hall
4. http://www.bups.bilkent.edu.tr/ibcomp/cpp/cpp.html
KONU 2: KONTROL YAPILARI
HEDEFLER:
9- Yukarıdan aşağı (“top-down”) algoritma geliştirebilme
10- Yapısal programlamayı anlama
11- Seçim yapma yapılarını (if, if/else, switch) kullanabilme
12- Tekrar etme yapılarını (while, do/while, for) kullanabilme
13- Sayaç kontrollu tekrarı anlama
14- Mantıksal işlem, atama operatörleri, artırma ve eksiltmeyi kullanabilme
15- Program kontrol cümlelerini (break, continue) kullanabilme
İÇERİK:
Algoritmalar
“Pseudocode”
Kontrol yapıları: if, if/else, while
“Yukarıdan-aşağı” yaklaşımla algoritma tasarlama
Atama operatörleri
Tekrar için sayaç-kontrollu yapı: for
Çoklu-seçme yapısı: multiple
Tekrar yapısı: do/while
Break ve continue cümleleri
Mantıksal operatörler
GİRİŞ
Bir problemi çözecek programı yazmaya başlamadan önce, problemi tam olarak anlamak ve
çözüm için dikkatlice planlama yapmak gerekir. Daha sonra program yazamaya başlanabilir.
Programı yazarken de – planlama kadar önemli bir konu - dilin sunduğu yapı bloklarını ve
program yapılandırma ilkelerini çok iyi bilmektir. Bu konumuzda, yapısal programlama
yaklaşımını, C++’nin bu konuda sağladığı yapıları kullanarak öğreneceğiz.
ALGORİTMA
Filiz Eyüboğlu
YTÜ-BTB
10
Kaynak: Deitel&Deitel, C++ How To Program
Algoritma, bir problemi çözmek için
- yürütülecek eylemlerin, ve
- bu eylemlerin sırasını
belirten bir talimattır, prosedürdür .
Bir bilgisayar programında yürütülecek cümlelerin sırasını belirlemeye program denetimi
(“program kontrol”) denir. Bu derste, C++’ın program denetimiyle ilgili yeteneklerini
göreceğiz.
PSEUDOCODE
Pseudocode, algoritma geliştirmede programcılara yardımcı olan dildir; günlük konuşma
dilimizde kullandığımız sözcüklerden oluşur. Bu dille yazılan program bilgisayarda
yürütülemez; ancak programcıya geliştirmeye çalıştığı algoritma üzerinde düşünmesini, onu
şekillendirmesini, oluşturmasına yarar. İyi yazılmış bir pseudocode’u gerçek bir programlama
diline çevirmek kolay olur.
Pseudcode ile sadece yürütülecek cümleleri yazarız. int x gibi tanımlamaları yazmayız.
Tanımlamalar (“declarations”) yürütülebilir cümleler değildir. int x
dediğimiz zaman
bilgisayar x için bir yer ayırır.
Bazı programcılar, pseudocode’un baş kısmında, kullanacakları değişkenlerin ad ve
amaçlarını listelemeyi tercih ederler.
KONTROL YAPILARI
Normalde, bir programdaki cümleler yazıldıkları sırayla, biri diğerinin ardından yürütülürler.
Buna sıralı yürütme (“sequential execution”) denir.
Sıralı yürütmeye basit bir örnek ver, akış şeması ile. s.62
Yürütmek istediğimiz cümle, sıradaki cümle değil de, programın daha ilerisinde veya baş
tarafında olabilir. Yürütmenin bir sonraki cümleye değil de programın başka bir yerindeki
cümleye yönlendirilmesine kontrolun transferi denir. 1960’larda kontrolun transferi için
çokça kullanılan goto cümlesi yazılım geliştirenlerin işini zorlaştırmıştır. Goto’nun fazlaca
kullanıldığı bir programı yazmak, takip etmek, anlamak zordur. Yapısal programlama
dediğimiz kavramla goto’lar mümkün olduğunca ya da tümden yok edilirler. Bohm ve
Jacopini bir programın goto’suz, üç tür yapı - sıralı, seçme, tekrar yapıları – kullanılarak
yazılabileceğini göstermiştir. 1970’lerde yapısal programlamadan çok ciddi biçimde söz
edilmeye ve kullanılmaya başlanmıştır. Bu yaklaşım yazılım geliştirme zamanını azaltmıştır.
Bildiğiniz gibi, akış şeması bir algoritmanın ya da algoritma parçasının görsel ifadesidir.
Pseudocode gibi akış şeması da algoritma geliştirmede kullanışlıdır.
Akış şeması sembolleri geçen dönem EBT2’de öğrenildi.
if SEÇME YAPISI ( “if selection structure”)
Seçme yapısı, çeşitli eylem seçeneklerinden birini seçmek için kullanılır. Örneğin,
“öğrencinin notu 60’dan fazla ise, ‘geçti’ yaz “ demek istiyorsak...Bunu ifade edebilmek için,
öğrenci notunun 60’dan büyük eşit olup olmadığını sınamamız gerekir. Sınama yaptığımızda
Filiz Eyüboğlu
YTÜ-BTB
11
Kaynak: Deitel&Deitel, C++ How To Program
koşul doğru ise “geç” yazdırırız, koşul yanlış ise hiçbir şey yaptırmadan sıradaki cümle ile
yürütme devam eder. Bunu C++ ile şöyle ifade ederiz:
if (not >= 60)
cout << “geçti”;
((((( BU İFADEYİ AKIŞ ŞEMASI İLE GÖSTER ))))) s.64 şekil. 2.3
SIK YAPILAN HATALAR:
C++ anahtar kelimelerini değişken veya fonksiyon adı olarak kullanmak. Anahtar sözcükler
aşağıda verilmiştir.
C ve C++’da ortak olan anahtar kelimeler:
auto
break case
else enum
long
Short signed sizeof
void volatile
s.63
char const continue
default
extern float for
goto if
register
return
static struct switch
typedef
while
do
double
int
union unsigned
Sadece C++’da geçerli olan anahtar sözcükler:
asm
bool
dynamic_cast
new
protected
template
throw true
virtual
catch
class
const_cast
delete
explicit false friend inline
mutable
namespace
operator
private
pubic
reinterpret_cast
static_cast
this
try
typeid
typename
using
wchar_t
İYİ PROGRAM YAZMA TAVSİYELERİ:
if cümlesinde koşulun doğruluğuna göre yapılacak eylemi (if’in gövdesine yazılacak
cümleleri) bir sonraki satırdan ¼ inç veya 3 boşluk içeriden yazınız.
if/else SEÇME YAPISI ( “if/else selection structures”)
if/else yapısı, koşulun doğruluğuna veya yanlışlığına göre değişik işlemler yaptırmak için
kullanılır.
if (not >= 60)
cout << “geçti”;
else
cout << “kaldı”;
((((( BU İFADEYİ AKIŞ ŞEMASI İLE GÖSTER )))))
Filiz Eyüboğlu
YTÜ-BTB
12
Kaynak: Deitel&Deitel, C++ How To Program
Yukarıdaki if/else örneğini C++’da, ?: koşul operatörü kullanarak şöyle de yazabiliriz.
cout << (not >= 60
? “geçti”
:
“kaldı” );
Birden fazla durumu sınamak için içiçe if/else cümleleri kullanılır.
if (grade >= 90)
cout <<”A”;
else
if (grade >= 80)
cout << “B”;
else
if (grade >= 70)
cout << “C”;
else
if (grade >= 60)
cout << “D”;
else
cout << “F”;
Aynı kod şöyle de yazılabilir (çok fazla sağa doğru uzamayı engellemek için):
if (grade >= 90)
cout << “A”;
else if (grade >= 80)
cout << “B”;
else if (grade >= 70)
cout << “C”;
else if (grade >= 60)
cout << “D”;
else
cout << “F”;
PERFORMANS İLE İLGİLİ İPUCU:
İçiçe if/else yapısı, bir seri tek seçim yapan if cümlelerinden daha hızlı çalışır.
if yapısında gövdeye tek bir cümle koymayı gördük. Birden fazla sayıda cümle koyacaksak
bunlar { } parantezlerinin arasına alınır ve bu tarz parentezler arasında bulunan cümleler
topluluğuna Bileşik Cümle (“compound statement”) denir.
Örnek:
if (not >= 60)
cout << “geçti.\n”;
else {
Filiz Eyüboğlu
YTÜ-BTB
13
Kaynak: Deitel&Deitel, C++ How To Program
}
cout << “kaldı.\n;
cout << “Bu dersi tekrar almak zorundasınız.\n;
SIK YAPILAN HATALAR
-
if cümlesinde, koşuldan sonra ; (noktalı virgül) koymak
if, if/else gövdesinde parantezi kapamayı unutmak, veya yanlış yerde kapatmak
while TEKRAR YAPISI
(while repetition structure)
Tekrar yapısı, programcının bir eylemi belirli bir koşul doğru olduğu müddetçe tekrar
etmesini sağlar.
Alış veriş listesinde daha mal olduğu müddetçe
Bir sonraki malı al, sonra üzerini çiz
gibi.
Örnek bir program: 2’nin 1000’den büyük yapan ilk üssünü bulunuz.
carpim isimli degişkene 2 sayısını atamış olalım.
int carpim = 2;
Aşağıdaki w h i l e yapısı bittiğinde, carpim degiskeni istenen cevabı içerecektir.
while (carpim <= 1000)
carpim = 2 * carpim;
Carpim, ilk giriste 2, daha sonra 4,8,16,32,64,128, 256, 512, 1024 değerlerini alır.
1024 > 1000 oldugunda while’ın yürütülmesi durur.
ALGORİTMA GELİŞTİRME
ÇALIŞMA-1: (sayaç kontrollu tekrar kullanarak)
On öğrencilik bir sınıf sınava girdi. Aldıkları notlar size verildi. Sınıfın ortalamasını bulacak
algoritmayı geliştirip, daha sonra C++ ile yazınız.
Ortalama ne demek? 10 notu toplayıp, 10’a böleceğiz.
10 not okumamız gerektiği için s a y a ç kullanarak okuma işlemini tekrar etmemiz gerekir.
Sayaç, 10’u geçtiği anda tekrar işlemi bitmeli.
Okuduğumuz notları üstüste toplayacağımız bir değişkenimiz olmalı. Buna t o p l a m
diyelim.
toplam = 0
sayac = 1
while s a y a c ondan küçük eşit olduğu müddetçe
Filiz Eyüboğlu
YTÜ-BTB
14
Kaynak: Deitel&Deitel, C++ How To Program
bir sonraki notu oku
bu notu t o p l a m‘ a ekle
s a y a c’ ı bir artır
t o p l a m’ ı ona bölerek o r t a l a m a’yı hesapla
o r t a l a m a ‘yı yazdır.
// sayac kontrollu tekrar ile sınıf ortalamasını bulan program
#include <iostream>
using std::cout
using std::cin;
using std::endl;
int main()
{
int
toplam,
sayac,
not
ortalama;
// notların toplamı
// girilen notların sayısı
// bir not
// notların ortalaması
// ilk değerlerin atanması
toplam = 0;
sayac = 1;
while (sayaca <= 10)
{
cout << “notu giriniz: “;// bir notun girilmesini iste
cin >> not;
// girilen değeri not değişkenine
al
toplam = toplam + not; // notu toplama ekle
sayac = sayac + 1;
// sayacı artır
}
ortalama = toplam / 10;
cout << “Sınıf ortalaması = “ << ortalama << endl;
return 0;
}
SIK YAPILAN HATALAR
-
Toplam, sayac gibi değişkenlere ilk değer atamalarını unutmayınız. Unutursanız
değişkenin içinde hangi sayı olduğunu bilemezsiniz ve program beklenenden farklı
değerler üretir.
İlk değer atamalarını unutmak, yazım (“syntax”) hatası vermez, ancak programınız
istenen sonucu vermediği için mantık hatası oluşmuş olur.
Filiz Eyüboğlu
YTÜ-BTB
15
Kaynak: Deitel&Deitel, C++ How To Program
-
Sayaç kontrollu döngüde, döngüden çıkıldığında (while’dan çıkıldığında) sayacın değeri
saydığımızdan / istediğimizden 1 fazla olacaktır (örneğimizde döngüden çıkıldığında
sayac 11’dir. Öğrenci sayısı ondur). Dolayısıyla hesaplamalarda s a y a c değişkenini
kullanırsak hesap hatası oluşur.
İYİ PROGRAM YAZMA TAVSİYESİ
Her bir değişkeni ayrı bir satırda tanımlayınız.
ÇALIŞMA-2
Yukarıdan aşağı yaklaşımla (“top-down”) algoritma geliştirme
(işaret kontrollu tekrar ile - “flag controlled repetition”)
Sınıf ortalaması problemini genelleştirelim.: herhangi bir sayıda notu okuyup ortalama alacak
bir algoritma geliştiriniz.
Herhangi bir sayıda giriş yapılacağına göre girişlerin bittiğini nasıl anlayacağız? Bunun bir
yolu, “sentinel” veya “flag” veya “dummy” değer denen özel bir değer ile girişlerin sonunu
belirtmektir. Bu değer, giriş verileri ile karışmayacak bir değer olmalıdır. Giriş verileri
arasında yer alan bir flag değeri seçmek mantık hatasıdır. Sorumuzda, öğrenci notları
girileceğinden ve notlar negatif olmayacağından,
negatif bir sayıyı örneğin
-1’i
kullanabiliriz. Buna göre, girilen sayılar 75, 82, 67, 30, 25, -1 şeklinde olacaktır. –1 giriş
sonunu belirtir ve hesaplamalara karışmaması gerekir.
Sınıf ortalaması problemini yukarıdan-aşağı yaklaşımla ele alacak olursak:
Yapacağımız işte temel aşamalar nelerdir?
1- İlk değer atamalarını yap
2- Oku; topla, sayacı artır
3- Ortalamayı al, yazdır.
1. aşamayı ele alıp detaylandıracak olursak:
toplam’a sıfır ata
sayac’a bir ata
2. aşama bir tekrar yapısı / döngü gerektirir. Kaç not okuyacağımızı bilmediğimiz için flag
kontrollu bir yapı kurmamız gerekir. Notu okuyup, okur okumaz bu özel değeri içerip
içermediğini test etmeliyiz. Buna göre 2.aşama şöyle detaylandırılır:
ilk değeri oku
okunan değer f l a g değerinden farklı olduğu müddetçe
notu toplama ekle
sayacı bir artır
bir sonraki notu oku
3. aşama için de şunları yazabiliriz:
sayac sıfır değilse
Filiz Eyüboğlu
YTÜ-BTB
16
Kaynak: Deitel&Deitel, C++ How To Program
toplamı sayaca bölerek ortalamayı hesapla
ortalamayı yazdır
değilse (else)
“herhangi bir not girilmedi” yazdır.
ÖNEMLİ NOT: Bölme işlemlerine dikat!!! “Divide by zero is a fatal logic error”.
// Örnek: Deitel s. 77’de, fig.2.9
// flag kontrollu olarak yazılmış sınıf ortalaması programı
#include <iostream>
using
using
using
using
std::cout;
std::cin;
std::endl;
std::ios;
#include <iomanip>
//
setprecision kullanmak için bu olmalı
using std::setprecision;
using std::setiosflags;
int main()
{
int
toplam,
sayac,
not;
double ortalama;
toplam = 0;
sayac = 0;
cout << “Notu giriniz: (bitirmek için –1 giriniz) “;
cin >> grade;
while (not != -1)
{
toplam = toplam + not;
sayac = sayac + 1;
cout << “Notu giriniz: (bitirmek için –1 giriniz) “;
cin >> grade;
}
if (sayac != 0 )
{
ortalama = static_cast<double>(toplam) / sayac;
cout << “Sınıf ortalaması: “ << setprecision (2)
<< setiosflags( ios::fixed | ios::showpoint)
<< ortalama << endl;
}
else
cout << “hiç not girimedi” << endl;
Bilimsel
Filiz Eyüboğlu
YTÜ-BTB
gösterim
yerine
Ondalık
virgülden
Ondalık
virgülden
sonra sıfırlar
varsa onları
da yazması 17
için
Kaynak: Deitel&Deitel, C++ How To Program
return 0;
}
d o u b l e & float
int
reel sayı; ondalık virgülü olan sayılar
tamsayı
double, float’tan daha büyük sayıları veya daha fazla duyarlılıkla saklar.
Ortalamayı hesaplarken, toplam ve sayac değişkenlerimiz int türünde olduğu için bunların
bölümünden elde edilecek sayı int olacak ve ondalık virgülden sonraki kısmı olmayacaktı.
Oysa bir ortalama alırken virgülden sonraki kısma da ihtiyacımız vardır. Bunun için cast
operatörü kullandık (lab’daki bilgisayarlarda yüklü Turbo C/C++ V3’de bu geçerli
olmayabilir).
The cast operator static_cast<double>() creates a temporary floating-pint copy of
its operand in parentheses – toplam. Using a cast operator in this manner is called explicit
conversion. The value stored in t o p l a m is still an integer. The calculation now consists of
a floating-point value (temporary double version of total) divided by the integer sayac.
Implicit Conversion (Programcı açıkça belirtmediği halde yapılan dönüştürme): Bir
aritmetik ifadede hem int hem de double operand’lar varsa, derleyici int operand’ları
double’a dönüştürür.
ÇALIŞMA 3 – Yukarıdan aşağı algoritma geliştirme (içiçe kontrol yapıları kullanarak)
Bir derste birinci konu sonunda yapılan sınavın sonuçlarını değerlendirmek üzere bir
algoritma geliştireceksiniz (Bu değerlendirmeye göre bir sonraki konuya geçilip
geçilmeyeceğine karar verilecek)
Size 10 öğrencinin notlarını içeren bir liste verilecek. Listede, her ismin yanında öğrenci
sınavı geçtiyse 1, kaldıysa 2 yazıyor olacak.
Programınız sınavın sonuçlarını şu şekilde analiz etmeli:
1. Her bir sonucu (1 veya 2) oku. Program her seferinde başka bir sonuç okumak istediğinde
ekranda “sonucu girin: “ mesajı görüntülenmeli.
2. Her sonuç türünün kaç tane olduğunu say.
3. Geçen ve kalan öğrencilerin sayılarını görüntüle.
4. Eğer sekizden fazla öğrenci sınavı geçtiyse “Bir sonraki konuya geçilebilir” mesajını
görüntüle.
Bunları dikkatlice okuduktan sonra şu kararlara varabiliriz:
1- program 10 sonuç işleyecek. Bunun için sayac-kontrollu döngü kullanılmalı.
2- her bir sonuç okuduktan sonra bunun 1 mi 2 mi olduğunu program kontrol etmeli.
Programımızda 1 için kontrol edip, 1 değilse 2 olduğunu varsayabiliriz.
3- Hem geçenlerin hem de kalanların sayısı istendiğine göre 2 sayac kullanmak gerekir.
4- Tüm sonuçlar işlendikten sonra geçenlerin sayının 8’den fazla olup olmadığına karar
vermeliyiz.
Filiz Eyüboğlu
YTÜ-BTB
18
Kaynak: Deitel&Deitel, C++ How To Program
Pseudocode ile yazmaya başlayalım.
Değişkenlere ilk değerlerini ata
On sınav notunun girişini yap; kalan ve geçenleri say
Sonuçları yazdır ve bir sonraki konuya geçilip geçilmeyeceğine karar
ver
Değişkenlere ilk değerlerini ata
kısmını açalım:
Gecenler’e sıfır ata
Kalanlar’a sıfır ata
OgrenciSayaci’na bir ata
On sınav notunun girişini yap; kalan ve geçenleri say’ı
açalım:
While OgrenciSayaci ondan küçük veya eşit olduğu müddetçe
Bir sonraki sonucu oku
Ogrenci geçtiyse
Gecenler’i bir artır
degilse
Kalanlar’ı bir artır
OgrenciSayaci’ni bir artır
Sonuçları yazdır ve bir sonraki konuya geçilip geçilmeyeceğine
karar ver
kısmını açalım:
Gecenlerin sayısını yazdır
Kalanların sayısını yazdır
Gecenler 8’den fazla ise
“Bir Sonraki Konuya Geç” yaz
Bu pseudocode, C++’a geçmeyi sağlayacak kadar rafine edilmiş durumda.
// Şekil. 2.11 s.84
// Sınav sonuçlarının analizi
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
int gecenler = 0,
kalanlar = 0,
ogrencisayaci = 1,
Filiz Eyüboğlu
YTÜ-BTB
Değişkenleri tanımladığımız
anda bu şekilde ilk değer
atamalarını da yapabiliriz. Bu
yaklaşım, bazı değişkenlere
ilk değer atamalarını
unutmamızı engeller.
19
Kaynak: Deitel&Deitel, C++ How To Program
sonuc;
while (ogrencisayaci <= 10)
{
cout << “Sonuç gir (geçti için 1, kaldı için 2): “;
cin >> sonuc;
if ( sonuc == 1)
gecenler = gecenler + 1;
else
kalanlar = kalanlar + 1;
}
ogrencisayacı = ogrencisayaci + 1;
cout << “Geçenlerin sayısı: “ << gecenler << endl;
cout << “Kalanların sayısı: “ << kalanlar << endl;
if (gecenler > 8 )
cout << “BİR SONRAKİ KONUYA GEÇİLEBİLİR” << endl;
}
return 0;
Sonuç gir ( geçti için 1, kaldı
Sonuç gir ( geçti için 1, kaldı
Sonuç gir ( geçti için 1, kaldı
Sonuç gir ( geçti için 1, kaldı
Sonuç gir ( geçti için 1, kaldı
Sonuç gir ( geçti için 1, kaldı
Sonuç gir ( geçti için 1, kaldı
Sonuç gir ( geçti için 1, kaldı
Sonuç gir ( geçti için 1, kaldı
Sonuç gir ( geçti için 1, kaldı
Geçenlerin sayısı: 9
Kalanların sayısı: 1
BİR SONRAKİ KONUYA GEÇİLEBİLİR
için
için
için
için
için
için
için
için
için
için
2):
2):
2):
2):
2):
2):
2):
2):
2):
2):
1
1
1
1
1
1
2
1
1
1
TAVSİYE:
Bazı programcılar pseudocode ile algoritma geliştirmeyi zaman kaybı olarak görerek
doğrudan dil ile kodlamaya geçseler de bu yaklaşım basit ve bilinen problemler için
uygundur; karmaşık ve büyük projelerde çok ciddi hatalara yol açabilir.
ATAMA OPERATÖRLERİ
c = c + 3; şeklindeki bir atama cümlesi c += 3 şeklinde yazılabilir.
Bu ifadedeki += (toplama atama operatörü), sağ taraftaki değeri, sol taraftaki değere ekler
ve sonuc sol taraftaki değişkenin içine konur.
Diğer aritmetik atama operatörleri:
-=
*=
/=
%=
c -= 7;
b *= 5;
a /= 2;
d %= 4;
Filiz Eyüboğlu
c = c – 7;
b = b * 5;
a = a / 2;
d = d % 4;
YTÜ-BTB
20
Kaynak: Deitel&Deitel, C++ How To Program
ARTIRMA ve AZALTMA OPERATÖRLERİ
Birli (“unary”) operatörler - yani tek bir operandı olan.
++a
değeri kullan.
a++
artır.
--b
kullan.
b-azalt.
ön artırma operatörü
sonra artırma operatörü
a’yı 1 artır, sonra, a’nın bulunduğu ifadede bu yeni
a’nın bulunduğu ifadede a’nın mevcut değerini kullan; sonra a’yı 1
ön eksiltme operatörü
sonra eksiltme operatörü
b’yi 1 azalt; b’nin bulunduğu ifadede bu yeni değeri
b’nın bulunduğu ifadede b’nın mevcut değerini kullan; sonra b’yı 1
DİKKAT: Bu operatörleri yazarken operand ile arasında boşluk bırakılmamalıdır.
Aşağıdaki 3 atama cümlesi
gecenler = gecenler + 1;
kalanlar = kalanlar + 1;
Atama operatörleri kullanılarak şöyle yazılır:
gecenler += 1;
kalanlar += 1;
Ön artırma operatörleri ile
++gecenler;
++kalanlar;
şeklinde yazılır.
ŞU ANA KADAR GÖRDÜĞÜMÜZ OPERATÖRLERİN ÖNCELİK SIRASI
()
++ -- static cast<türü> ()
++ -- + * / %
multiplicative
+ << >>
insertion/extraction
< <= > >=
== !=
?:
= += -= *= /= %=
,
Filiz Eyüboğlu
soldan sağa
soldan sağa
parentez
unary (postfix)
sağdan sola
unary (prefix)
soldan sağa
soldan sağa
soldan sağa
soldan sağa
sağdan sola
YTÜ-BTB
additive
relational
soldan sağa
sağdan sola
assignment
soldan sağa
equality
conditional
comma
21
Kaynak: Deitel&Deitel, C++ How To Program
Aşağıdaki program parçasını inceleyelim:
// sayaç-kontrollu tekrar
#include <iostream>
using std::cout;
using std::endl;
int main()
{
int sayac = 1;
}
while (sayac <= 10)
{
cout << sayac << endl;
++sayac;
}
return 0;
Şekil: 2.16
Şekil 2.16’daki programda, s a y a c’a 1 atanarak başlanmış ve w h i l e cümlesine koşul
olarak ( s a y a c <= 10 ) konmuştur. Buna göre sayac = 11 olduğunda döngü biter.
Döngüden çıkışta sayac’ın değeri 11’dir.
s a y a c = 0 ile başlatılıp döngü şu şekilde yapılabilir:
while ( ++sayac <= 10)
cout << sayac << endl;
Bu tür kullanımda, sayac, while’daki koşul test edilmeden önce artırılır. Daha az satır
kodlama bakımından tercih edenler olabilir. Ancak bu yazış, deneyim gerektirdiği gibi
programı izleme, anlama, bakımı zorlaştırmaktadır. .
İYİ PROGRAMLAMA TAVSiYELERİ:
Her kontrol yapısından önce ve sonra okunabilirliği/anlaşılabilirliği sağlamak için birer boş
satır bırakınız.
Filiz Eyüboğlu
YTÜ-BTB
22
Kaynak: Deitel&Deitel, C++ How To Program
for TEKRAR YAPISI
Şekil 2.16’daki programı for kullanarak yazalım.
// for yapısı kullanarak
#include <iostream>
sayaç-kontrollu tekrar
using std::cout;
using std::endl;
int main()
{
// ilk değer atama, tekrar koşulu, artırma...herşey
// yapısının başlığında
for (int sayac = 1; sayac <= 10;
cout << sayac << endl;
}
f o r
sayac++)
return 0;
Şekil. 2.17 s.91
SIK YAPILAN HATALAR:
While ve for cümlelerinin koşulllarında yanlış bağıntısal operatörler ve/veya yanlış son
değerler kullanmak.
Örneğin, birden ona kadar sayılar yazdırılacaksa, sayac = 1 ile başlayıp, (sayac <= 10)
koşulu sınanmalıdır. Ancak çoğu kişi sayac = 0 ile başlayıp koşulu (sayac < 10) şeklinde
yazmayı tercih eder. İkide doğru. ANCAK İKİSİNİ BİRBİRİNE KARIŞTIRMAYIN!
for yapısının genel formatı:
for ( ilk değer atama; döngü devam koşulu; artırma )
cümle
İlk değer atama kısımında döngü kontrol değişkenine ilk değer ataması yapılır.
Dööngünün devam testi kısmında, döngünün devam koşulu sınanır.
Artırma kısmında da döngü kontrol değişkeni artırılır.
Daha anlaşılır olması bakımından pek çok durumda f o r yerine
ona denk şu w h i l e yapısı kullanılır.
ilk değer atama;
while ( döngü devam koşulu )
{
cümle
Filiz Eyüboğlu
YTÜ-BTB
23
Kaynak: Deitel&Deitel, C++ How To Program
artırma
}
SIK YAPILAN HATALAR:
s.93
for yapısının başlık kısmı içinde tanımlanıp değer atanan bir değişkeni, for’un gövdesi
dışında kullanmak. ANCAK bu kural özellikle eski C++ derleyicilerinde farklılıklar
gösterebilir. Bu bakımdan, taşınabilirlik için,
1- her
for
yapısında
farklı
bir
kontrol
değişkeni
kullanın
ya da
2- aynı değişkeni kullanmak birden fazla for yapısında kullanmak istiyorsanız, bu değişkeni
ilk for yapısının dışında ve yapıdan önce tanımlayınız.
for yapısının başlık bölümünde yer alan ilk değer atama ve artırma kısımlarında birden
fazla ifade yer alabilir, bu durumda bunlar virgül ile ayrılırlar. Yani ilk değer atama kısmında
birden fazla değişkeni tanımlayıp değer atayacaksanız bunlar virgülle ayrılırlar. Döngünün
devam koşuluna geçmek için noktalı virgül kullanılmalıdır. Devam koşulunun sınanmasından
sonra, artırma kısmına geçerken de arada noktalı virgül olmalıdır. Noktalı virgül yerine virgül
koymak yazım (syntax) hatasına yol açar.
İlk değer atamalarda sadece for için gerekli değişkenleri tanımlayınız. for dışında
kullanılacak değişkenleri for yapısının dışında tanımlayınız.
for yapısının başlık bölümünde yer alan 3 ifade seçimliktir; yani hepsinin konması gerekmez.
Örneğin döngü devam koşulu kaldırılırsa sonsuz döngü meydana gelir.
Artırma kısmı kaldırılıp, aşağıdaki ifadelerden biri kullanılarak for’un gövde kısmına
konabilir. Bu ifadeler birbirine denktir.
sayac = sayac + 1
sayac +- 1
++sayac
--------Æ sayac’ı bir artırıp gövdeyi çalıştırır.
sayac++ -----Æ gövdeyi çalıştırdıktan sonra sayac bir artırılır. Bu nedenle bu daha doğal bir
kullanımdır.
Önce veya sonra artırmadaki farklılık böyle bir kullanımda sorun yaratmaz çünkü s a y a c
değişkeni bir aritmetik ifadede yer almamaktadır.
for yapısının başlık bölümündeki 3 ifade (ilk değer atama; döngü devam koşulu; artırma)
aritmetik ifadeler içerebilir.
Örnek olarak, x=2 ve y=10 kabul edelim. Eğer x ve y döngünün gövdesinde
değiştirilmiyorsa şu iki cümle birbirine denktir:
for ( int j = x; j <= 4 * x + y; j += y / x)
for ( int j = 2;
j <= 80; j += 5)
NOT: - artırma kısmı negatif olabilir. Bu durumda kontrol değişkeninin değeri eksiltilerek
aşağı doğru sayma yapılmış olur.
Filiz Eyüboğlu
YTÜ-BTB
24
Kaynak: Deitel&Deitel, C++ How To Program
- for’a ilk başlayışta döngü devam koşulu yanlış ise, for’un gövdesi yürütülmez,
kontrol, for yapısından sonraki ilk cümleye geçer.
F o r yapısının akış şeması, w h i l e’ın akış şemasına benzer.
Örnek olarak:
f o r ( int j = 1; j <= 10; j++)
cout << j << endl;
j=1
doğru
j <= 10
Cout << j << endl;
j++
yanlış
Şekil. 2.19 s. 95
Tipik bir for tekrara yapısının akış şeması
for yapısı kullanan örnekler
a) kontrol değişkenini 1’den 100’e kadar 1 artırın.
for ( int i = 1; i <= 100; i++ )
b) kontrol değişkenini 100’den 1’e kadar –1 azaltın.
for ( int i = 100; i >= 1; i-- )
kontrol değişkeninin azaltma veya artma durumuna göre doğru bağıntısal operatörü
kullanmaya dikkat ediniz.
c) kontrol değişkenini 7’den 77’ye kadar 7’şer artırın.
for ( int i = 7; i <= 77; i += 7 )
d) kontrol değişkenini 20’den 2’ye –2’şer azaltın.
for (int i = 20; i >= 2; i-=2)
e) kontrol değişkenini 2,5,8,11,14,17,20 değerlerini alacak şekilde ayarlayın.
for (int j = 1; j <= 20; j += 3)
Filiz Eyüboğlu
YTÜ-BTB
25
Kaynak: Deitel&Deitel, C++ How To Program
f) kontrol değişkenini 99,88,77,66,55,44,33,22,11,0 değerleini alacak şekilde ayarlayın.
for ( int j = 99; j >= 0; j-=11 )
BASİT BİR PROGRAM
// 2’den 100’e kadar çift sayıların toplamı bulan program
#include <iostream>
using std::cout;
using std:: endl;
int main()
{
int toplam = 0;
for (int sayi = 2; say,i <= 100; sayi +=2 )
toplam += sayi;
cout << “Toplam = “ << toplam << endl;
return 0;
}
Toplam = 2550
Şekil. 2.20 s.96
for’un gövde kısmı, başlık kısmının içine alınarak şöyle de yazılabilirdi:
for (int sayi = 2;
sayi <= 100;
toplam += sayi;
sayi += 2)
// ilk değer ata
// devam koşulu
// toplamı oluştur
// kontrol değişkenini artır
ANCAK BU ŞEKİLDE – gövdeyi başlığın içine alarak - KODLAMAK PROGRAMIN
OKUNABİLİRLİĞİNİ AZALTMAKTADIR.
BAŞKA BİR for ÖRNEĞİ:
1000 lirasını %5’den yıllık faize yatıran bir kişinin, faiz ve anaparadan hiç çekmediğini
düşünürsek 10 sene sonra kaç lirası birikmiş olur.
a = p (1 + r)ⁿ
p: ilk yatırılan anaparanın miktarı
r: yıllık faiz oranı
n: yıl sayısı
a: n sene sonunda oluşan toplam para
•
•
for döngüsü 10 kez dönmeli
kontrol değişkeni birer birer artacak
Filiz Eyüboğlu
YTÜ-BTB
26
Kaynak: Deitel&Deitel, C++ How To Program
•
•
•
C++, üs alma operatörü içermediğinden pow standart kitaplık fonksiyonu kullanacağız.
pow (x,y) x’in y’ninci üssünü alır. x ve y double tanımlanmalıdır.
Bu programımızın çalışması için <cmath> dahil edilmelidir.
pow’un argümanı oalacak sene değişkeni tamsayıdır (int). Pow çalışırken int’i double’a
çevirerek geçici bir yere koyar.
Yukardaki formüle göre programda
Belirli bir senenin sonunda oluşan para = anapara * pow (1.0 + oran, sene) şeklinde hesaplanacatır.
DİKKAT:
Bilgisayarda 14.234 ve 18.673 olarak saklı olan iki para değeri, print işlemi esnasında setprecision(2)
belirtilmişse 14.23 ve 18.67 olarak yazılırlar. Bu değerler toplandığında siz sonucu 32.90 beklerken,
virgülden sonraki ve printte görmediğimiz 3.basamaktaki değerler nedeniyle toplam 32.91 olacaktır.
Bunun farkında olun. Para hesaplarına dikkat!
Faiz probleminin C++ ile kodlanması
// Bileşik faiz hesabı yapan program
#include <iostream>
using std::cout;
using std::endl;
using std::ios;
#include <iomanip>
using std::setw;
using std::setiosflags;
using std::setprecision;
#include <cmath>
int main()
{
double miktar,
anapara = 1000.0,
oran = .05;
// Çıktının başlığını yazdır
cout ( “SENE “ << setw (21) << HESAPTAKİ MİKTAR” << endl;
// set the floating-point number format
cout << setiosflags( iosfixed | ios::showpoint ) << setprecision (2);
for (int sene =1; sene <= 10; sene++)
{
miktar = anapara * pow (1.0 + oran, sene);
cout << setw (4) << sene << setw(21) << miktar << endl;
}
return 0;
}
Filiz Eyüboğlu
YTÜ-BTB
27
Kaynak: Deitel&Deitel, C++ How To Program
SENE
1
2
3
4
5
6
7
8
9
10
HESAPTAKİ MİKTAR
1050.00
1102.50
1157.62
1215.51
1276.28
1340.10
1407.10
1477.46
1551.33
1628.89
Şekil. 2.21 s. 98
switch YAPISI: ÇOKTAN SEÇME İÇİN (“multiple-selection”)
Anımsanacağı gibi if cümlesi tek bir koşulun doğru olma durumuna göre bir seçeneğin
(single-selection) yürütülmesini; if / else koşulun doğru veya yanlışlığına göre iki değişik
seçenekten (double selection) birinin yürütülmesini sağlıyordu. Zaman zaman algoritmamız
ikiden fazla seçeneğin sınanıp her bir seçenek için değişik işlerin yapılmasını gerektirebilir.
C++’da bu iş için switch yapısı kullanılır.
Örnek Program: Harf notlarının sayılması
// Harf notlarını sayan program
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
int
not,
sayacA = 0,
sayacB =
sayacC =
sayacD =
sayacF =
0,
0,
0,
0;
// A’ların sayısı
// B’lerin sayısı
// C’lerin sayısı
// D’lerin sayısı
// F’lerin sayısı
EOF, IBM
PC uyumlu
makinelerde
ctrl Z
cout << “Harf notlarını giriniz. “ << endl
<< Girdi sonunu belirtmek için EOF karakterini giriniz. “ <<
endl;
while (
( not = cin.get () ) != EOF )
cin.get() klavyeden girilen bir karakteri okur
ve not değişkenine koyar. Bu komutun
detayı konu 6’da...Not, integer bir değişken.
Aslında okunan karakterin, karakter bir
değişkene konması gerekirdi, ancak C++’in
çok önmeli bir özelliği karakterlerin
int değişkenlere atanmasına izin vermesidir.
{
switch (not)
Filiz Eyüboğlu
YTÜ-BTB
28
Kaynak: Deitel&Deitel, C++ How To Program
{
case ‘A’:
case ‘a’:
++sayacA;
break;
switch’den çıkmak için break gerekli
case ‘B’:
case ‘b’:
++sayacB;
break;
.........
.........
case ‘F’:
case ‘f’:
++sayacF;
break;
case ‘\n’:
case ‘\t’:
case ‘ ‘:
break;
}
cout
hepsini yazmadım
// ignore new lines,
// tabs,
// spaces in input
default:
// catch all other characters
cout << “Yanlış bir harf girdiniz. ”
<< “Yeni bir harf giriniz.” << endl;
}
<< “\n\nHER BİR HARF NOTUNDAN KAÇ TANE OLDUĞU: “
<< “\nA: “ << sayacA
<< “\nB: “ << sayacB
<< “\nC: “ << sayacC
<< “\nD: “ << sayacD
<< “\nF: “ << sayacF << endl;
return 0;
}
Harf notlarını giriniz.
Girdi sonunu belirtmek için EOF karakterini giriniz.
A
B
C
C
A
D
F
C
E
Yanlış harf girdiniz. Yani bir harf giriniz.
D
A
B
HER BİR HARF NOTUNDAN KAÇ TANE OLDUĞU:
A: 3
B: 2
C: 3
D: 2
F: 1
Şekil. 2.22 s. 101 switch örneği
Filiz Eyüboğlu
YTÜ-BTB
29
Kaynak: Deitel&Deitel, C++ How To Program
Yukarıda, karakterlerin tamsayı değişkenlere atanabildiğini gördük, çünkü her bir karakter 1
bayt yer tutar. Dolayısıyla, kullanım alanına göre, bir karaktere, bir tamsayı ya da bir karakter
muamelesi yapabiliriz. Örneğin,
cout << “ ‘a’ karakterin değeri:
“ << static_cast< int > (‘a’) << endl;
cümlesinin yazdığı satır aşağıdaki gibidir:
a karakterinin değeri: 97
---------- DENEMEDİM.....AMA static-cast’ı denediğim başka bir programda ÇALIŞMADI.
Static-cast’ın Turbo C++ version 3’deki karşılığını bulmak gerek.-------
do / while
TEKRAR YAPISI
do/while yapısı while yapısına benzemekle beraber fark şudur: while yapısında, döngü devam
koşulu döngünün başında sınanır. do/while yapısında ise, döngü devam koşulu döngü
yürütüldükten sonra sınanır. Buna göre döngü gövdesi içinde yer alan ifadeler en az bir kere
yürütülmüş olur. do/while bittiğinde, while’dan sonraki cümle yürütülür.
do/while yapısının gövdesi içinde tek bir cümle varsa gövdeyi paranteze almak gerekmez
(while ve for’daki gibi) , birden fazla cümle varsa parantez içine alınmalıdır (yoksa mantık
hatası oluşur). Ancak tek bir cümle bile olsa, do/while yapısında parantez kullanmak iyidir;
karışıklığı önlemek için. Yani
do
do
Cümle
{
while (koşul);
cümle
yerine
}
while (koşul);
SIK YAPILAN HATALAR
while, do/while ve for yapılarında döngü devam koşulunda sınanan kontrol değişkeninin
değeri , başlık veya gövde bölümlerinden birinde mutlaka değiştiriliyor olmalıdır. Kontrol
değişkenini değiştirmemek sonsuz döngüye neden olur.
// fig. 2.24 do/while yapısı
#include <iostream.h>
int main()
Filiz Eyüboğlu
YTÜ-BTB
Do/while’ın akış
şeması
s.107
fig.2.25
30
Kaynak: Deitel&Deitel, C++ How To Program
{
int sayac = 1;
do
{
}
cout << sayac << “ “ ;
while (++sayac <= 10);
cout << endl;
return 0;
}
1 2 3 4 5 6 7 8 9 10
break
ve continue CÜMLELERİ
break ve continue cümleleri kontrolun akışını (“flow of control”) değiştirirler. break
cümlesi; while, for, do/while, switch yapılarında kullanıldığında, yapıdan anında çıkmayı
sağlar; bu durumda kontrol, yapıdan sonraki ilk cümleye geçer (programın yürütülmesi bu
cümleyle devam eder).
Şekil. 2.26 f o r yapısı içinde b r e a k ‘in kullanımını göstermektedir.
// f o r
içinde b r e a k
#include <iostream.h>
kullanan program
int main()
{
int x;
for ( x = 1; x <= 10; x++ )
{
if (x==5)
break;
// break loop only if x is 5
}
}
cout << x << “ “;
cout << “\nBroke out of loop at x of “ << x << endl;
return;
1 2 3 4
Broke out of loop at x of 5
Şekil. 2.26 s. 108 Deitel
continue
cümlesi, while, for, do/while yapıları içinde kullanıldığında, gövdenin içinde
continue’dan sonra gelen cümleleri atlayarak, döngüye devam eder: kullanılmakta olan yapı
while veya do /while ise döngü devam koşulu sınanır, for ise, kontrol değişkeninin
artırım işlemi yapılır, sonra devam koşulu sınanır.
for ve continue kullanımına başka bir örnek:
// şekil.2.27
Filiz Eyüboğlu
f o r
ve
c o n t i n u e
YTÜ-BTB
kullanımına örnek
31
Kaynak: Deitel&Deitel, C++ How To Program
#include <iostream.h>
int main()
{
for ( x = 1; x <= 10; x++ )
{
if (x==5)
continue;
// skip the remaining code in loop only if x is 5
}
cout << x << “ “;
cout << “\n5’i yazmamak için c o n t i n u e kullanıldı. “ << endl;
return;}
1 2 3 4 6 7 8 9 10
şekil.2.27
5’i yazdırmamak için c o n t i n u e kullanıldı.
ÖNEMLİ NOT: Bazı programcılar break ve continue kullanımının yapısal programlamayı
ihlal ettiğini düşünürler. Esasen bu cümlelerin işlevleri, ilerde görceğimiz yapısal
programlama teknikleriyle sağlanabilir. Bu durumda, break ve continue kullanmaya gerek
kalmaz.
MANTIKSAL OPERATÖRLER
Şimdiye kadar basit koşulların nasıl ifade edildiğini (tek bir koşul) gördük: sayac <= 10 ,
toplam > 1000 , flag != 0 gibi. Birden fazla koşulu sınamak içinse içiçe if’ler veya if/else
yapıları kullanabileceğimizi gördük.
Daha karmaşık koşulların ifadesi için veya basit koşulların biraraya getirilmesi için C++,
mantıksal operatörler sağlar: && (mantıksal AND) ve || (mantıksal OR) ve
! (mantıksal NOT).
İki koşulun aynı anda doğru olması durumunda belirli bir işlem yapmak istiyorsak bu
koşulları mantıksal VE ile bağlayarak ifade etmeliyiz:
Örneğin:
if (cinsiyet == 1 && yas >= 65)
++grup1;
if’in başlığındaki koşul, ancak, && ile bağlanmış her iki koşul da doğruysa doğrudur.
((((( logical AND, OR, NOT biliniyor mu???? )))))
Mantıksal AND:
ifade1
ifade2
ifade1 && ifade2
yanlış
yanlış
doğru
yanlış
doğru
yanlış
yanlış
yanlış
yanlış
Filiz Eyüboğlu
YTÜ-BTB
32
Kaynak: Deitel&Deitel, C++ How To Program
doğru
doğru
doğru
SIK YAPILAN HATALAR:
3 < x < 7 şeklinde bir ifade, her ne kadar matematiksel olarak doğruysa da bunu C++’da
(3<x && x<7) şeklinde yazmak gerekir.
Mantıksal OR:
ifade1
ifade2
ifade1 || ifade2
yanlış
yanlış
doğru
doğru
yanlış
doğru
yanlış
doğru
yanlış
doğru
doğru
doğru
if (donem_ortalamasi <= 90 || final_notu >= 90 )
cout << “Ogrencinin notu: A “ << endl;
&& operatörünün, ||’ye göre önceliği vardır.
Soldan sağa işlem yapılır.
&& ve || içeren bir ifadenin doğruluğu ya da yanlışlığı kesin olarak belli olduğu anda daha
sağdaki ifadelerin değerlendirilmesinde gerek kalmaz. Örneğin,
if (cinsiyet == 1 && yas >= 65 ) ifadesinde cinsiyet bire eşit değilse yani birinci ifade yanlış
ise, yaş koşulunu sınamaya gerek yoktur çünkü && ile bağlı iki ifadeden biri yanlış ise tüm
ifadenin sonucu yanlış olacaktır.
Mantıksal NOT (“logical negation”)
ifade
!ifade
doğru
yanlış
yanlış
doğru
EŞİTLİK (==) ve ATAMA (=) OPERATÖRLERİNİN KARIŞMASI
Ne kadar deneyimli olursa olsun C++ programcıları zaman zaman atama operatörü = ile
eşitlik koşulu sınamasa kullanılan ==’ i birbirinin yerine kullanabilmektedirler. Böyle bir
hata durumunda program doğru olarak derlenmekte ancak yürütüldüğü zaman ya yanlış
sonuçlar veya mantık hatası vermektedir. Örneğin
if ( odeme_kodu == 4)
Filiz Eyüboğlu
YTÜ-BTB
33
Kaynak: Deitel&Deitel, C++ How To Program
cout << “ikramiye kazandınız!” << endl;
yerine
if (odeme_kodu = 4)
cout << “ikramiye kazandınız!” << endl;
kodladığınızı
düşünelim.
Hatırlanacağı gibi, if’in koşulunun doğru olması demek parantez içindeki kısımdan 1 (true –
doğru) dönmesi demektir. Ancak bu durumda if’in gövde kısmı yürütülür.
Örnekte ilk if’de (doğru kodlanmış olan) odeme_kodu 4 ise, koşul doğru (1) olur.
İkinci – yanlış - yazılanda ise bize problem yaratan C++’ın şu kuralıdır: Bir değer yaratan
herhangi bir ifade if kontrol yapısının karar kısmında kullanılabilir. Bu değer sıfır ise, yanlış
(“false”) olarak değerlendirilir, değer sıfırdan farklıysa doğru (“true”) olarak değerlendirilir.
Buna göre odeme_kodu = 4 atama cümlesi hem odeme_kodu’na 4 atayarak bunun orijinal
değerini bozar hem de sıfırdan büyük olduğu için if’in koşulunun her zanman doğru olması
sonucunu doğurur, buna göre de kişi her durumda ikramiye kazanır.
=Î ATAMA ve EŞİTLİK OPERATÖRLERİNE DİKKAT!!!!!!!
AYRICA, ATAMA CÜMLESİNDE, DEĞİŞKEN, = İŞARETİNİN SOL TARAFINDA
YER ALMALIDIR.
YAPISAL PROGRAMLAMA ÖZETİ
Sınfta yapılar tahtaya çizilerek anlatılacak.
A computer program is said to be structured if it has a modular design and uses only the three
types of logical structures:
1- sequences
2- decisions (decision structures: if / else, switch)
(repetition structures: for, do – while)
3- loops
Diğer bir tanım:
Structured programmimg is a technique for organizing and coding computer programs in
which a hierarchy of modules is used, each having a single entry point and a single exit point,
in which control is passed downward through the structure without unconditional branches to
higher levels of the structure.
*****
YILDIZ TEKNİK ÜNİVERSİTESİ
BİLGİSAYAR ve ÖĞRETİM TEKNOLOJİLERİ EĞİTİMİ BÖLÜMÜ
Filiz Eyüboğlu
YTÜ-BTB
34
Kaynak: Deitel&Deitel, C++ How To Program
DERS:
DERSİ VEREN:
SINIF:
DÖNEM:
PROGRAMLAMA DİLLERİ – 1
Öğr. Gör. Filiz Eyüboğlu
2
2002-2003 güz dönemi
TÜM DERS NOTLARI: www.bto.yildiz.edu.tr, ders notları linkinde. Bu notlar aşağıdaki
1.no.lu kaynaktan yararlanılarak hazırlanmıştır.
DİĞER KAYNAKLAR:
5. Deitel & Deitel. (2000). C++ How To Program. Third Edition. New Jersey: Prentice Hall
6. http://www.bups.bilkent.edu.tr/ibcomp/cpp/cpp.html
KONU 3: FONKSİYONLAR
HEDEFLER:
16- Fonksiyon kullanarak modüler programların nasıl oluşturulduğunu anlama
17- Fonksiyon yaratabilme
18- Fonksiyonlar arasında bilgi geçişini sağlayan mekanizmaları anlama
19- Rasgele sayı üretme benzetim tekniklerini tanıma
20- Kendisini çağıran fonksiyonları (“recursive function” = özyineli fonksiyonlar) yazmayı ve
kullanmayı öğrenme
İÇERİK:
C++’deki program bileşenleri
Matematik kitaplık fonksiyonları
Fonksiyonlar: fonksiyon tanımları, fonksiyon prototipleri
Başlık dosyaları (“header files”)
Rasgele sayı üretme
Bellek sınıfları (“storage classes”)
Kapsam kuralları (“scope rules”)
Özyineleme (“recursion”)
Özyineleme örneği: Fibonacci serisi
Yineleme - Özyineleme
Boş parametre listeli fonksiyonlar
Inline fonksiyonlar
Referanslar ve referans parametreleri
Varsayılan bağımsız değişkenler (“default arguments”)
“Unary scope resolution operator “
Function overloading
Fonksiyon şablonları (“function templates”)
C++’DA PROGRAM BİLEŞENLERİ
C++’daki modüller fonksiyon ve sınıf (“class”) olarak adlandırılır. C++’da program, C++’ın
standart kitaplığında yer alan ve önceden yazılmış fonksiyonlarla programcının yazdığı yeni
Filiz Eyüboğlu
YTÜ-BTB
35
Kaynak: Deitel&Deitel, C++ How To Program
fonksiyonlar birleştirilerek oluşturulur. C++ standart kitaplığı; matematiksel hesaplar, dizgi
(“string”) işlemleri giriş/çıkış işlemleri, hata kontrol etme, vb için çok sayıda fonksiyon
içerir.
TAVSİYE: C++ standart kitaplığındaki fonksiyonları tanıyarak mümkün olduğunca bunları
kullanınız; tekerleği yeniden keşfetmeyiniz.
Bunların dışında, programcı özel bir takım işlemler yapmak için fonksiyonlar yazar.
Fonksiyonu çağırmak yani program içinde bulunduğumuz noktada o fonksiyonu kullanmak
için bir fonksiyon çağrı cümlesi (“function call”) yazarız. Bu cümlede çağrılacak
fonksiyonun adı ve fonksiyona geçirilecek argümanlar belirtilir. Çağrılan fonksiyon
çalıştıktan sonra çağrıldığı noktaya fonksiyonun sonucunu döndürür (“return”). Çağrılan
fonksiyon da işini yapabilmek için başka fonksiyonlar çağırabilir.
Şekil. 3.1 hiyerarşik patron fonksiyonu / çalışan fonksiyonu ilişkisi - TAHTAYA ÇİZ
MATEMATİKSEL KİTAPLIK FONKSİYONLARI
Bunlar programcının bazı çok kullanılan matematiksel hesaplamaları yapmalarını sağlarlar.
Örneğin 900 sayısının karekökünü yazdırmak için
cout << sqrt (900.0); yazabiliriz.
Fonksiyonun adı: sqrt
Argüman: 900.0
sqrt fonksiyonunun argümanı d o u b l e olmalıdır.
ÖNEMLİ NOT: C++’nın matematiksel fonskiyonlarını kullanabilmek için bunları içeren
cmath başlık dosyası (“header file”) programın başında include ile dahil edilmelidir.
cl = 13.0
d = 3.0
f = 4.0 ise
cout << sqrt (cl + d + f)
cümlesi 5 değerini yazar. Parantez içindeki
toplamın sonucu 25.0’dır ve karekök 5.0 yapar. Ancak C++ noktadan sonraki sıfırları
basmadığından 5 olarak yazılır.
Sık kullanılan bazı matematiksel kitaplık fonksiyonları
Nasıl çağrılacağı
Anlamı
Örnek
ceil (x)
x’i, kendisinden büyük en küçük tamsayıya yuvarlar
cos (x)
x’in kosinüsü
ceil(9.2) = 10.0
ceil (-9.8)=-9.0
cos (0.0) = 1.0
exp (x)
exponential function e üzeri x
exp (1.0)=2.71828
fabs(x)
x’in mutlak değeri
fabs (-2.5)=2.5
floor(x)
x’i kensisinden küçük en büyük tamsayıya yuvarlar
floor (8.2)=8.0
floor(-9.8)=-10.0
fmod(x,y)
x/y’nin kalanı – kayan noktalı olarak
Filiz Eyüboğlu
YTÜ-BTB
36
Kaynak: Deitel&Deitel, C++ How To Program
log (x)
x’in doğal logirtması (e tabanına göre)
log (2.71828)=1.0
log10(x)
x’in 10 tabanına göre logaritması
pow(x,y)
x üzeri y
log10(10.0)= 1.0
log10(100.0)=2.0
pow(2,7)=128
pow(9, .5)=3
sin (x)
sqrt (x)
tan (x)
x’in sinüsü
x’in karekökü
x’in tanjantı
İYİ PROGRAMLAMA İÇİN TAVSİYE:
Programcının yazacağı her bir fonksiyon, iyi tanımlanmış, tek bir iş yapmalı ve fonksiyonun
adı bu işlevi ifade edecek biçimde verilmelidir.
Örnek: Programcı tarafından yazılmış (“programmer-defined”) bir fonksiyon
// şekil. 3.3
#include <iostream.h>
int kare (int);
//function prototype
int main()
{
for (int x = 1; x <= 10; x++)
cout << kare (x) << “ “;
}
cout << endl;
return o;
// kare alma fonksiyonunun tanımı
int kare (int y);
{
return y * y;
}
1 4 9 16 25 36 49 64 81 100
Şekil. 3.3 s. 162
Fonksiyon prototipinde yani int kare ( int ) ‘de, parantez içindeki int derleyiciye
bu fonsiyon çağrılırken tamsayı bir argümanla çağrılması gerektiğini bildirir. Fonksiyon
adının sol tarafındaki int ise, kare fonksiyonunun çağrıldığı noktaya yollacağı sonucun
tamsayı olması gerektiğini belirtir.
Mavi renkle yazılmış olan fonksiyon tanımı main()’den önce yer alabilir. Bu durumda,
fonksiyon prototipine gerek kalmaz. (s.163)
Bir fonksiyon tanımının formatı şöyledir:
Geri-dönecek-değerin-veri-türü
{
Filiz Eyüboğlu
fonksiyon-adı ( parametre-listesi )
YTÜ-BTB
37
Kaynak: Deitel&Deitel, C++ How To Program
}
tanımlamalar ve cümleler
Geri-dönecek-değerin-veri-türü kısmına
değer döndürmeyecek anlamına gelir.
void
yazılırsa, bu, fonksiyon herhangi bir
SIK YAPILAN HATALAR:
- fonksiyon tanımında parantezden sonra noktalı virgül koymak
- fonksiyon içinde fonksiyon tanımlamak
- fonksiyon prototipi, fonksiyon çağrı cümlesi ve fonksiyon tanımının argüman ve
parametrelerin sayısı, sırası, ve veri türü bakımından ve geri dönen sonucun veri türü
bakımından uyuşmaması
- fonksiyon parametresini yerel bir değişken olarak fonksiyon içinde tanımlamak
İYİ PROGRAMLAMA İÇİN TAVSİYELER:
- anlamlı fonksiyon ve parametre isimleri seçiniz.
- karışıklığı önlemek için fonksiyonun çağrıldığı argümanlar ile fonksiyonun parametreleri
için farklı isimler kullanınız
- Program küçük fonksiyonlar topluluğu olarak tasarlanırsa, yazması, hata ayıklaması,
bakımı kolay olur.
Fonksiyonun Sonucunun Fonksiyonun Çağrıldığı Yere Döndürülmesi
- fonksiyon her hangi bir sonuç döndürmüyorsa
- fonksiyon sonuç döndürecekse
return;
return ifade :
Örnek: maximum fonksiyonu
// sekil 3.4 programmer-defined maximum function
#include <iostream.h>
int enbuyuk (int, int, int);
// fonksiyon prototipi
int main()
{
int a,b,c;
cout << “ üç tamsayı giriniz: “;
cin >> a >> b >> c;
cout << “Girilen sayıların en büyüğü: “ << enbuyuk (a,b,c) <<
endl;
return 0;
}
// fonksiyon tanımı
int enbuyuk (x,y,z)
{
max = x;
Filiz Eyüboğlu
YTÜ-BTB
38
Kaynak: Deitel&Deitel, C++ How To Program
if (y
max
if (z
max
>
=
>
=
max)
y;
max)
z;
return max;
}
Üç tamsayı giriniz: 22 85 17
Girilen sayıların en büyüğü: 85
Şekil. 3.4 s.166
FONKSİYON PROTOTİPLERİ
C++’nın en önemli özelliklerindendir. Fonksiyon prototipi, derleyiciye, fonksiyonun adını,
fonksiyon tarafından döndürülecek verinin türünü, fonksiyonun kabul edeceği parametrelerin
sayısını, parametrelerin türünü ve parametrelerin kabul ediliş sırasını söyler. Derleyici,
fonksiyon çağrı cümlelerini doğrulamak için prototipte verilen bilgileri kullanır. C’nin eski
sürümlerinde bu kontrol yoktu ve bu çok ciddi hatalara yol açıyordu.
Yukardaki örnekteki fonksiyon prototipi int enbuyuk (int,int,int); ‘den fonksiyonun adının
enbuyuk olduğunu, 3 parametresi olduğunu; bunların tamsayı olduğunu ve fonksiyonun
döndüreceği sonucun da tamsayı olduğunu anlıyoruz.
DÖNÜŞTÜRME KURALLARI
sqrt(x) fonksiyonunun argümanının double olması gerektiğini daha önce söylemiştik. Ancak,
sqrt (4) yazdığımızda da sonuç 2 olarak bize döner. Burada C++ tamsayı bir veriyi double’a
dönüştürerek işlem yapar. double veya float bir veri de tamsayıya (gerekiyorsa) C++
tarafından dönüştürülür, ancak burada dikkat edilmesi gereken double veya float verinin
noktadan sonra küsurat kısmı varsa tamsayıya dönüştürüldüğünde küsuratın yok olacağıdır.
Benzer şekilde uzun tamsayıları kısa tamsayılara dönüştürme de değerlerin değişmesiyle
sonuçlanabilir. Dolayısıyla dönüştürme işlemlerinde C++ yükseltme kuralları (“promotion
rules”) takip edilmezse yanlış sonuçlar ortaya çıkabilir.
Değişik veri türleri içeren karışık bir ifadede de yükseltme kuralları uygulanır. İfadede yer
alan veri türleri ifadedeki en yüksek düzeydeki veri türüne yükseltilir. Bu işlemler esnasında
orijinal değer aynı kalır, yükseltilecek değerin konması için bellekte geçici bir yer açılır.
Aşağıda, en yüksekten en düşüğe kadar veri türlerinin hiyerarşisi verilmiştir:
Veri türü
long double
Filiz Eyüboğlu
YTÜ-BTB
39
Kaynak: Deitel&Deitel, C++ How To Program
double
float
unsigned long int
long int
unsigned int
int
unsigned short int
short int
unsigned char
char
bool
(unsigned long ile aynı)
(long ile aynı)
(unsigned ile aynı)
(unsigned short ile aynı)
(short ile aynı)
yanlış 0, doğru 1 olur
Şekil. 3.5 Promotion hierarchy for built-in data types
Daha önce yazdığımız kare fonksiyonu - tamsayı parametre kullanıyordu – kayan noktalı
(floating-point) argümanla çağrılırsa, floating-point argüman daha düşük seviyeli olan int’e
dönüştürülür ve bu nedenle kare (4.5) şeklinde bir çağrı 20.25 yerine 16 sonucunu
döndürür.
BUNA GÖRE: yüksek seviyeli bir türü daha alçak seviyeli bir türe
dönüştürürseniz yanlış değerler elde edebilirsiniz.
BAŞLIK DOSYALARI (“Header Files”)
Her standart kitaplıkta, bu kitaplıktaki fonksiyonlara ait fonksiyon prototipleri içeren başlık
dosyaları bulunur.
Şekil 3.6 C++ programlarınıza dahil edebileceğiniz bazı çok kullanılan C++ standart kitaplık
başlık dosyalarını listelemektedir. C++’IN DEĞİŞİK SÜRÜMLERİNDE BU BAŞLIK
DOSYALARININ ADLARI FARKLI OLABİLMEKTEDİR.
BTB BİLGİSAYAR
LABORATUARINDAKİ BİLGİSAYARLARDA KURULU Turbo C++ Version 3’de GEÇERLİ
BAŞLIK DOSYA ADLARI – OLASILIKLA - SAĞ KOLONDA YAZILI OLANLAR
OLABİLİR. DENEYİNİZ/ARAŞTIRINIZ.
Standart kitaplık
başlık dosya adı
<cassert>
<cctype>
<cfloat>
<climits>
<cmath>
<cstdio>
<cstdlib>
<cstring>
<ctime>
<iostream>
<iomanip>
<fstream>
<utility>
Filiz Eyüboğlu
Açıklama
eski C++ sürümlerinde
Hata ayıklama ile ilgili makroları içerir.
<assert.h>
karakterleri test etmeyle ilgili fonksiyonlar
<ctype.h>
floating-point büyüklük limitlerini içerir.
<float.h>
Integral büyüklük limitlerini içerir.
<limits.h>
Matematik fonksiyonları içerir.
<math.h>
Standart giriş/çıkış kitaplık fonksiyonları ve bunlar
tarafından kullanılan bilgiler
<stdio>
sayıları texte, texti sayılara dönüştürme, rasgele sayı
üretme, bellek tahsis etmeyle ilgili fonksiyonlar
<stdlib.h>
string işleme fonksiyonları
<string.h>
zaman ve tarih ile ilgili fonksiyonlar
<time.h>
standart giriş / çıkış işlemleri
<iostream.h>
stream manipulators that enable formatting
of streams of data.
<iomanip.h>
disk dosyalarına giriş, çıkış yapan fonksiyonlar
<fstream.h>
pek çok standart kitaplık başlık dosyaları tarafından
kullanılan fonksiyon ve sınıflar
YTÜ-BTB
40
Kaynak: Deitel&Deitel, C++ How To Program
.... devamı ss. 169-170 şekil. 3.6
RASGELE SAYI ÜRETME (“random number generation”)
Şimdi, oyun ve benzetim uygulamalarında çokça kullanılan rasgele sayı üretme konusuna
bakalım.
i = rand (); yazdığımızda rand
fonksiyonunun ürettiği rasgele bir sayı i değişkenine
atanmış olur. rand sıfır ile <cstdlib.h> başlık dosyasında belirtilmiş olan maksimum değer
arasında rasgele bir sayı üretir. Ancak, eğer bir zar atma programı yazıyorsak rasgele gelecek
sayının 1 ile 6 arasında olmasını isteriz. Yazı tura atılması gerekiyorsa 0 ve 1 üretilmelidir.
0 ile 5 arasında bir sayı üretmek için
rand () % 6 yazmamız gerekir. Bu, ölçekleme (“scaling”)olarak adlandırılır. Üretilen
sayıya bir ekleyerek 1 ile 6 arasında sayılar elde etmiş oluruz.
// 1 ile 6 arasında sayı üreten program
#include <iostream.h>
#include <stdlib.h>
int main()
{
for (int i = 1; i <= 20 ; i++ )
{
cout << setw (10) << (1 + rand() % 6);
if ( i % 5 == 0)
cout << endl;
}
return 0;
}
5
2
5
5
5
4
3
1
3
2
2
4
5
5
2
6
5
5
1
4
Zarın 6000 kere atılmasının benzetimini yapan bir program yazalım. Ve her bir rakamdan kaç
tane geldiğini yazalım.
Filiz Eyüboğlu
YTÜ-BTB
41
Kaynak: Deitel&Deitel, C++ How To Program
// Altı yüzlü zarın 6000 kere atılması ve gelen sayıların sayısını
// bulan program
#include <iostream.h>
#include <stdlib.h>
int main()
{
int sayi1 = 0, sayi2 = 0, sayi3 = 0,
sayi4 = 0, sayi5 = 0, sayi6 = 0,
face;
for ( int atis = 1; atis <= 6000; atis++ )
{
face = 1 + rand() % 6;
switch (face )
{
case 1:
++sayi1;
break;
case 2:
++sayi2;
break;
case 3:
++sayi3;
break;
case 4:
++sayi4;
break;
case 5:
++sayi5;
break;
case 6:
++sayi6;
break;
default: cout << “program hiç buraya gelmemeli aslında!”;
}
}
cout << “Zarın Yüzü” << setw (13) << “Kaç kere geldiği”
<< “\n
1” << setw (13) << sayi1
<< “\n
2” << setw (13) << sayi2
<< “\n
3” << setw (13) << sayi3
<< “\n
4” << setw (13) << sayi4
<< “\n
5” << setw (13) << sayi5
<< “\n
6” << setw (13) << sayi6 << endl;
return 0;
}
Zarın Yüzü
1
2
3
Filiz Eyüboğlu
Kaç kere geldiği
987
984
1029
YTÜ-BTB
42
Kaynak: Deitel&Deitel, C++ How To Program
4
5
6
974
1004
1022
rand function actually generates pseudo-random numbers. Calling rand repeatedly produces a
sequence og numbers to be random. However, the sequence repeats itsef each time the
program is executed. Once a program has been thoroughly debugged, it can be conditioned to
produce a different sequence of random numbers for each execution. This is called
randomizing, and it is accomplished with the standard library function srand.
Function srand takes an unsigned int argument and seeds the rand function to produce
a different sequence of random numbers for each execution of the program.
// Şekil.3.9 – randomizing the die-rolling program
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
//yeni sürümlerde <cstdlib>
int main()
{
unsigned seed;
cout << “seed değerini giriniz: “;
cin >> seed;
srand (seed);
for (int i=1; i<= 10; i++)
{
cout << setw (10) << 1 + rand () % 6;
if (i % 5 == )
cout << endl;
}
return 0;
}
seed değerini giriniz: 67
1
6
5
5
6
3
seed değerini giriniz: 432
4
2
6
2
5
1
seed değerini giriniz: 67
1
6
5
5
6
3
1
1
4
2
4
4
3
4
1
1
4
2
Her defasında seed değeri girmeden değişik rasgele sayılar seti üretmek isterseniz
srand( time ( 0 ) );
Filiz Eyüboğlu
YTÜ-BTB
43
Kaynak: Deitel&Deitel, C++ How To Program
şeklinde bir cümle kullanabilirsiniz. 0 argümanı ile time fonksiyonun döndürdüğü değer
‘takvim zamanının’ saniye cinsinden değeridir. Bu, unsigned int’e çevrilerek seed olarak
kullanılır. Time fonksiyonunun fonksiyon prototipi <ctime.h> başlık dosyasındadır.
SIK YAPILAN HATALAR: Rand fonksiyonu yerine srand kullanmaya kalkışmak.
Bu, syntax (yazım ) hatası verir; çünkü srand, programa değer döndüren bir fonksiyon
değildir.
ÖRNEK 3.9 s.176 Bir şans oyunu ( enum kullanarak )
enum Status {DEVAM, KAZANDI, KAYBETTI};
cümlesi
kullanıcı-tanımlı bir tür (“user-defined type) yaratır. Örnekte bu türün adı Status’dür. Status
türünün alabileceği değerler DEVAM, KAZANDI ve KAYBETTI’dir. Bunlara “enumaration
constants” denir. Başka hiçbir belirtim yazpılmaz ise DEVAM’ın değeri 0, KAZANDI’nın
değeri 1, KAYBETTI’nın değeri 2 olarak kabul edilir. Status veri türüne bu üç değerden
başka değer atanamaz. Diğer bir örnek
Enum Aylar {OCAK=1, SUBAT,MART,NISAN,MAYIS, HAZIRAN, TEMMUZ,
AGUSTOS, EYLUL, EKIM, KASIM,ARALIK}
OCAK=1 verildiğinden SUBAT=2........ARALIK=12 olur.
TAVSİYE:
Diğer değişkenlerle ve veri türleriyle karıştırılmaması bakımında kullanıcı-tanımlı veri
türlerinin ilk harfini büyük harf yapınız.
Enumaration sabitlerini programın açık ve net olması bakımından büyük harflerle yazınız.
BELLEK SINIFLARI (“storage classes”)
Şimdiye kadar gördüğümüz değişkenlerin dört özelliği (“attribute”) vardı: ismi, türü,
büyüklüğü, değeri. Ancak esasında bir değişkenin bunlardan daha fazla özelliği vardır. Bunlar
• bellek sınıfı (“storage class”)
• kapsam (“scope”)
• “linkage”dir.
C++ beş bellek sınıfı sağlar: auto, register, extern, mutable, static.
(mutable – konu 21’de, diğerlerini aşağıda göreceğiz)
Bir değişkenin kapsamı bu değişkenin programın hangi kısımlarında kullanılabileceğini
gösterir (where the identifier can be referenced in the program).
Linkage ise değişkenin sadece mevcut programda mı ya da birden fazla program içinde de mi
kullanılabileceğini belirtir.
Filiz Eyüboğlu
YTÜ-BTB
44
Kaynak: Deitel&Deitel, C++ How To Program
Bir değişkenin bellek sınıfı değişkenin bellekte bulunma peryodunu belirler. Bu bölümde biz
2 bellek sınıfı göreceğiz: otomatik ve statik.
Otomatik bellek sınıfındaki değişkenleri tanımlamak için auto ve register anahtar sözcükleri
kullanılır. Bu özellikteki değişkenler tanımlı oldukları bloğa girildiğinde tanımlanır ve blok
boyunca varolup, bloğun yürütülmesi bitince yok edilirler. Örneğin bir fonksiyonun yerel
değişkenleri ve parametreleri...
auto int x,y;
auto, default olduğundan yazılmasına gerek yoktur ve genelde
yazmayız zaten.
auto yerine, register olarak belirtim koyarsak bu değişkenler ana bellek yerine register’larda
tutulurlar; bunlara erşim çok hızlı olur. Ancak derleyicinin kullanımı için yeterli sayıda
register yoksa register yazmış olsak bile değişken bellekte tutulur.
NOT: register kullanımı genellikle gereksizdir. Günümüzün derleyicileri sık kullanılan
değişkenleri tanıyıp bunları zaten register’lara koyarlar.
Statik bellek sınıfında yer alan değişken ve fonksiyonlar
tanımlanırlar.
extern
veya
static
ile
Global değişkenler extern olarak tanımlanır. Bunlar prorgam boyunca geçerlidirler; sadece
bir blokta değil.
Yerel (“local”) değişkenler
static olarak tanımlanır. Bunlar, fonksiyona girildiğinde
tanımlanırlar, fonksiyon bittiğinde kullanılamaz olurlar ama değerlerini muhafaza ederler ve
fonksiyona bir sonraki girişte o değerler geçerli olur.
KAPSAM KURALLARI (“scope rules”)
İdentifier’ın anlamının olduğu program parçasına, kapsam denir. Örneğin bir fonksiyon içinde
yerel bir değişken tanımladığımızda bu değşişken sadece o fonksiyon içinde tanımlı ve
anlamlıdır. Fonksiyon dışında anlamı yoktur; kullanılmaz. Bu durumda o değişkenin kapsamı
o fonksiyondur.
Dört çeşit kapsam vardır:
• fonksiyon kapsamı
• dosya kapsamı
• blok kapsamı
• fonksiyon prototipi kapsamı
Her hangi bir fonksiyonun dışında tanımlanan değişkenin kapsamı tüm programdır ve bu,
dosya kapsamı olarak adlandırılır. Böyle bir değişken programın içindeki tüm fonksiyonlarda
geçerlidir; kullanılabilir.
Etiketler (“labels” start: den sonra konan) sadece yazıldığı fonksyonda geçerlidir.
Bunların kapsamı fonksiyondur. Yani fonksiyon dışından bunlara atıfta bulunulamaz.
Etiketler, switch yapıları içinde ve goto cümlelerinde kullanılırlar.
Bir bloğun içinde tanımlanan değişkenlerin kapsamı o bloktur. Blok { ile başlayan ve } ile
biten yapıdır. İçiçe blokların olduğu durumda dıştaki ve içteki blokta aynı adlı değişkenler
Filiz Eyüboğlu
YTÜ-BTB
45
Kaynak: Deitel&Deitel, C++ How To Program
tanımlandıysa iç blokta dış bloğun aynı adlı değişkeni geçerli olmaz; bu iç blok boyunca dış
bloğun değişkeninn değeri “saklanmış” durumdadır.
Fonksiyon prototipinde – anımsanacağı gibi- parametrelerin veri türleri belirtiliyordu. Bu
parametrelerin adlarının yazılması gerekmez ancak yazanlar olabilir ancak bu durumda
derleyici bu isimleri dikkate almaz, yok sayar. Bu durumda bu isimlerin kapsamı fonksiyon
prototipidir.
YAPILAN HATALAR: dış blokta tanımlı bir değişkenin iç blokta da geçerli olmasını
istiyorsanız bu değişken iç blokta tanımlanmamalı. Tanımlanırsa bu artık başka bir
değişkendir. Bu da programınızda mantık hatasına yol açar.
=Î dış ve iç blokta farklı işlerde kullanılacak değişkenlere aynı adı vermeyin.
ÖRNEK: KAPSAM KURALLARI
// şekil 3.12 a scoping example
#include <iostream>
void a ( void );
void b ( void );
void c ( void );
// fonksiyon prototipi
// fonksiyon prototipi
// fonksiyon prototipi
int x = 1;
// global değişken
int main ()
{
int x = 5 ;
// main’in yerel değişkeni
cout << “main’in dış bloğundaki x’in değeri = “ << x << endl;
{
int x = 7 ;
cout << “main’in iç bloğundaki x’in değeri = “ << x << endl;
}
cout << “main’in dış bloğundaki x’in değeri = “ << x << endl;
a();
b();
c();
a();
b();
c();
//
//
//
//
//
//
a fonksiyonunun otomatik yerel x’i var
b fonksiyonunun statik yerel x’i var
c fonksiyonu global x’i kullanıyor
a, otomatik yerel x’e yeniden ilk değerini atar
b, statik yerel x değeri muhafaz etmektedir
gloabl x de değerini muhafaza etmektedir.
cout << “main’in yerel x değişkeninin değeri = “ << x << endl;
}
return 0;
void a ( void);
{
int x = 25;
// a’nın her çağrılışında
x’e 25 atanır.
cout << endl << a’ya girişte, a’daki yerel x= “ << x << endl;
++x;
cout << a’dan çıkmadan önce,
Filiz Eyüboğlu
a’daki yerel x= “ << x << endl;
YTÜ-BTB
46
Kaynak: Deitel&Deitel, C++ How To Program
}
void b ( void);
{
static int x = 50; // b’ye sadece ilk girişte statik
// ilk değer atama yapılır.
cout << endl << b’ye girişte, b’deki statik yerel x= “ << x << endl;
++x;
}
cout << b’den çıkmadan önce,
b’daki statik yerel x= “ << x << endl;
void c ( void);
{
cout << endl << c’ye girişte, global x = “ << x << endl;
++x;
}
cout << c’den çıkarken
global x= “ << x << endl;
PROGRAMIN ÇIKTISI, S. 184’DE
ÖZYİNELEME (“recursion)
Şimdiye dek gördüğümüz programlar genellikle birbirini çağıran fonksiyonlar şeklinde
yapılandırılmış programlardı. Bazı problemler için kendisini çağıran fonksiyonlar
kullanışlıdır. Özyineli bir fonksiyon (“a recursive function”) doğrudan veya dolaylı olarak
kendisini çağıran bir fonksiyondur. Bu konu bilgisayar bilimiyle ilgili daha üst sınıflarda
oldukça uzun ve ayrıntılı okunan bir konudur. Bu bölümde, biz, özyinelemenin birkaç
örneğini göreceğiz.
Örnek: negatif olmayan bir n sayısının faktöriyeli (n!) = n (n-1)(n-2)(n-3)......1
Özyineli olmayan biçimde (“iterative”)
factoriyel = 1;
for (int sayac = sayi; sayac >=1; sayac--)
faktoriyel *= sayi;
olarak kodlayabiliriz.
Faktöriyel fonksiyonunun özyineli (“recursive”) tanımı ise şöyle ifade edilir: n! = n (n –1 )!
Örneğin
5! = 5 . 4 . 3 . 2 . 1
5! = 5 . 4!
5 faktöriyeli bulmak için çağıracağımız fonksiyon bu hesabı yapmnak için 4!’ye gereskinim
duyar ve kendisini 4 ile çağırır. 4! için 3!’e gereksinimimiz vardır, aynı fonksiyon 3 ile
çağrılır.......(şekil. 3.13 s 186 kitapta). Programı yazacak olursak:
// Recursive factorial function
s.186
// sıfırdan ona kadar sayıların faktöriyellerini bulan program
Filiz Eyüboğlu
YTÜ-BTB
47
Kaynak: Deitel&Deitel, C++ How To Program
#include <iostream>
#include <iomanip>
unsigned long faktoriyel(unsigned long ); // function prototype
int main()
{
for ( int i = 1; i <= 10; i++ )
cout << setw (2) << i << “! = “ << faktoriyel (i) << endl;
return 0;
}
// recursive definition of function factorial
unsigned long faktoriyel( unsigned long sayi )
{
if ( sayi < = 1 )
// base case – temel durum
return 1;
else
return sayi * faktoriyel(sayi – 1);
}
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
şekil.3.14 s.187
6! = 720
7! = 5040
8! = 40320
9! = 362880
10!= 3628800
Programda, unsigned long kullandık. Bilindiği gibi bu, unsigned long int’in kısaltılmış hali.
C++ dilinde, unsigned long int değişkenler 4 bayt yani 32 bitle temsil edilirler. 32 bitle
gösterilebilecek sayılar 0 – 4294967295’dir.
Long int değişkenler de 32 bitle gösterilirler. Long int ile temsil edilebilen en küçük ve en
büyük sayılar artı/eksi 2147483647’dir. Programımızın çıktısından görüleceği gibi faktöriyel
sonucu çok büyük olabilir. N değeri arttıkça faktöriyle çok büyük bir hızla artar. Bunun için
unsigned long int kullandık. Bazı durumlarda bu bile yetmeyebilir. Î double daha iyi bir
seçim.....Ayrıca, C++ daha da büyük sayıları temsil etmemize imkan sağlar.
SIK YAPILAN HATALAR: Özyineleme adımını veya temel durumu (faktöriyel
fonksiyonunda 0! ve 1! için 1 döndürülmesi) yanlış yazmak. Bu durumda fonksiyon temek
duruma yaklaşamaz ve sonsuz döngüye girerek belleği tüketir.
Diğer bir özyineleme örneği: Fibonnaci Serisi
0, 1, 1, 2, 3, 5, 8, 13, 21, ......
Sıfır ve birden sonraki her sayı kendisinden önce gelen 2 sayının toplamıdır. Birbirini takip
eden iki Fibonnacci sayısının oranı 1.618...’e yaklaşır. Bu oran mimarlar, ressamlar, vb
arasında "altın oran"”denilen orandır. Bu oran insanlara estetik gelen orandır (pencere ve
kapıların en – boy oranları gibi).
SINIFA SOR: Fibonnacci serisini özyineli olarak tanımlayınız:
fibon(0) = 0
Filiz Eyüboğlu
YTÜ-BTB
48
Kaynak: Deitel&Deitel, C++ How To Program
fibon(1) = 1
fibon(n) = fibon(n – 1) + fibon(n – 2)
Program:
// şekil. 3.15 s. 189
// i. Fibonnaci sayısını özyineli olarak bulan program
#include <iostream>
unsigned long fibon( unsigned long );
int main()
{
unsigned long sonuc, sayi;
cout << “bir tamsayı giriniz: “;
cin >> sayi;
sonuc = fibon(sayi);
cout << “Fibonnacci(“ << sayi << “) = “ << sonuc << endl;
return 0;
}
// recursive definition of function fibon
unsigned long fibon( unsigned long n)
{
if ( n == 0 || n == 1 )
// base case
return n;
else
return fibon(n-1) + fibon (n-2);
}
Bir sayı giriniz: 0
Fibonnacci(0) = 0
Bir sayı giriniz: 1
Fibonnacci(1) = 1
Bir sayi giriniz: 2
Fibonnacci(2) = 1
Bir sayi giriniz: 3
Fibonnacci(3) = 2
Bir sayı giriniz: 4
Fibonnacci(4) = 3
Bir sayı giriniz: 5
Fibonnacci(5) = 5
Bir sayı giriniz: 6
Fibonnacci(6) = 8
Bir sayı giriniz: 10
Fibonnacci (10) = 55
Bir sayı giriniz: 30
Fibonnacci(30) = 832040
Filiz Eyüboğlu
YTÜ-BTB
49
Kaynak: Deitel&Deitel, C++ How To Program
f(3)
f(2)
f(1)
+
return 1
+
f(0)
f(1)
return 1;
şekil.3.16
s.191
return 0
ÖZYİNELEME (“recursion”) - YİNELEME (“iteration”)
Geçtiğimiz bölümlerde özyineli ve yineli şekilde yazılabilen iki fonksiyon gördük. Iterasyon,
bir tekrar yapısı kullanır, özyineleme seçme yapısı kullanır. Özyineleme’de, tekrar,
fonksiyonun tekrar tekrar kendisini çağırmasıyla gerçekleştirilir. Iterasyon, döngü devam
koşulu yanlış olduğu zaman biter; özyineleme temel duruma gelindiğinde biter.
Özyineleme, yinelemeye göre çok daha fazla bellek alanaı ve işlemci zamanı harcar. Daha
fazla bellek alanı harcar çünkü fonksiyonu her çağırışta fonksyonun bir kopyası (fonksiyonun
değişkenlerinin bir kopyası) yaratılır. Peki o zaman neden özyinleme kullanırız?
•
bazı problemleri özyineli biçimde ifade etmek ve kodlamak anlaşılabilirliği artırır.
Anlamak, takip etmek kolaydır.
ANCAK, performans önemliyse, özyineleme kullanmaktan kaçınmak gerekir.
PARAMETRE LİSTESİ BOŞ OLAN FONKSİYONLAR
(“functions with empty parameter lists”)
C++’da boş parametre listeli fonksiyonlar, parantez içi boş bırakılarak veya void yazılarak
belirtilir.
Fonksiyonun, çağrıldığı noktaya döndürdüğü bir değer de yoksa fonskiyon adının baş tarafına
(sol) yine void sözcüğü yazılır.
void yazdir();
yazdir fonksiyonun her hangi bir argüman almadığını ve geriye değer döndürmediğini ifade
eder.
// şekil. 3.18 s. 194
// argümanı olmayan fonksiyon
#include <iostream>
void function1();
void function2( void );
int main();
{
function1();
function2();
Filiz Eyüboğlu
YTÜ-BTB
50
Kaynak: Deitel&Deitel, C++ How To Program
return 0;
}
void function1();
{
cout << “Fonksiyon1’in hiç argümanı yok.” << endl;
}
void function2 ( void );
{
cout << “Fonksiyon2’nin de hiç argümanı yok.” << endl;
}
Fonksiyon1’in hiç argümanı yok.
Fonksiyon2’in de hiç argümanı yok.
NOT: Fonksiyonlar kullanarak program yazmak, hiyerarşik ve anlaşılabilir bir yapı
oluşturması bakımından, iyi
yazılım mühendisliği örneğidir. ANCAK, çok sayıdaki
fonksiyon çağırma cümlesi yürütme zamanını artıran bir etkendir.
**** BU DERSTE ZAMANI AZALTMAYA ÇALIŞMAK YERİNE; ANLAŞILABİLİR,
FONKSİYON KULLANAN – MODÜLER - PROGRAMLAR YAZMAYI ÖĞRENİYORUZ .
ÖDEV ve SINAVLARDA BUNA DİKKAT EDİNİZ ****
INLINE FONKSİYONLAR
Fonksiyon çağırmanın işlemciye yük (“overhead”) getirdiğinden bahsettik. Bunu aşmak için
C++ “inline” fonksiyonlar sağlar; özellikle küçük fonksiyonlar için. İnline sözcüğü ile
belirtilen fonksiyonlar için çağrı yapılmaz; oldukları yerde fonksiyonunun bir kopyası
yaratılır; bu da esasında programın büyüklüğünü artırır. Örnek brir program aşağıda.
// şekil 3.19 s 196
// kübün hacmini inline fonksiyon kullanarak hesaplayan pgm
#include <iostream>
inline double cube( const double s) { return s * s * s; }
int main()
{
cout << “Kübün bir kenar uzunluğunu giriniz: “;
double kenar;
}
cin >> kenar;
cout << “Kenari “ << kenar << “olan kübün hacmi = “
<< cube (kenar) << endl;
return 0;
CALL-BY-VALUE - CALL-BY-REFERENCE
Filiz Eyüboğlu
YTÜ-BTB
51
Kaynak: Deitel&Deitel, C++ How To Program
(değer ile çağırma – referans ile çağırma)
Şimdiye kadar çağırdığımız fonksiyonlara argüman gönderirken argümanın değerini
gönderdik (“call-by-value”). Geçirilen değer çok büyükse bunun fonksiyona geçirilmesi
zaman alıcı olabilmektedir. Bu sorunu yok etmek için referans parametreleri kavramını
göreceğiz ve “call-by-value” yerine “call-by-reference” yapmayı öğreneceğiz. Bu
yaklaşımda, fonksiyona, argümanların adresleri yollanır; fonksiyon o değere doğrudan o
adresi kullanarak erişir; call-by-value’da olduğu gibi yollanan değişkenlerin kopyalarını
tutmak için bellekte ayrı yer tahsis edilmez.
NOT: “Call-by-reference can weaken security, because the called function can corrupt the
caller's data”.
SIK YAPILAN HATALAR: Because reference parameters are mentioned only by name in
the body of the called fucntion, the programmer might inadvertently treat reference
parameters as call-by-value parameters. This can cause unexpected side-effects if the original
copies of the variables are changed by the calling function.
Değer ile (“call-vy-value”) ve Referans parametreleriyle çağırma (“call-by-reference”)
örneği:
//şekil. 3.20 s.198 Comparing call-by-value and call-by-reference
#include <iostream.h>
int squareByValue ( int );
void squareByReference ( int & );
int main()
{
int x = 2, z = 4;
cout << “squareByValue’dan önce ” << “x= “ << x << endl
<< “squareByValue’dan dönen değer “ << squareByValue( x ) << endl
<< “squareByValue’dan sonra “ << “x = “ << x << endl;
cout << “squareByReference’dan önce ” << “z= “ << z << endl;
squareByReference( z );
cout << “squareByReference’dan sonra “ << “z = “ << z << endl;
return 0;
}
int squareByValue( int a )
{
return a *= a; //çağıranın argümanı değiştirilmez
}
void squareByReference( int &cRef )
{
cRef *= cRef; // çağıranın argümanı
// değiştirilmiş olur
}
Şöyle okunur:
“CRef is a reference to an int”.
Reference parameter is an
alias for its corresponding
squareByValue’dan önce x = 2
Filiz Eyüboğlu
YTÜ-BTB
52
Kaynak: Deitel&Deitel, C++ How To Program
squareByValue’dan dönen değer = 4
squareByValue’dan sonra x = 2
squareByReference’dan önce z = 4
squareByReference’dan sonra z = 16
Şekil: 3.20 s. 198
Referens parametresi ( & ile tanımlanan), orijinal değişken için bir takma addır (“alias”).
Takma ad üzerinde yapılan her işlem, aslında orijinal değişken üzerinde yapılmış olur.
Örneğin:
int sayac = 1;
int &ref = sayac;
++ref;
//tamsayı değişken sayacı tanımla, 1 ata
// ref, sayac için takma addır
// sayac 1 artırılmış olur.
Örnek: using an initialized reference – ilk değer atanmış referans kullanımı (aşağıda)
(((( ÇIKTIYI SINIFA SOR ))))
// şekil. 3.21
#include <iostream>
int main()
{
int x = 3, &y = x;
//
y,
x
için
takma addır.
cout << “x = “ << x << endl << “y = “ << y << endl;
y = 7;
cout << “x = “ << x << endl << “y = “ << y << endl;
}
x
y
x
y
return 0;
=
=
=
=
3
3
7
7
SIK YAPILAN HATALAR:
1- Birden fazla referans değişkeni tanımlarken her birinin başına & koymamak.
Örneğin, doğru yazım olan int &x=a, &y=b, &z=c; yerine
int& x=a, y=b, z=c; yazmak.
2- Tanımlandığı yerde referans değişkenine değer atamamak.
Yani
int x = 3, &y; y’ye değer atanmadığı için hata verir.
3- Bir değişkene takma ad olarak tanımlanmış bir referans değişkenini başka bir değişkene
takma ad olarak vermeye kalkışmak.
VARSAYILAN BAĞIMSIZ DEĞİŞKENLER (“default arguments”)
Filiz Eyüboğlu
YTÜ-BTB
53
Kaynak: Deitel&Deitel, C++ How To Program
Fonksiyon çağrı cümleleri, fonksiyona, genellikle, argümanlar için belirli değerler geçirirler.
Bunlara “argümanların varsayılan değerleri” diyoruz. Bu değerler, herhangi bir argüman için
özellikle bir değer geçirmediğimiz zaman varsayılan (default) değeri alarak çalışırlar.
Örnek: default argümanların kullanımı
// şekil. 3.23 s. 201
#include <iostream>
int kutununhacmi( int boy = 1, en = 1, yuksekil = 1);
int main()
{
cout << “Varsayılan kutu hacmi: “ << kutununhacmi()
<< “\n\nBoy=10, en=1, yükseklik=1 olduğunda \n”
<<”kutunun hacmi: “ <<
kutununhacmi(10),
<< “\n\nBoy=10, en=5, yükseklik=1 olduğunda \n”
<< “kutunun hacmi: “ <<
“kutununhacmi(10,5)
<< “\n\nBoy=10, en=2, yükseklik=2 olduğunda \n”
<< “kutunun hacmi: “ << kutununhacmi(10,5,2) << endl;
return 0;
}
// kutunun hacmi fonksiyonu
int kutununhacmi(int boy, int en, int yukseklik)
{
return boy * en * yukseklik;
}
Varsayılan kutu hacmi: 1
Boy=10, en=1, yükseklik=1 olduğunda
Kutunun hacmi: 10
Boy=10, en=5, yükseklik=1 olduğunda
Kutunun hacmi: 50
Boy=10, en=5, yükseklik=2 olduğunda
Kutunun hacmi: 100
TAVSİYE: Varsayılan değerlere bırakmak yerine, TÜM argümanları açıkça ifade etmek
anlaşılabilirliği artırır.
ÇOK ÖNEMLİ AÇIKLAMA: Varsayılan değerleri almasını istediğimiz için çağrı
cümlesine yazmayacağımız argümanlar, ancak parantezin içinde en sağdakiler olmalıdır.
“unary scope resolution operator”
Global ve yerel değişkenleri aynı isimle tanımlamak mümkün olabilir.C++’da tekli kapsam
operatörü (“unary scope resolution operator”) iki adet iki nokta üstüste :: , kapsam içinde
aynı adlı bir yerel değişken varken global değişkene erişmeyi sağlar. Bu operatör, dış blokta
tanımlı ve aynı adlı yerel bir değişkene erişmeyi ise sağlamaz. Tekli kapsam operatörünün
kullanımına örnek aşağıdaki programda verilmiştir.
// şekil 3.24 s.203 using the unary scope resolution operator
Filiz Eyüboğlu
YTÜ-BTB
54
Kaynak: Deitel&Deitel, C++ How To Program
#include <iostream.h>
#include <iomanip.h>
const double PI = 3.14159265358979;
int main()
{
const float PI = static_cast< float >( ::PI );
cout << setprecision(20)
<< “ Yerel (float) PI’ın değeri= “ << PI
<< “\nGlobal (double) PI’ın değeri= “ << ::PI << endl;
}
return 0;
Borland C++ derleyicisinin çıktısı
Yerel (float) PI’ın değeri = 3.141592741012573242
Global (double) PI’ın değeri = 3.141592653589790007
MS Visual C++ derleyicisinin çıktısı
Yerel (float) PI’ın değeri = 3.1415927410125732
Global (double) PI’ın değeri = 3.14159265358979
Şekil. 3.24 s 203 using the unary scope resolution operator
İYİ PROGRAMLAMA TAVSİYESİ: Bir programda aynı isimli değişkenleri değişik amaçlarla
kullanmaktan kaçının.
FONKSİYONA YENİ ANLAM YÜKLEME (“function overloading”)
C++, parametre sayıları, türleri vb farklı olduğu müddetçe, aynı isimle birden çok
fonksiyonun tanımlanmasına izin verir. Buna “function overloading” denir. Yeni anlam
yüklenmiş bir fonksiyon çağrıldığında, C++ derleyicisi, çağrı cümlesindeki argümanların
sayısını, türünü ve sırasını inceleyerek doğru fonksiyonu seçer. Bu özellik genellikle değişik
veri türleri üzerinde benzer işler yapan fonskiyonlar yaratmada kullanılır.
Şekil 3.25’deki program, int olarak tanımlanmış bir sayının karesini ve double olarak
tanımlanmış bir sayının karesini almak üzere yükleme yapılmış kare fonksiyonunu
göstermektedir.
//şekil 3.25 s.204
#include <iostream.h>
int kare( int x ) { return x * x; }
double kare ( double y ) { return y * y;}
int main()
{
cout << “7’nin karesi= “ << kare ( 7 )
<< “\n7.5’un karesi= “ << kare (7.5)
<< endl;
return 0;
}
Filiz Eyüboğlu
YTÜ-BTB
55
Kaynak: Deitel&Deitel, C++ How To Program
7’nin karesi= 49
7.5’un karesi= 56.25
SIK YAPILAN HATALAR: Parametre listeleri tamamen aynı fakat geri döndürecekleri
değerin türü (“return type”) farklı olacak biçimde yüklenmiş (“overloaded”) fonksiyon
tanımlamaya çalışmak yazım hatası verir.
YILDIZ TEKNİK ÜNİVERSİTESİ
BİLGİSAYAR ve ÖĞRETİM TEKNOLOJİLERİ EĞİTİMİ BÖLÜMÜ
DERS:
DERSİ VEREN:
SINIF:
DÖNEM:
PROGRAMLAMA DİLLERİ – 1
Öğr. Gör. Filiz Eyüboğlu
2
2002-2003 güz dönemi
TÜM DERS NOTLARI: www.bto.yildiz.edu.tr, ders notları linkinde. Bu notlar aşağıdaki
1.no.lu kaynaktan yararlanılarak hazırlanmıştır.
DİĞER KAYNAKLAR:
7. Deitel & Deitel. (2000). C++ How To Program. Third Edition. New Jersey: Prentice Hall
8. http://www.bups.bilkent.edu.tr/ibcomp/cpp/cpp.html
KONU 4: DİZİLER
HEDEFLER:
21- Veri türlerinden dizi’yi tanımak
22- Listeleri ve tabloları saklamak, sıralamak ve arama yapmak için dizilerin kullanımını
anlamak
23- Dizileri tanımlamayı, ilk değer atamayı, dizinin elemanlarına erişmeyi anlamak
24- Fonksiyonlara dizileri geçirebilmek
25- Temel sıralama (“sorting”) tekniklerini öğrenmek
26- Çoklu indisli dizileri tanımlayabilmek ve kullanabilmek
İÇERİK:
Dizileri tanımlama
Dizi kullanımına örnekler
Fonksiyonlara dizileri geçirmek
Sıralama algoritmaları
Filiz Eyüboğlu
YTÜ-BTB
56
Kaynak: Deitel&Deitel, C++ How To Program
Arama algoritmaları: lineer arama, ikili arama (“binary search”) teknikleri
Çoklu indisli diziler
DİZİLER
Bu konuda çok önemli veri yapılarından biri olan dizileri öğreneceğiz. Diziler ve daha ileride
göreceğimiz “structure”lar statik yapılardır; yani, boyutları program boyunca aynı kalır. Daha
ilerki konularda ele alınan listeler, kuyruklar, ağaçlar ise dinamik veri yapılarıdır; bunların
boyutları programın yürütülmesi boyunca değişirler (azalır veya artar)
Dizi, aynı adı taşıyan ve aynı tür olan bir grup bellek yerine verilen addır. Aşağıda 5 elemanlı
bir dizi görüyorsunuz.
C[0]
C[1]
C[2]
C[3]
C[4]
-45
6
0
72
1543
.
Her dizinin ilk elemanı sıfırıncı elemandır. Buna göre, c dizinin ilk elemanı c[0] ile, ikinci
elemanı c[1] ile, .....gösterilir. Köşeli parantez içindeki pozisyon numarası “subscript” olarak
adlandırılır. Subscript, tamsayı veya tamsayı üreten bir ifade olmalıdır. c[ a + b ] += 2; gibi.
Bu cümle, a=5, b=6 ise, c’nin 11.elemanına 2 sayısını ekler.
Dizideki ilk üç elemanında yer alan değerlerin toplamını yazdırmak için:
cout << c[0] + c[1] + c[2] << endl; yazabiliriz.
SIK YAPILAN HATALAR:
“Dizinin 7.elemanı” ile “dizi elemanı 7”nin farklı olduğuna dikkat ediniz. Dizinin 7.elemanı
indisi 6 olan yerde bulunur (indis sıfırdan başladığı için). Dizi elemanı 7 ise, indisin 7
olduğunu gösterir; bu pozisyonda dizinin sekizinci elemanı yer alır.
DİZİLERİN TANIMLANMASI (“declaring arrays”) ve KULLANIMI
int c[12];
12 elemanlı c dizisini tanımlar.
int b[100], x[27];
Diziler sadece tamsayı elemanlar içermezler. Bir dizi char türünde de tanımlanabilir (bkz.
chapter 5 Deitel).
Örnek: dizinin elemanlarına ilk değer atama
// şekil 4.3 initializing an array
#include <iostream>
#include <iomanip>
int main()
{
int i, n[10];
Filiz Eyüboğlu
YTÜ-BTB
57
Kaynak: Deitel&Deitel, C++ How To Program
for ( i = 0; i < 10; i++ )
n[i] = 0;
// initialize array
cout << “Eleman” << setw(13) << “Değeri” << endl;
for ( i = 0; i < 10; i++ )
cout << setw(6) << i << setw(13) << n[i] << endl;
}
return 0;
Eleman
0
1
2
3
4
5
6
7
8
9
Değeri
0
0
0
0
0
0
0
0
0
0
Bir dizinin elemanlarına ilk değer ataması, dizi tanımlanırken de yapılabilir.
int n[10] = {0}; Bu tanımlamada sadece bir sıfır olduğundan, esasında bu sıfır dizinin
birinci elemanına atanır. Atama değerleri, dizinin eleman sayısından az olduğunda geri kalan
elemanlara sıfır değeri atanır. Buna göre n dizisinin 10 elemanına da sıfır atanmış olur. Tüm
elemanlara sıfır atanmasını istiyorsak en azından birinciye biz sıfır atamasını açıkça
yapmalıyız.
int a[10] = {1}; tanımında a dizisinin elemanlarına atanan ilk değerleri söyleyiniz.
Dizinin eleman sayısından daha fazla atancak değer belirtildiği durumda da derleyici yazım
hatası verir. Örneğin:
int b [5] = { 32, 27, 34, 56, 12, 98 }; dizinin 5 elemanı var; oysa 6 ilk değer verilmiş.
İlk değer atama listesiyle yapılan dizi tanımlama cümlesinde, dizinin eleman sayısı
belirtilmzse (köşeli parantezin içi boş bırakılarak), dizinin, atama değerlerinin sayısı kadar
elemanı olur.
int n[] = {12,23,45,56,78}; n dizinin eleman sayısı beştir.
NOT: dizi elemanlarına programın yürütülme zamanında (“at execution time”) atama
cümleleriyle ilk değer atamak yerine, tanımlama cümlesinde atama listesi kullanmak
performansı artırır; çünkü bu atamalar derleme zamanında (“at compile time”) yapılır.
Filiz Eyüboğlu
YTÜ-BTB
58
Kaynak: Deitel&Deitel, C++ How To Program
BİR ÖRNEK: Şekil.4.5’deki program 10 elemanlık s dizisine 2,4,6,…..,20 değerlerini atar
ve liste şeklinde yazdırır.
// şekil. 4.5
s.245
Bu bir sabit değişken tanımı. Sadece
okunan , değiştirilemeyen bir tür.
Dikkatinizi
çektiği
gibi,“sabit
değişken” ifadesi
“oxymoron”
denen çelişkili ifadelere bir örnek!
(yakıcı bir soğuk gibi…)
#include <iostream>
#include <iomanip>
int main()
{
const int dizibuyuklugu = 10;
int j, s[dizibuyuklugu];
// dizi elemanlarına 0,2,4,6,8,…,20 değerlerini koy
for ( j = 0; j < dizibuyuklugu; j++ )
s[ j ] = 2 + 2 * j;
cout << “Dizi Elemanı” << setw(13) << “Değeri” << endl;
NEDEN
DİZİNİN
BÜYÜKLÜĞÜ
İÇİN SABİT
DEĞİŞKEN
KULLANDIK?
ÖNEMLİ
*****
// dizinin eleman no ve her elemanın değerlerinin yazdır
for ( j = 0; j < dizibuyuklugu; j++ )
cout << setw(6) << j << setw(12) << s[ j ] << endl;
return;
}
Dizi Elemanı
0
1
2
3
4
5
6
7
8
9
Şekil 4.5 s. 246
Filiz Eyüboğlu
Değeri
2
4
6
8
10
12
14
16
18
20
Generating values to be placed into elements of an array
YTÜ-BTB
59
Kaynak: Deitel&Deitel, C++ How To Program
İYİ PROGRAMLAMA TAVSİYESİ: dizi büyüklüğünü tanımlarken sabit değişken
kullanınız. Bu, programı hem daha okunaklı yapar hem de dizi büyüklüğünün değişmesi
gerektiğinde programda sadece bir tek yerde değişiklik yapmak yeterli olur. Sabit değişken
yerine sabit bir sayı kullansaydık, örneğin 10, 10’u 100 yapmak gibi bir gereklilik
doğduğunda programda pek çok yerde 10’u değiştirmemiz gerekirdi.
Başka bir örnek: Dizinin elemanlarının toplamını bulan program
// şekil. 4.8
s.249
#include <iostream>
int main()
{
const int dizibuyuklugu = 12;
int a[dizibuyuklugu]= {1,3,5,4,7,2,99,16,45,67,89,45 };
int toplam = 0;
for ( i = 0; i < dizibuyuklugu; i++ )
toplam += a[ i ] ;
cout << “Dizi elemanlarının değerlerinin toplamı = “ << toplam <<
endl;
return 0;
}
Dizi elemanlarının değerlerinin toplamı = 383
Şekil 4.8 s.249
Başka bir örnek: bir ankette toplanan verilerin özetlenmesi
Kırk öğrenciye yemeklerin kalitesiyle ilgili bir soru soruldu. 1-10 arasında yanıt verdiler. Bu
kırk yanıtı bir tamsayı diziye yerleştiriniz ve sonucu özetleyiniz.
// şekil. 4.9 s. 249
// anket sonuçlarını özetleyen program
#include <iostream>
using std::cout;
using std::endl;
Filiz Eyüboğlu
YTÜ-BTB
60
Kaynak: Deitel&Deitel, C++ How To Program
#include <iomanip>
using std::setw;
int main()
{
const int yanitsayisi = 40; frekanssayisi = 11;
int yanitlar[ yanitsayisi ] = {
1,2,6,4,8,5,9,7,8,10,1,6,3,8,6,10,3,8,2,7,6,5,7,68,6,7,
5,6,6,5,6,7,5,6,4,8,6,8,10};
int frekans[frekanssayisi] = { 0 };
for (int yanit = 0; yanit < yanitsayisi; yanit++)
++frekans[ yanitlar[ yanitsayisi ] ];
cout << “Verilen Not” << setw(15) << “Frekans” << endl;
for ( int i = 1; i < frekanssayisi; i++)
cout << setw (6) << i << setw(15) << frekans[i] << endl;
}
return 0;
Puan
1
2
3
4
5
6
7
8
9
10
Frekans
2
2
2
2
5
11
5
7
1
3
NOT: dizinin sınırları dışında bir elemana atıfta bulunmaya kalkıştığınızda C++ sizi uyarmaz.
Örneğin frekans[12]’yi 1 artırmak isterseniz (12, frekans dizisinin sınırları dışında) uyarı
almazsınız. Bu nedenle dikkatli olunuz!.
ÖRNEK: Histogram basan program
// şekil 4.10 s. 252
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::setw;
int main()
{
Filiz Eyüboğlu
YTÜ-BTB
61
Kaynak: Deitel&Deitel, C++ How To Program
const int dizibuyuklugu = 10;
int n[dizibuyuklugu ] = {19,3,15,7,11,9,13,5,17,1};
cout << “Eleman” << setw(5) << “Değer” << setw (5) << “Histogram”
<< endl;
for (int i = 0; i < dizibuyuklugu << i++)
{
cout << setw(5) << i << setw(5) << n[ I ] << setw(5);
for ( int j = 0; j < n[ 1 ]; j++)
cout << ‘*’;
cout << endl;
}
}
return 0;
Eleman
0
1
2
3
4
5
6
7
8
9
Değer
19
3
15
7
11
9
13
5
17
1
Histogram
*******************
***
***************
*******
***********
*********
*************
*****
*****************
*
ÖRNEK:
// şekil 4.11 s. 253
// alti yüzlü zarı 6000 kere atıp hangi yüzün kaç kere geldiğini
// bir diziye yerleştiren pgm
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::setw;
int main()
{
const int dizibuyuklugu = 7 ;
int yuz, frekans[ dizibuyuklugu ] = { 0 };
srand ( time( 0 ) );
for ( int atis = 1; atis <= 6000; atis++)
++atis[ 1 + rand() % 6 ];
cout << “Yüz”
<< setw(5) << “Frekans” << endl;
// dizinin sıfırıncı elemanını dikkate alma
for ( yuz = 1; yuz < dizibuyuklugu; yuz++ )
cout << setw(2) << yuz << setw(5) << frekans[ yuz ] << endl;
Filiz Eyüboğlu
YTÜ-BTB
62
Kaynak: Deitel&Deitel, C++ How To Program
}
Yüz
1
2
3
4
5
6
return 0;
Frekans
1037
987
1013
1028
952
983
KARAKTER DİZİLER
Karakter bir dizi, her bir elemanına karakterler konabilen dizidir. Örneğin
char a[] = “ahmet”;
a dizisinin elemanlarına ahmet dizgisindeki (“string”) her bir karakteri koyar. Yani
yukarıdaki tanımlama ile şu aynıdır:
char a[] = { ‘a’, ‘h’, ‘m’, ‘e’, ‘t’, ‘\0’ };
boş karakterinin karakter gösterimidir (“character representation of null character).
Tüm dizgiler (“string”) bu karakter ile biterler.
‘\0’
Bir string, karakterlerden meydana gelmiş bir dizidir. Bu nedenle stringin bir elemanına
dizilerde oldugu gibi indis kullanarak erişiriz. Yukarıdaki örnekle ilgili olarak a[3] ‘e’
karakterini gösterir
char string1 [ 20 ];
19 karakter saklama kapasitesindeki bir diziyi tanımlar.
Neden 19 ???????
cin >> string1; dediğimiz zaman klavyeden bir karakter dizgisi okunur. Ve
sonuna \0 boş karakteri eklenir. Dizi sınırları ile klavyeden girilecek/okunacak karakter
dizgisinin uyuşmasını sağlamak programcının sorumluluğundadır. Diziniz daha küçük
tanımlanmış bile olsa daha uzun bir dizgi buna okunur ancak mantık hatalarına yol açar ve
farketmesi güç olabilir.
Bir dizgiyi cin ile okuduğumuz gibi cout ile de yazdırırız.
cout << string1 << endl; gibi. Burada da cin de olduğu gibi C++ dizinin
tanımlama esnasında verilmiş olan büyüklüğüne aldırış etmeden dizide \0 karakterini görene
kadar tüm elemanları yazar.
BİR ÖRNEK:
// şekil 4.12 s. 255
// karakter dizilere dizgi gibi muamele etmek
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include <iomanip>
Filiz Eyüboğlu
YTÜ-BTB
63
Kaynak: Deitel&Deitel, C++ How To Program
using std::setw;
int main()
{
char dizgi1[ 20 ], dizgi2[] = “nasilsiniz?”;
cout << “Bir dizgi giriniz: “;
cin >> dizgi1;
cout << “Girilen dizgi: “ << dizgi1”;
cout << “\nProgramda değer atanan dizgi: “ << dizgi2;
cout << “\nGirilen dizginin karakterleri arasına * koyarak oluşturulmuş
dizgi:\n”;
for ( int i = 0; dizgi1[ I ] != ‘\n’; i++)
cout << dizgi1[ I ] << ‘*’;
return 0;
}
Bir dizgi giriniz: Merhaba
Girilen dizgi: Merhaba
Programda değer atanan dizgi: Nasılsınız?
Girilen dizginin karakterleri arasına * koyarak oluşturulmuş dizgi:
M*e*r*h*a*b*a*
3.konuda bellek sınıflarında static tanımını görmüştük. Anımsayacağınız gibi, static
olarak tanımlanan bir değişken ancak tanımlı olduğu fonksiyon veya blok içinde
kullanılabilir ancak tüm program boyunca varlığını korur; yani fonksiyon veya bloktan
çıkılınca yok olmaz, değerini korur.
Diziler de static olarak tanımlanabilir. Bunlara programcı açıkça ilk değer ataması yapmaz
ise yaratıldıkları anda derleyici tarafından sıfırlarla doldurulurlar.
Aşağıdaki programda 2 fonksiyon vardır:
1- statikdizitanimla 2-otomatikdizitanimla
// şekil 4.13 s. 256
// static diziler sıfırla doldurulurlar
#include <iostream>
using std::cout;
using std::endl;
void statikdizitanimla( void );
void otomatikdizitanimla( void );
int main()
{
cout << “Fonksiyonların ilk çağırılışı:\n”;
statikdizitanimla();
otomatikdizitanimla();
cout << “Fonksiyonlarin ikinci çağırılışı:\n”;
statikdizitanimla();
otomatikdizitanimla();
cout << endl;
}
return 0;
Filiz Eyüboğlu
YTÜ-BTB
64
Kaynak: Deitel&Deitel, C++ How To Program
// statik yerel bir diziyi gösteren fonksiyon
void statikdizitanimla( void ;
{
static int dizi1[ 3 ];
int i;
cout << “\nstatikdizitanimla’ya girişte değerler:\n”;
for ( i = 0; i < 3; i++)
cout << “dizi1[“ << i << “] = “ << dizi1[ i ] << “ “;
cout << “nfonksiyondan çıkarken değerler:\n”;
for ( i = 0; i < 3; i++)
cout << “dizi1[“ << i << “] = “ << (dizi1[ i ] += 5 ) << “ “;
}
// otomatik yerel diziyi gösteren fonksiyon
void otomatikdizitanimla( void )
{
int I, dizi2[ 3 ] = { 1, 2, 3 };
cout << “\notomatikdizitanimla’ya girişte değerler:\n”;
for ( i = 0; i < 3; i++)
cout << “dizi2[“ << i << “] = “ << dizi2[ i ] << “ “;
cout << “nfonksiyondan çıkarken değerler:\n”;
for ( i = 0; i < 3; i++)
cout << “dizi2[“ << i << “] = “ << (dizi2[ i ] += 5 ) << “ “;
}
Fonksiyonların ilk çağrılışı:
statikdiziye
dizi1[0] = 0
Fonksiyondan
dizi1[0] = 5
girişte değerler:
dizi1[1] = 0 dizi1[2] = 0
çıkışta değerler:
dizi1[1] = 5 dizi1[2] = 5
otomatikdiziye girişte değerler:
dizi2[0] = 1 dizi2[1] = 2 dizi2[2] = 3
Fonksiyondan çıkışta değerler:
Dizi2[0] = 6 dizi2[1] = 7 dizi2[2] = 8
Fonksiyonların ikinci çağrılışı:
statikdiziye girişte değerler:
dizi1[0] = 5 dizi1[1] = 5 dizi1[2] = 5
Fonksiyondan çıkışta değerler:
dizi1[0] = 10 dizi1[1] = 10 dizi1[2] = 10
otomatikdiziye girişte değerler:
dizi2[0] = 1 dizi2[1] = 2 dizi2[2] = 3
Fonksiyondan çıkışta değerler:
Dizi2[0] = 6 dizi2[1] = 7 dizi2[2] = 8
ÖNEMLİ NOT: Bir fonksiyonun static dizisinin fonksiyon her çağrıldığından sıfırlarla
doldurulduğunu varsaymak mantık hatalarına yol açar.
Filiz Eyüboğlu
YTÜ-BTB
65
Kaynak: Deitel&Deitel, C++ How To Program
DİZİLERİN FONKSİYONLARA GEÇİRİLMESİ
int a [20 ];
şeklinde tanımlanmış bir diziyi diziyidegistir isimli bir fonksiyona argüman olarak
yollayacaksak bu fonksiyonu çağrı cümlesi şöyle yazılır:
diziyidegistir( a, 20 );
C++ dizileri fonksiyonlara “call-by-reference” ile geçirir; yani fonksiyona yollanan dizinin ilk
elemanının adresidir. Bu demektir ki, fonksiyon, dizinin elemanlarının değerlerini değiştirirse,
bu değişiklik orijinal dizide yapılmış olur; dizinin başka bir kopyası üzerinde değil.
Bir diziyi parametre olarak alacak bir fonksiyon tanımı aşağıdaki gibi yazılabilir (yukardaki
örnek için)
void diziyidegistir( int b[], int diziboyutu )
Köşeli parantez içine dizinin boyutunu yazmak gerekmez; yazılırsa, derleyici bunu yok sayar;
dikkate almaz.
Aynı tanım şöyle de yapılabilir:
void diziyidegistir( int [], int )
Aşağıdaki örnek, bir fonksiyona tüm diziyi geçirmekle tek bir dizi elemanını geçirmek
arasındaki farkı göstermektedir. Fonksiyona bir dizinin tümü geçirildiğinde C++ call-byreference kullanır; yani fonksiyonda dizinin yeni bir kopyası açılmaz; orijinal dizi
üzerinde işlem yapılır. Orijinal dizi üzerinde işlem yapmamak yani orijinal diziyi bozmamak
istiyorsak call-by-value kullanmamız gerekir ki bunun yolu dizi elamanlarını tek tek
geçirmektir – bu da uzun ve prtaik olmayan bir yoldur.
// şekil 4.14 s. 259
// dizileri ve dizi elemanlarını fonksiyonlara geçirmek
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::setw;
void diziyidegistir( int [], int );
void elemanidegistir( int );
int main()
{
const int diziboyutu = 5;
int i, a [ diziboyutu ] = {0, 1, 2, 3, 4 };
cout << “call-by-reference ile tüm diziyi geçirmenin etkisi: “
<< “\n\nOrijinal dizinin değerleri:\n”;
for ( i = 0; i < diziboyutu; i++ )
cout << setw( 3 ) << a[ i ];
cout << endl;
Filiz Eyüboğlu
YTÜ-BTB
66
Kaynak: Deitel&Deitel, C++ How To Program
// fonksiyonun çağrılışı – CALL-BY-REFERENCE ile
diziyidegistir( a, diziboyutu );
// fonksiyondan dönüşte dizi a’nın eleman değerleri
cout << “Fonksiyondan dönüşte değerler:\n”;
for ( i = 0; i < diziboyutu; i++ )
cout << setw( 3 ) << a[ i ];
cout << “\n\n\n”
<< “CALL-BY-VALUE ile dizi elemanlarını çağırmanın etkisi:
<< “\n\n a[3]’ün değeri: “ << a[ 3 ] << “\n”;
elemanidegistir( a [ 3 ] );
cout << “a[3]’ün değeri: “ << a[ 3 ] << endl;
return 0;
}
// diziyidegistir fonksiyonunun tanimi: burada
// “a”ya işaret eder.
“b”
bellekteki orijinal dizi
void diziyidegistir( int b[], int boyut )
{
for (int j = 0; j < boyut; j++)
b[ j ] = *= 2;
}
// elemanidegistir fonksiyonunun tanimi: buradaki “e” ana fonksiyondaki a(3)’ün
// yerel kopyasıdır.
void elemanidegistir( int e )
{
cout << “elemanidegistir’deki değer: “
<< ( e *= 2 ) << endl;
}
call-by-reference ile tüm diziyi geçirmenin etkisi:
Orijinal dizinin değerleri:
0 1 2 3 4
Fonksiyondan dönüşte değerler:
0 2 4 6 8
CALL-BY-VALUE ile dizi elemanlarını çağırmanın etkisi:
a[3]’ün değeri: 6
elemanidegistir’deki değer: 12
a[3]’ün değeri: 6
Yukarıda dizilerin fonksiyonlara call-by-reference ile geçirildiğini; bunun da orijinal dizi
elemanları üzerinde işlem yapıp değerleri değiştirdiğini gördük. Bunu istemediğimiz (yani,
kontrol etmek istediğimiz) durumlar olabilir. Bunu için const niteleyicisi kullanılır.
Aşağıdaki örnek const niteleyicisi kullanıldığında orijinal dizinin değiştirilemeyeceğini
göstermektedir.
// şekil 4.15 s. 261
// const niteleyicisi
#include <iostream>
using std::cout;
using std::endl;
void diziyidegistirmeyecalis( const int [] );
Filiz Eyüboğlu
YTÜ-BTB
67
Kaynak: Deitel&Deitel, C++ How To Program
int main()
{
int a [] = { 10, 20, 30 };
diziyidegistirmeyecalis( a );
cout << a[ 0 ] << ‘ ‘ << a[ 1 ] << ‘ ‘ << a[ 2 ] << ‘\n’;
return 0;
}
// asagiaki fonksiyonda orijinal dizi “a”yı değiştirme çabası hata verecektir;
çünkü // yukarıda fonksiyon prototipinde “a”
const olarak tanımlanmış.
void
{
b
b
b
}
diziyidegistirmeyecalis( const int b[] )
[ 0 ] /= 2;
[ 1 ] /= 2;
[ 2 ] /= 2;
// hata
// hata
// hata
DİZİLER ÜZERİNDE SIRALAMA İŞLEMLERİ (“SORTING ARRAYS”)
Verilerin sıralanması ( büyükten küçüğe ya da küçükten büyüğe gibi) bilgisayar
uygulamalarının en önemlilerinden biridir. Bir bankanın hesap numaralarına göre sıralama
yapması, okulda öğrenci soyadlarına göre sıralama yapamak gibi pek çok alanda verilerin
belirli sıralara dizilmesi gerekli ve vaz geçilmezdir.
Aşağıdaki program 10 elemanlı a dizisindeki değerleri küçükten büyüğe doğru (“ascending”)
sıralar. Kullanılan algoritma “bubble sort” algoritmasıdır. Daha küçük değerler – baloncuklar
gibi - dizide yukarı doğru çıkarlar, daha büyük değerler aşağıya kayar. Bu teknik dizi
üzerinden pek çok kez geçmemizi (yani pek çok kez diziyi baştan sona okumak, işlemek) Her
bir geçişte yan yana iki değer karşılaştırılır; daha üstte olan daha büyükse bu 2 eleman yer
değiştirir.
// fig. 4.16 s. 263
BUBBLE SORT
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::setw;
int main()
{
const int diziboyutu = 10;
int a[diziboyutu] = {2,6,4,8,10,12,89,68,45,37};
int i, gecici;
cout << “Verilerin Orijinal Sırası:\n;
for ( i = 0; i < diziboyutu; i++)
cout << setw(4) << a[ i ];
for ( int pass = 0; pass < diziboyutu - 1; pass++); //passes
for ( i = 0; i < diziboyutu – 1; i++)
Filiz Eyüboğlu
YTÜ-BTB
// one pass
68
Kaynak: Deitel&Deitel, C++ How To Program
if a[i ] > a[ i + 1 ]
{
// iki elemanın yerini değiştir
gecici = a[ i ];
a[ i ] = a[ 1 + 1 ];
a[ i + 1 ] = gecici;
}
cout << “\nKüçükten Büyüğe Doğru Verilerin Sıralanışı:\n;
}
for ( i = 0; i < diziboyutu; i++)
cout setw(4) << a[ i ];
cout << endl;
return 0;
Verilerin Orijinal Sırası:
2
6
4
8
10
12
89
68
45
37
Büyükten Küçüğe Doğru Verilerin Sıralanışı :
2
4
6
8
10
12
37
45
68
89
DİZİLERDE ARAMA YAPMA ( “searching arrays” ):
Doğrusal Arama ( “linear search” ) ve İkili Arama ( “binary search” ) algoritmaları
Çoğu zaman belirli bir sayının bir dizinin içinde yer alıp almadığını aramak gerekir. Dizinin
belirli bir elemanını bulmaya “arama” denir.
Bu bölümde 2 arama algoritması göreceğiz.
Doğrusal aramada, dizinin her bir elemanının aradığımız değere eşit olmadığı araştırılır.
Dizideki değerler sırasız olduğunda aradığımız değeri bulmak için ortalama olarak dizinin
eleman sayısının yarısı kadar erşim ve karşılaştırma yaparız. Eleman sayısı n ise, ortalama n
/ 2 karşılaştırma yapılmış olur (aradığınzı değer dizinin ilk elemanı ise 1 karşılaştırma; son
elemanı ise n karşılaştırma...)
Bu algoritma küçük boyutlu ve sırasız diziler için uygundur. Ancak büyük boyutlu diziler için
verimsiz bir tekniktir. Büyük boyutlu dizileri önce sıralayıp (“sort”) sonra İkili Arama
(“binary search”) denilen tekniği uygulamak çok daha verimlidir. Aslında sort etmek de
maliyetli bir iştir ancak büyük bir dizide çok sık arama yapılacaksa sort maliyetini göze almak
gerekir ve bu sık sık yapılacak arama maliyetinin yanında önemsiz kalır.
// fig. 4.19 s.269
LINEAR SEARCH algoritması kullanarak boyutu 100 olan
dizide belirli bir // değeri arayan programdır.
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int DA(const int[], int, int );
int main()
{
const int diziboyutu = 100;
int a[diziboyutu], sayi, eleman;
Filiz Eyüboğlu
YTÜ-BTB
69
Kaynak: Deitel&Deitel, C++ How To Program
// diziyi bazı sayılarla dolduralım
for ( int x = 0; x < diziboyutu; x++ )
a[ x ] = 2 * x;
cout << “ Aranacak sayıyı giriniz:” << endl;
cin >> sayi;
eleman = DA(a, sayi, diziboyutu);
if ( eleman != -1 )
cout <<
“Aranan sayi
“ <<
eleman
<< “. elemanda bulundu”
endl;
else
cout << “Aranan sayi dizide bulunamadı” << endl;
<<
return 0;
}
// DA fonksiyonu
int DA( const int array[], int key, int boyut )
{
for (int n=0; n < boyut; n++)
if ( array [n] == key )
return n;
return –1;
}
Aranacak sayıyı giriniz:
36
Aranan sayı 18. elemanda bulundu.
Aranacak sayıyı giriniz:
37
Aranan sayı dizide bulunamadı
İKİLİ ARAMA – binary search
İkili arama, her karşılaştırmdan sonra dizinin yarısını artık dikkate almaktan vazgeçer ve
dolayısıyla her seferinde daha az elemanı kontrol etmek durumundadır.
Anımsamak gerekirse ikili arama sıralı (sorted) diziler üzerinde çalışır.
Aranacak sayı öncelikle dizinin en ortasında yer alan sayı ile karşılaştırılır. Aranan sayı bu
sayıdan daha küçük ise artık dizinin orta ksımından gerisini (yani alt yarısını) aramaya gerek
yoktur. Üst yarıda aramamıza devam edebiliriz. Aradığımız sayıyı bu yarının en ortasındaki
elemanla karşılaştırıp sayı oratdaki sayıdan büyükse alt yarıyı küçükse üst yarıyı aramaya
devam ederiz....
1024 sayı içeren bir dizide aradığımız sayıyı bulmak için en fazla 10 karşılaştırmak yapmamız
yeterlidir. NEDEN? Dizinin bir milyar elemanı varsa 30 karşılaştırmada aradığımız sayıyı
buluruz. ((( first power of 2 greater than the number of elements in the array)))
// fig. 4.20 s.271 BINARY SEARCH algoritması kullanarak
// boyutu 15 olan dizide belirli bir değeri arayan programdır.
#include <iostream>
using std::cout;
Filiz Eyüboğlu
YTÜ-BTB
70
Kaynak: Deitel&Deitel, C++ How To Program
using std::cin;
using std::endl;
#include <iomanip>
using std::setw;
int binaryS(const int[], int, int, int, int );
void baslikyaz( int );
void satiryaz( const int [], int, int, int, int );
int main()
{
const int diziboyutu = 15;
int a[diziboyutu], sayi, sonuc;
// diziye bazı sayılar koy
for ( int i = 0; i < diziboyutu; i++ )
a[ i ] = i * 2;
cout << “0 ile 28 arasında bir sayı giriniz: “;
cin >> sayi;
baslikyazdir(diziboyutu);
sonuc = binary( a, sayi, 0, diziboyutu-1, diziboyutu );
if ( sonuc
cout <<
bulundu.“;
cout <<
else
cout <<
return 0;
}
!= -1 )
‘\n’ << sayi << “, “ <<sonuc << “no.lu dizi elemanında
endl;
‘\n’ << sayi << “bulunamadı.” << endl;
// Binary Search
int binaryS(const int b[], int key, int low, int high, int size )
{
int orta;
while (low <= high )
{
orta = (low + high ) / 2;
satiryaz(b, low, middle, high, size);
}
if ( key == b[orta] )
return orta;
else if ( key < b[orta] )
high = orta –1 ;
else
low = orta + 1;
return –1;
// aranan sayi bulunamadı
// çıktı için başlık yazdır
void baslikyazdir(int size )
{
int i;
Filiz Eyüboğlu
YTÜ-BTB
71
Kaynak: Deitel&Deitel, C++ How To Program
cout << “\nAltindisler:\n “;
for ( i=0; i < size; i++)
cout << setw(3) << i << ‘ ‘;
cout << ‘\n’;
for ( i =1; i <= 4*size; i++)
cout << ‘-‘;
cout << endl;
}
// dizinin proses edilmekte olan satırını yazdır
void satiyaz(const int b[], int low, int mid, int high, int size)
{
for (int i=0; i > size; i++)
if ( i < low || i > high)
cout << “
“;
else if ( i == mid )
// orta değeri işaretle
cout << setw(3) << b[i] << ‘*’;
else
cout << setw(3) << b[i] << ‘ ‘;
cout << endl;
}
0 ile 28 arasında bir sayı giriniz: 25
Altindisler:
0
1
2
3
4
5
6
7
8
9 10 11 12 13 14
-----------------------------------------------------------0
2
4
6
8 10 12 14* 16 18 20 22 24 26 28
16 18 20 22* 24 26 28
24 26* 28
24*
25 bulunamadı
0 ile 28 arasında bir sayı giriniz: 8
Altindisler:
0
1
2
3
4
5
6
7
8
9 10 11 12 13 14
-------------------------------------------------------0
2
4
6
8 10 12 14* 16 18 20 22 24 26 28
0
2
4
6* 8 10 12
8 10* 12
8, 4 nolu dizi elemanında bulundu.
ÇOKLU-ALTİNDİSLİ DİZİLER
C++’da dizilerin birden fazla altindisi olabilir. Çoklu altindis kullanmayı gerektiren en yaygın
yapı tablolardır. Bir tablo satır ve kolonlardan meydana gelir. Belirli bir tablo elemanına atıfta
bulunabilmek için 2 alt indis kullanılır. Birinci indis satır numarasını, ikinci satır sütun
numarasını gösterir.
satır 0
Satır 1
Satır 2
Filiz Eyüboğlu
Kolon 0
a[0][0]
Kolon 1
a[0][1]
YTÜ-BTB
Kolon 2
a[0][2]
Kolon 3
a[0][3]
72
Kaynak: Deitel&Deitel, C++ How To Program
Devamı sınıfta anlatılıyor.
KONU - 5 :
POINTERS
Deitel & Deitel, p. 305
POINTERS are one of the most powerful features of the C++ prog.lang. And they are the
most difficult capabilities to master. In Ch.3 we saw that references can be used to perform
call-by-reference. Pointers enable programs to simulate call-by-reference and create dynamic
structure such as linked lists, stacks, queues.
int *countPtr, count;
“countPtr is a pointer to int”
POINTER OPERATORS
p. 307
& operator (address operator) is a unary operator that returns the address of its operand. For
example, assume the declarations
int y = 5;
int *yPtr;
yPtr = &y; assigns the address of the variable y to pointer variable yPtr.
Variable yPtr is then said to “point to” y.
yPtr
y
5
Fig. 1
The * operator, commonly referred to as the indirection operator or dereferencing operator,
returns a synonym, alias or nickname for the object to which its operand ( i.e., a pointer )
points. For example,
cout << *yPtr << endl;
prints the value of variable y, namely 5, in much the same way as the statement
cout << y << endl;
would. Using * in this manner is called dereferencing to a pointer. Note that a dereferenced
pointer may also be used on the left side of an assignment statement as in
Filiz Eyüboğlu
YTÜ-BTB
73
Kaynak: Deitel&Deitel, C++ How To Program
*yPtr = 12;
which would assign 12 to y in Fig.1. The dereferenced pointer may also be used to receive an
input value as in
cin >> *yPtr;
ÖRNEK:
// fig.5.4 p. 308
// using the & and * operators
#include <iostream>
using std::cout;
using std::endl;
int main()
{
int a;
// a is an integer
int *aPtr;
// aPtr is a pointer to an integer
a = 7;
aPtr = &a;
// aPtr is set to address of a
cout << “the address of a is “ << &a << “\nThe value of
aPtr : “
<< aPtr;
cout << “the value of a is “ << a
<< “\nThe value of *aPtr : “ << *aPtr;
}
cout << “\n\nShowing that * and & are inverses of “
<< “each other.\n&*aPtr = “ << &*aPtr <<
<< “\n*&aPtr = “ << *&aPtr << endl;
return 0;
The address of a is 006AFDF4
The value of aPtr is 006AFDF4
The value of a is 7
The value of *aPtr is 7
Showing that * and & are inverses of each other.
&*aPtr = 006AFDF4
*&aPtr = 006AFDF4
Filiz Eyüboğlu
YTÜ-BTB
74
Kaynak: Deitel&Deitel, C++ How To Program
KONU - 6: SINIFLAR ( “CLASSES” )
Deitel&Deitel, 391
C dilinde temel bileşenler fonksiyonlardır ve programcı programını fonksiyonlardan
oluşturmaya odaklanır.
C++’da ise temel bileşenler sınıflardır. Her sınıf, veri kadar o veri üzerinde çalışacak
fonksiyonları da içerir; sınıf’taki veri bileşenlerine “data members”, fonksiyon bileşenlerine
“member functions” veya “methods “ denir.
CLASSES:
Data members and
Methods
Sınıflar, C’deki yapıların (“structures” – struct ) evrimleşmiş halidir. Sınıflara geçmeden önce
kısaca C’de struct tanımına bakalım.
Struct Time
{
int saat;
int dakika;
int saniye;
}
// 0-23
// 0-59
// 0-59
saat, dakika ve saniye yapının üyeleridir ( “members of structure “)
Yukarıdaki, sadece tanımdır; Time adında bir veri türü tanımlamış oluruz. Bellekte yer işgal
etmez. Kullanıcı Time veri türünde bir değişken tanımladığı zaman o değişken için bellekte
yer açılır. Örneğin
Time timeobject;
// Time veri türünde timeobject adlı bir değişken tanımı
Time timearray[10];
// Time veri
Time &timeref = timeobject;//
Time *timeptr;
türünde 10’luk bir dizi tanımı
Timeref Time objesine bir atıftır(takma ad)
// timeptr is a pointer to Time object
YAPI ÜYELERİNE ERİŞİM
Filiz Eyüboğlu
YTÜ-BTB
75
Kaynak: Deitel&Deitel, C++ How To Program
cout << timeobject.saat;
struct yerine class kullanımı
class Time
{public:
Time();
void setTime(int, int, int);
void printMilitary();
void printStandard();
private:
int saat;
// 0-23
int dakika;
// 0-59
int saniye;
// 0-59
};
public’den sonra gelen tanımlar (private’a kadar) programda herhangi bir Time objesine
erişim olduğu her yerde geçerlidir.
Private’dan sonra gelen tanımlar (bir sonraki public veya private’a kadar) sadece bu sınıfın
üyeleri tarafında erişilirler.
Sınıf tanımları aşağıdaki preprocessor direktfileri içinde alınmalıdır:
// time.h header file
#ifndef TIME_H
#define TIME_H
class tanımı
#endif
ifndef ( if not defined )’in anlamı: TIME_H header dosyasını daha önce include
etmediysen, et demektir. Aynı header dosyasının birden fazla kere include edilmesini
önlemek içindir.
ÖRNEK PROGRAM:
önce class tanımı - header dosya içinde
// fig.6.5 s.405
time1.h header file
// Time sınıfının tanımlanması
// Bu sınıfa ait “member functions (methods)” time1.cpp’de
tanımlı
#ifndef TIME1_H
#define TIME1_H
Filiz Eyüboğlu
YTÜ-BTB
76
Kaynak: Deitel&Deitel, C++ How To Program
class Time
{public:
Time();
void setTime(int, int, int);
void printMilitary();
// military formatta yazmak için
void printStandard();
// standard formatta yazmak için
private:
int saat;
// 0-23
int dakika;
// 0-59
int saniye;
// 0-59
};
#endif
Şimdi sınıfa ait metotları tanımlayalım. cpp uzantılı bir dosya içinde olmalı.
// fig.6.5 time1.cpp
// Time sınıfının metodları “member functions”
#include <iostream>
using std::cout;
#include “time”.h”
// Time constructor initializes each data member to zero
// ensures that all Time objects start in a consistent state
Time::Time() {saat = dakika = saniye = 0; }
// set a new Time value using military time. Perform validity
// checks on the data values. Set invalid values to zero.
void Time::setTime(int s, int d,
{
saat
= ( s >= 0 && s < 24 )
dakika = ( d >= 0 && d < 60 )
saniye = ( sa >= 0 && sa < 60
}
int sa )
? s : 0;
? d : 0;
) ? sa : 0;
// Zamanı “military “ formatta yazdırma fonksiyonu
void Time::printMilitary()
{
cout << ( saat < 10 ? “0” : “” ) << saat “:”
<< (dakika < 10 ? “0” : “” ) << dakika;
}
// standart formatta yazdırma fonksiyonu
void Time::printStandard();
Filiz Eyüboğlu
YTÜ-BTB
77
Kaynak: Deitel&Deitel, C++ How To Program
{
cout <<
<<
<<
<<
( ( saat == 0 || saat
“:” << (dakika < 10 ?
“:” << (saniye < 10 ?
(saat < 12 ? “ AM “ :
== 12 )
“0” : “”
“0” : “”
“ PM “ )
? 12 : saat % 12)
) << dakika
) << saniye
;
}
Yukardaki time1.h ve time1.cpp ‘yi kullanan program:
// fig.6.5
fig06_05.cpp
// Driver for Time1 class
// Note: compile with time1.cpp
#include <iostream>
using std::cout;
using std::endl;
#include “time”.h”
int main()
{
Time t;
//
Time sınıfına ait bir t objesi (nesnesi) yarat
cout << “Askeri formatta zaman: “;
t.printMilitary();
cout << “\nStandart formatta zaman: “;
t.printStandard();
t.setTime(13,17,6);
cout << “setTime’dan sonra askeri formatta zaman: “;
t.printMilitary();
Filiz Eyüboğlu
YTÜ-BTB
78
Kaynak: Deitel&Deitel, C++ How To Program
cout << “\nsetTime’dan sonra standart formatta zaman: “;
t.printStandard();
t.setTime(99,99,99);
// geçersiz bir saat ataması
cout << “\n\ngeçersiz atamadan sonra askeri formatta zaman:
“;
t.printMilitary();
cout << “\n\ngeçersiz atamadan sonra standart formatta
zaman: “;
t.printStandard();
cout endl;
return 0;
}
Askeri formatta zaman: 00:00
Standart formatta zaman: 12:00:00 AM
SetTime’dan sonra askeri formatta zaman: 13:27
SetTime’dan sonra standart formatta zaman: 1:27:06 PM
Geçersiz atamadan sonra askeri formatta zaman: 00:00
Geçersiz atamadan sonra standart formatta zaman: 12:00:00 AM
DERS:
DÖNEM:
PROGRAMLAMA DİLLERİ – 1
2002-2003 Güz yarı yılı
KONU 7: DOSYA İŞLEME (“File Processing”)
HEDEFLER:
27- Dosyaları yaratabilme, okuyabilme, yazabilme ve güncelleyebilme
28- Sıralı erişim dosyalarını tanıma
29- Rasgele (doğrudan) erişim dosyalarını tanıma
30- Bu dosyalar üzerinde G/Ç işlemleri yapma
İÇERİK:
Veri hiyerarşisi
Sıralı erişim dosyası yaratma
Sıralı erişim dosyasından okuma
Sıralı erişim dosyalarını güncelleme
Filiz Eyüboğlu
YTÜ-BTB
79
Kaynak: Deitel&Deitel, C++ How To Program
Rasgele erişimli dosyalar
Sıralı erişim dosyalarını yaratma
Sıralı erişim dosyalarına yazma
Sıralı erişim dosyasından sıralı okuma
VERİ HİYERARŞİSİ
Bilgisayarlarda her sayı ya da alfabetik karakterin 0 ve 1’lerle temsil edildiğini biliyorsunuz.
Karakterlerin bitlerden oluşması gibi alanlar da karakter (veya baytlardan) oluşur. Alan bir
anlamı olan bir grup karakterdir.
Bir kayıt ise (C++’da class , C’de struct ) birden fazla alandan meydana gelir. Örneğin bir
muhasebe sisteminde bir çalışana ait bir kayıtta aşağıdaki alanlar bulunabilir.
1- Sicil no
2- Adı
3- Adresi
4- Ücreti
31- Vergi oranı
Dolayısıyla bir kayıt birbiriyle alakalı alanlardan meydana gelir.
100000 kaydın olduğu bir dosyadan bir kayda erişmek istediğimizi düşünelim. Genellikle bu
erişimi kolaylaştırmak için kaydın bir alanı anahtar (“record key”) olarak belirlenir ve erişim
esnasında kullanılır. Yukardaki örnekte sicil no kayıt anahtarı olarak kullanılabilir.
Şirketlerin birden fazla dosyaları vardır: muhasebe, alacak hesapları, stok, personel, vb gibi.
Birbiriyle ilgili dosyaların bir veri tabanı programı kullanılarak veri tabanında tutulması pek
çok kolaylık sağlar: veri bütünlüğü, veri tutarlılığı, bakım kolaylığı, mükerrer veri olmaması
gibi. Veri tabanlarını yaratmak ve erişimi sağlamak, bakımlarını yapmnak için Veri Tabanı
Yönetim Sistemi (DBMS) denen yazılımlar mevcuttur.
C++ bir dosyayı baytlar sırası (“sequence of bytes”) olarak görür. Her dosya, dosya sonunu belirten
bir işaret ile biter.
C++’da dosya işlemleri yapabilmek için <iostream> ve <fstream> başlık dosyaları dahil edilmelidir.
<fstream> başlık dosyası ifstream (giriş işlemleri için) ve ofstream (çıkış işlemleri için) gerekli sınıf
(“class”) tanımlarını içerir.
SIRALI DOSYA YARATMA
Örnek: Her müşteri için hesap no, müşter, adı, bakiyesi, vb. tutulacak. Program, kullanıcının kayıtları
hesap no sırasında gireceğini varsaymaktadır.
// fig. 14.4 s.761
// create a sequential file
#include <iostream>
using
using
using
using
using
std::cout;
std::cin;
std::ios;
std::cerr;
std::endl;
Filiz Eyüboğlu
YTÜ-BTB
80
Kaynak: Deitel&Deitel, C++ How To Program
#înclude <fstream>
using std::ofstream;
#include <cstdlib>
int main()
{
ofstream MusteriDosyasi(“musteri.dat”, ios::out ); // musteri.dat çıkış
// için açılır (open)
if
{
(!MusteriDosyasi) // dosya düzgün açılırsa 0 döndürür
cerr << “Dosya açılamadı” << endl;
exit(1); // sıfır harici bir değer programın bir hata sonucu bittiğini gösterir. Bu değer op.sys’e ...
}
cout << “Hesap no, Ad, Bakiye bilgilerini giriniz.\n”
<< “Girişi bitirmek için EOF giriniz.\n?”;
int hesap;
char ad[20];
double bakiye;
while (cin >> account >> ad >> bakiye ) //EOF olmadıkça bu koşul doğrudur
{
MusteriDosyasi << hesap << ‘ ‘ << ad << ‘ ‘ << bakiye << ‘\n’;
cout << “? “;
}
return 0; // EOF olunca main biter. Musteri.dat dosyası kapatılır.
}
Hesap no, Ad, Bakiye bilgilerini giriniz.
Girişi bitirmek için EOF giriniz.
? 100 Jones 24.98
? 200 Doe 345.67
? 300 White 0.00
? 400 Stone –42.16
? 500 Rich 224.62
? ^Z
Dosya açma durumları (“file open modes”)
ios::app
ios::in
ios::out
ios::trunc
ios::binary
dosyanın sonuna ekle
dosyayı giriş için aç
dosyayı çıkış için aç
dosyanın içeriğini at
dosyayı ikili (metin olmayan) giriş çıkış için aç
SIRALI DOSYADAN OKUMA YAPMA (“reading from sequential access file”)
// fig. 14.7 s. 766-767
.
.
#include <fstream>
.
.
void satiryazdir(int, const char * const, double);
int main()
{
Filiz Eyüboğlu
YTÜ-BTB
81
Kaynak: Deitel&Deitel, C++ How To Program
ifstream MusteriDosyasi(“musteri.dat”, ios::in );
da olur
// ios::in konulmasa
if ( !MusteriDosyasi)
{
cerr << “Dosya açılamadı\n”;
exit(1);
}
int hesap;
char ad[20];
double bakiye;
cout << setiosflags( ios::left ) setw( 10) << “HESAP NO”
<< setw(13) << “ADI”
<<
BAKİYE\n” << setiosflags( ios::fixed | ios::showpoint );
while ( MusteriDosyasi >> hesap >> ad >> bakiye )
satiryazdir(hesap, ad, bakiye);
}
return 0;
ad is a char
pointer to a
const char
void satiryazdir(int hes, const char * char ad, double bak)
{
cout << setiosflags( ios::left ) setw( 10) << hes << setw(13) << ad
<< setw(7) <<
setprecision(2)
<< resetiosflags( ios::fixed
<< bal << ‘\n’;
}
HESAP NO
100
200
300
400
500
ADI
Jones
Doe
White
Stone
Rich
)
BAKIYE
24.98
345.67
0.00
-42.16
224.62
----------------------------------------------------------------------------------------------------------ss. 768-769-770-771 atlandı
SIRALI ERİŞİM DOSYALARININ GÜNCELLENMESİ
Yukarıda yaratılmış olan musteri dosyasındaki bir veri değiştirilmek (güncellenmek)
istendiğinde diğer verilerin bozulma riski vardır. Örneğin White ismini Worthington yapmak
istersek, bu isim orijinal isim olan Whhite’dan 6 karakter daha uzun olduğundan kendisinden
sonra gelen kaydı bozar. Bunu önlemek için 300 White 0.00’a kadar olan kayıtlar yeni bir
dosyaya kopyalanıp 300 Worthington 0.00 yazılıp geri kan kayıtlar da yeni dosyaya
aktarılabilir. Bir seferde çok sayıda kayıt güncellenecekse bu yöntem kabul edilebilir.
RASGELE ERİŞİMLİ DOSYALAR
Belirli bir kaydın hemen bulunmasu gerektiği durumlarda kullanılır. Bankada belirli bir
müşteri hesabına (dosyada daha önce gelen müşteri kayıtları okunmadan ) erişilmesi, kayıt
sırasında belirli bir öğrenci numarasına daha önceki tüm numaralar okunmadan erişilmesi
gibi.
C++ dosyalar üzerinde bir yapı oluşturmadığı için bunu programcı yapmalıdır. Rasgele
erişimli dosya yaratmak için pek çok teknik vardır. Bunların en kolayında, tüm kayıtların sabit
Filiz Eyüboğlu
YTÜ-BTB
82
Kaynak: Deitel&Deitel, C++ How To Program
uzunluklu olması tercih edilir / gerekir. Kayıtların sabit uzunluklu olması aranan bir kaydın
dosyanın başına göre kaçıncı bayttan (“byte offset”) başladığını hesaplamamızı mümkün
kılar.
RASGELE ERİŞİMLİ DOSYALARI YARATMAK
Bu tür dosyalara genellikle class veya struct ile tanımlanmış bir grup alanı bir anda yazdırırız,
tek bir sayıyı değil.
Örnek: 100 müşteri için 100 sabit uzunluklu kayıt tutulacak. Her kayıtta hesap no (kayıt
anahtarı), ad, soyad, bakiye alanları bulunacak. Program, bir hesabı güncelleyebilmeli, yeni
hesap ekleyebilmeli, hesap silebilmeli ve tüm hesapları listeleyebilmeli.
Aşağıda rasgele erişimli bir dosyanın nasıl açıldığını, struct ile kayıt yapısının nasıl
tanımlandığı (musveri.h adlı başlık dosyasında) gösterilmektedir. Program öncelikle 100
kayda boş struct’lar yazarak kayıtların ik değer atamalarını yapmaktadır. Boş struct’da hesap
no için 0, ad ve soyad için “null” dizgi, ve bakiye için 0.0 vardır.
// musveri.h
// struct musteri’nin tanımı
#ifndef MUSVERI_H
#define MUSVERI_H
struct musteri
{
int hesapno;
char soyad[15];
char ad[10];
double bakiye;
};
#endif
Header file musveri.h
aşağıdaki tüm programlarda
bu başlık dosyası kullanılacak
// fig.14.11 s.774
// creating random-access file sequentially
#include <iostream>
using std::cerr;
using std::endl;
using std::ios;
#include <fstream>
using std::ofstream;
#include <cstdlib>
#include “musveri.h”
int main()
{
ofstream kredi(“kredi.dat”, ios::binary); // kredi.dat file is associated with
Filiz Eyüboğlu
YTÜ-BTB
83
Kaynak: Deitel&Deitel, C++ How To Program
// ofstream object kredi
if ( !kredi )
{
cerr << “kredi dosyası açılamadı” << endl;
exit(1);
}
musteri bosmusteri = { 0, “”, “”, 0.0 };
for ( int i = 0; i <100, i++ )
kredi.write(
reinterpret_cast<const char *>( &bosmusteri ), sizeof(musteri));
return 0;
}
kredi.write(
reinterpret_cast<const char *>( &bosmusteri ), sizeof(musteri));
cümlesinin anlamı:
kredi.dat ile ilişkilendirilmiş kredi nesnesine (“object”) musteri yapısı büyüklüğündeki
bosmusteri yapısını yazar.
NOTE THAT the first argument of write function must be of type const char *.
However, the data type of &bosmusteri is musteri *.
To convert &bosmusteri to the appropriate pointer type, the expression
reinterpret_cast<const char *>( &bosmusteri )
uses the cast operator reinterpret_cast to convert the address of bosmusteri to a
const char *, so the call to write compiles without issuing a syntax error.
RASGELE-ERİŞİMLİ DOSYAYA VERİLERİ RASGELE YAZMA
Aşağıdaki program kredi.dat dosyasına veri yazar. Dosyaya verileri tam yerlerine yazmak için
ofstream fonksiyonları write ve seekp kullanır. Fonksiyon seekp, dosyaya yazıacak kaydın
tam yerini ayarlar ve write verileri yazar.
// fig.14.12 s.775
// writing to a random access file
#include <iostream>
using
using
using
using
using
std::cerr;
std::endl;
std::ios;
std::cin;
std::cout;
#include <fstream>
Filiz Eyüboğlu
YTÜ-BTB
84
Kaynak: Deitel&Deitel, C++ How To Program
using std::ostream;
#include <cstdlib>
#include “musveri.h”
int main()
{
ofstream kredi(“kredi.dat”, ios::binary); // kredi.dat file is associated with
// ofstream object kredi
if ( !kredi )
{
cerr << “kredi dosyası açılamadı” << endl;
exit(1);
}
cout << “Hesap numarasını ( 1 ile 100 arasında )giriniz. “
<< “Bitirmek için 0 giriniz.\n? “;
musteri mus;
cin >> mus.hesapno;
while ( mus.hesapno > 0 && mus.hesapno <= 100 )
{
cout << “Ad, soyad ve bakiye giriniz.\n? “;
cin >> mus.ad >> mus.soyad >> mus.bakiye;
// kredi dosyasında gerekli adrese konumlan
kredi.seekp( ( mus.hesapno – 1 ) * sizeof (musteri) );
kredi.write(
reinterpret_cast<const char *>(&mus), sizeof(musteri) );
cout << “Hesap numarasını giriniz:\n? “;
cin >> mus.hesapno;
}
}
return 0;
Hesap numarasını ( 1 ile 100 arasında )giriniz.Bitirmek için 0 giriniz.
? 37
Ad, soyad ve bakiyeyi giriniz:
? Bakır Deniz 0.00
Hesap numarasını giriniz:
? 29
Ad, soyad ve bakiyeyi giriniz:
? Baki Naci –24.54
Hesap numarasını giriniz:
? 96
Ad, soyad ve bakiyeyi giriniz:
? Sarı Sami 34.98
Hesap numarasını giriniz:
? 88
Ad, soyad ve bakiyeyi giriniz:
? Simit Davut 258.34
Hesap numarasını giriniz:
? 0
Filiz Eyüboğlu
YTÜ-BTB
85
Kaynak: Deitel&Deitel, C++ How To Program
kredi.seekp( ( mus.hesapno – 1 ) * sizeof (musteri) );
Parantez içindeki aritmetik ifade, yazılacak yadın, dosya içine baştan kaçıncı bayttan
başlacağını hesaplar. Musteri 50 bayt ise, hesapno 4 ise, hesapno 4 olan kayıt 200.bayttan
itibaren yazılacak demektir. Dosya konumlandırma işaretçisi (“file position pointer”) bu
adrese konumlanır.
RASGELE-ERİŞİMLİ BİR DOSYAYI SIRALI OKUMA
s.777
Daha önce yarattığımız rasgele-erişimli dosyayı sıralı okuyacağız yani ilk kayıttan başlayarak
sırayla her kaydı. Öncelikle birkaç önmeli konuya bakalım:
ifstream fonksiyonu read belirlenen bayt uzunluğundaki veriyi dosyadan okur. Örneğin
kredi.read(reinterpret_cast<char *>( ?mus ), sizeof(musteri) );
=Î kredi dosyasından musteri uzunluğunda baytı okuyup mus yapısına koyar.
NOT: read fonksiyonunun ilk argümanı char
* olmak durumundadır.
Aşağıdaki program kredi.dat dosyasındaki bütün kayıtları sırayla okur ve okunan her bir
kaydın veri içerip içermediğine bakar. Döngü koşulunu inceleyecek olursak:
while ( kredi &&
!kredi.eof() )
dosya sonuna gelip gelinmediğini anlamak için eof fonksiyonunu kullanır. Dosya sonuna
gelindiyse döngüden çıkılır. İkinci bir koşul da && işaretinin sol tarafında yer alan kredi
sözcüğüyle belirtilmiştir. kredi dosyası okunurken bir hata oluşursa bu noktaya false
döner ve yine döngüden çıkılır.
OutputLine fonksiyonunun 2 argümanına dikkat edelim:
1- ostream objesi 2-musteri yapısı (structure).
Görüldüğü gibi, cout gibi bir ostream objesini argüman olarak vermek mümkündür.
Program: Rasgele erişimli dosyasını sıralı okunması
// fig. 14.14 reading a random access file sequentially
#include <iostream>
using
using
using
using
std::cerr;
std::endl;
std::ios;
std::cout;
#include <iomanip>
using
using
using
using
std::setprecision;
std::setiosflags;
std::resetiosflags;
std::setw;
#include <fstream>
using std::ifstream;
Filiz Eyüboğlu
YTÜ-BTB
86
Kaynak: Deitel&Deitel, C++ How To Program
using std::ostream;
#include <cstdlib>
#include “musveri.h”;
void outputLine( ostream&, const clientData & );
int main()
{
ifstream kredi(“kredi.dat”, ios::in); // kredi.dat file is associated with
// ifstream object kredi
if ( !kredi )
{
cerr << “kredi dosyası açılamadı” << endl;
exit(1);
}
cout <<
<<
<<
<<
setioflags( ios:: left ) << setw (10) << “HESAP NO”
setw(16) << “SOYADI” <<
setw(11)
“ADI” << resetiosflags(ios::left)
setw(10) << “BAKİYE” << endl;
musteri mus;
kredi.read(reinterpret_cast<char *>( &mus ), sizeof( musteri ));
while ( kredi && !kredi.eof() )
{
if (mus.hesapno != 0 )
outputLine ( cout, mus);
kredi.read(reinterpret_cast<char *>( &mus ),
sizeof( musteri ));
}
return 0;
}
void outputLine( ostream &output, const musteri &c)
{
output << setiosflags( ios::left ) << setw (10)
<< c.hesapno << setw(16) << c.soyad
<< setw(11) << c.ad << setw(10)
<< setprecision(2) << resetiosfalgs( ios::left)
<< setiosflags( ios::fixed | ios::showpoint)
<< c.bakiye << ‘\n’;
}
HESAP NO
29
33
37
88
96
SOYADI
Baki
Dakik
Bakır
Simit
Sarı
ADI
Naci
Selin
Deniz
Davut
Sami
BAKİYE
-24.54
314.33
0.00
258.34
34.98
PROGRAMLAMA DİLLERİ-1 DERSİ
Filiz Eyüboğlu
YTÜ-BTB
Güz 2002-2003
87
Kaynak: Deitel&Deitel, C++ How To Program
ALIŞTIRMA – 1
BOŞLUKLARI DOLDURUNUZ.
1- Bu konuda gördüğümüz dört dil sınıfı (programlamanın evrimi bakımından): ..............................,
......................................, ..........................................
ve .........................................’dir.
2- Bilgisayarlar, bilgisayar ............................. olarak adlandırılan komut kümelerinin denetimi altında
veriyi işlerler.
3- Yüksek seviyeli dillerle yazılmış programları makine diline çeviren programlara ......................
denir.
4- C, ...................... işletim sisteminin geliştirildiği dildir.
5- Bir C++ sisteminde, derleyiciden önce çalışan programa ................................. denir.
6- Derleyicinin çıktısını çeşitli kitaplık fonksiyonlarıyla birleştirerek yürütülebilir bir kod üreten
programa .......................denir.
7- Yürütülebilir kodu diskten alarak ana belleğe getiren programa ...................... denir.
8- Her C++ programı yürütülmeye ......... fonksiyondan başlar.
9- Her cümle ............. ile biter.
10- Programın okunabilir ve anlaşılabilir olması için ................................ yazmalıyız.
11- İmlecin ekranda bir satır sonraya konumlanmasını sağlayan karakter dizisi .......’dir.
AŞAĞIDAKİLERİN DOĞRU MU YANLIŞ MI OLDUĞUNA KARAR VERİNİZ.
12- // ile başlayan açıklama satırları yürütülebilir cümleler değildir. Bunlar olduğu gibi ekrana yazılır.
13- Tüm değişkenler kullanılmadan önce tanımlanmalıdır.
14- C++’a göre sayi
ile sAYi
aynidir.
15- Tanımlamalar bir C++ programının her hangi bir yerinde yer alabilir.
16- Modülüs operatörü (%) sadece tamsayılarla kullanılır.
17- Aritmetik operatörlerin öncelik sırası birbirine eşittir.
Filiz Eyüboğlu
YTÜ-BTB
88
Kaynak: Deitel&Deitel, C++ How To Program
AŞAĞIDAKİLERİ YERİNE GETİRMEK İÇİN BİRER C++ CÜMLESİ YAZINIZ.
18- qq234, tamsayi ve BuBirSayi değişkenlerini tamsayi olarak tanımlayınız.
19- Kullanıcıdan bir tamsayı girmesini isteyiniz. Mesaj iki nokta üstüste ile bitsin ve imleç alt satıra
geçmesin.
20- Klavyeden girilen sayıyı soyadi
değişkenine okuyunuz.
21- Sayi 7’ye eşit değilse “Sayı yediye eşit değil1” mesajını yazdırınız.
22- “Bu bir C++ programıdır.” mesajını bir satıra yazdırınız.
23- “Bu bir C++ programıdır.” mesajını iki satıra yazdırınız. İlk satır C++ ile bitsin.
24- “Bu bir C++ programıdır.” mesajını her bir kelime ayrı bir satırda olacak biçimde yazdırınız.
25- Programın 3 tamsayının çarpımını bulacağını belirten bir açıklama yazınız.
26- x,y,z ve sonuc değişkenlerini tamsayı olarak tanımlayınız.
27- Kullanıcıdan 3 tamsayı girmesini isteyiniz.
28- Kullanıcının girdiği 3 tamsayıyı okuyunuz ve x, y, z değişkenlerine saklayınız.
29- x, y ve z’nin çarpımını hesaplayıp sonucu sonuc değişkenine atayınız.
30- Programın başarıyla bittiğini belirten bir değeri main fonksiyondan döndürünüz.
AŞAĞIDAKİ İKİ CÜMLEDEKİ HATALARI BULUP DÜZELTİNİZ:
31- if (c < 7 ) ;
cout << “ c, yediden küçüktür.\n”;
Filiz Eyüboğlu
YTÜ-BTB
89
Kaynak: Deitel&Deitel, C++ How To Program
32- if (c => 7 )
cout << “ c yediye eşit veya büyüktür.\n”;
33- Aşağıdakilerin yazılım mı donanım mı olduğunu yanlarına yazınız:
CPU (merkezi işlem birimi)
C++ derleyicisi
ALU
C++ önderleyici
Giriş birimi
34- x =2 y = 2 kabul ederek aşağıdaki cümleler – eğer bir şey print ediyorlarsa – bunu cümlelerin
yanına yazınız. Hiçbir şey print etmiyorlarsa “hiçbirşey” yazınız.
a) cout << x;
b) cout << x + x;c) cout << “x=”;
d) cout “x= “ << x;
e) cout << x + y << “ = “ << y + x;
f) z = x + y;
g) cin >> x >> y;
h) // cout << “x + y = “ << x + y;
i) cout << “\n”;
35- Aşağıdaki C++ cümlelerinden hangilerinde değişkenlerin içerdikleri değerler değişmektedir:
a) cin >> a >> b >> c;
b) p = i + j + 7;
c) cout << a+5;
36- y = ax³ + 7 ifadesinin C++ karşılığı aşağıdakilerden hangisi veya hangileridir?
a) y = a * x * x * x + 7;
b) y = a * x * x * (x + 7);
c) y = (a * x) * x * (x + 7);
d) y = (a * x) * x * x + 7;
e) y = a * (x*x*x) + 7;
f) y = a * x * (x * x + 7);
Aşağıdaki C++ cümlelerinde operatörlerin değerlendirme sıralarını ve x’in alacağı değeri
gösteriniz.
37- x = 7 + 3 * 6 / 2 – 1;
38- x = 2 % 2 + 2 * 2 – 2 / 2;
39- x = ( 3 * 9 * ( 3 + (9 * 3 / (3))));
Filiz Eyüboğlu
YTÜ-BTB
90
Kaynak: Deitel&Deitel, C++ How To Program
Filiz Eyüboğlu
YTÜ-BTB
91

Benzer belgeler

c++ programlama dili ders notları

c++ programlama dili ders notları 10- Yapısal programlamayı anlama 11- Seçim yapma yapılarını (if, if/else, switch) kullanabilme 12- Tekrar etme yapılarını (while, do/while, for) kullanabilme 13- Sayaç kontrollu tekrarı anlama 14- ...

Detaylı

c++ programlama dili ders notları

c++ programlama dili ders notları using cümleleri: cout ve cin’den önce std:: kullanımını ortadan kaldırır. Hatırlanacağı gibi

Detaylı