Programlamaya Giri³ Ders Notlar H. Turgut Uyar ubat 2004 ii Önsöz (C) 2001-2004, H. Turgut Uyar <[email protected]> Bu notlar, stanbul Teknik Üniversitesi'nde verilen Introduction to Scientic and Engineering Computation dersi için Bilgisayar Mühendisli§i Bölümü ö§retim görevlisi H. Turgut Uyar tarafndan hazrlanm³tr. Yazarnn açkça belirtilmesi ko³uluyla e§itim amaçl kullanlabilir ve da§tlabilir. Di§er her türlü kullanm için yazarndan izin alnmaldr. Sürüm: 0.99.5 Son düzenleme tarihi: 5 ubat 2004 Web sayfas: http://www.ce.itu.edu.tr/Members/uyar/c Bu dersin amac, ö§renciye yalnzca programlamay ya da C dilini ö§retmek de§il, ayn zamanda temel saysal yöntemleri ve sralama algoritmalar gibi skça kullanlan programlama tekniklerini de göstermektir. Bu amaçla uygulamalarda daha çok saysal yöntemler üzerine örnekler seçilmeye çal³lm³tr. Bu örneklerin ço§u Prof. Dr. Nadir Yücel'in Saysal Analiz Algoritmalar kitabndan uyarlanm³tr. Notlarn hazrlanmasnda yeni standartlara uyumu kolayla³trmas açsndan C++ dilinin getirdi§i baz yeniliklerden yararlanlm³tr. Metin içinde yeri geldikçe, C++ dilinde geçerli olup C dilinin izin vermedi§i özellikler belirtilmi³tir. Programlarn ekran çktlarnda kullancnn yazd§ de§erler italik olarak i³aretlenmi³tir. Örnek programlar ve ders için hazrlanan sunumlar (ngilizce) yukarda belirtilen web sayfasnda bulunabilir. iii iv çindekiler 1 Giri³ 1 1.1 Veriler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.1.1 Taban Tipler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.1.2 Kaytlar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.1.3 Diziler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.2 Algoritmalar 1.2.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Algoritmalarn Kar³la³trlmas . . . . . . . . . . . . . . . . . . . . . . . 11 1.3 Blok Yapl Programlama . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.4 Soyutlama . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.5 Giri³ / Çk³ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 1.6 Program Geli³tirme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 1.6.1 Programlarn De§erlendirilmesi . . . . . . . . . . . . . . . . . . . . . . . 23 1.6.2 Programlarn Çal³trlmas . . . . . . . . . . . . . . . . . . . . . . . . . 24 1.6.3 Kitaplklar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 1.6.4 Standartlar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 1.6.5 Derleme A³amalar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2 C Diline Giri³ 29 2.1 simler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.2 De§erler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.3 De§i³kenler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.4 Veri Tipleri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.5 De§i³mezler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.6 Aritmetik Deyimler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.7 Tip Dönü³ümleri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 2.8 Artrma / Azaltma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 2.9 Matematik Kitapl§ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 2.10 Giri³ / Çk³ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 v vi ÇINDEKILER 3 Ak³ Denetimi 3.1 3.2 45 Ko³ul Deyimleri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 3.1.1 Kar³la³trma ³lemleri . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 3.1.2 Mantksal ³lemler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Seçim 3.2.1 Ko³ullu ³leç . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.3 Çoklu Seçim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.4 Ko³ul Denetiminde Yineleme . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.5 Döngü Denetimi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.6 Sayaç Denetiminde Yineleme . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Türetilmi³ Veri Tipleri 63 73 4.1 Numaralandrma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 4.2 Yaplar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 5 Diziler 85 5.1 Tek Boyutlu Diziler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 5.2 Katarlar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 5.3 Katar Kitapl§ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 5.4 Çok Boyutlu Diziler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 5.5 Ba³vurular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 6 Fonksiyonlar 103 6.1 Fonksiyon Bildirimi ve Tanm . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 6.2 Parametre Aktarm 6.3 Yerel De§i³kenler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 6.4 Genel De§i³kenler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 6.5 Ba³vuru Aktarm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 6.6 Giri³ Parametreleri Üzerinden De§er Döndürme . . . . . . . . . . . . . . . . . . 116 6.7 Dizilerin Fonksiyonlara Aktarlmas . . . . . . . . . . . . . . . . . . . . . . . . . 117 6.8 E³ simli Fonksiyonlar 6.9 Varsaylan Parametreler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 vii ÇINDEKILER 7 ³aretçiler 127 7.1 ³aretçi Tipinden De§i³kenler . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 7.2 Bellek Yönetimi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 7.3 ³aretçi - Dizi li³kisi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 7.4 ³aretçi Tipinden Parametreler 7.5 Statik De§i³kenler 7.6 Adres Aktarm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 8 Giri³-Çk³ 141 8.1 Çk³ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 8.2 Giri³ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 8.3 Ana Fonksiyona Parametre Aktarma . . . . . . . . . . . . . . . . . . . . . . . . 146 8.4 Dosyalar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 8.4.1 Dosya Açma - Kapama . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 8.4.2 Dosyada Okuma-Yazma . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 8.5 Standart Giri³ / Çk³ Birimleri . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 8.6 Hata letileri 8.7 Katarlar ile Giri³-Çk³ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 8.8 kili Dosyalar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 9 Öni³lemci 153 9.1 Makrolar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 9.2 Projeler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 10 Ba§lantl Listeler 163 10.1 Yaplara ³aretçiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 11 Rekürsiyon 171 A Simgelerin Kodlanmas 177 B Unix'de Program Geli³tirme 179 B.1 Yardmc Belgeler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 B.2 Derleme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 B.3 Editörler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 B.4 Hata Ayklayclar B.5 Ba³arm nceleme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 ÇINDEKILER viii Bölüm 1 Giri³ Bir problemi çözmek üzere bir bilgisayar program yazarken iki temel soruna çözüm getirmek gerekir: Problemin nasl temsil edilece§i. Bilgisayarlar temelde saylar üzerinde i³lem yapmak üzere tasarlanm³ makinalardr; dolaysyla tandklar varlk yelpazesi fazla geni³ de§ildir. Örne§in Türkiye'deki karayollaryla ilgili bir program yazlacaksa ³ehirlerin ve aralarndaki yollarn bir ³ekilde temsil edilmesi gerekir çünkü bilgisayarn ³ehir, yol gibi kavramlar yoktur. Bir ³ehri temsil etmek için ³ehrin ad, enlemi ve boylam kullanlabilir. Bir yolun temsili içinse farkl seçenekler dü³ünülebilir: • Yolun düz oldu§unu varsayarak bir do§ruyla göstermek (ekil 1.1a). Bu durumda yalnzca ba³langç ve biti³ ³ehirlerini (yani enlem, boylam ve isimlerini) bilmek yeterli olacaktr. Bu yöntem i³lemleri çok basitle³tirmekle birlikte gerçek durumdan büyük ölçüde sapmaya neden olur. • Yolu ucuca eklenmi³ do§ru parçalaryla göstermek (ekil 1.1b). ekilde stanbulAnkara yolu iki, stanbul-zmir yolu dört, Ankara-zmir yolu üç do§ru parçasndan olu³maktadr. Ancak bu yöntem daha zordur ve yolu ne kadar ayrntl temsil etmek isterseniz o kadar fazla do§ru parças kullanmanz gerekir. Problemi olu³turan varlklarn nasl temsil edileceklerinin belirlenmesi, problem için bir model olu³turulmas anlamna gelir. Problemin çözümünde ilk ve en önemli adm do§ru ve yeterli ayrntda bir model olu³turmaktr. Yukardaki örnekten de görülebilece§i gibi, çözece§iniz problemi nasl modelledi§iniz son derece önemlidir, çünkü çözdü§ünüz ³ey problemin kendisi de§il, sizin o problemi temsil etmek üzere tasarlad§nz modeldir. Modeliniz problemden uzaksa siz ne kadar iyi bir çözüm uygularsanz uygulayn elde edece§iniz sonuç anlamsz olur. Di§er yandan, modelin ne kadar ayrntl olmas gerekti§i, çözmek istedi§iniz problemin gereksinimleriyle belirlenir. Gerekenden daha ayrntl bir model hazrlarsanz belki daha iyi bir sonuç elde edersiniz ama o daha iyi sonuca ula³mak için harcamanz gerekecek ek çaba ya da çözümüzün gerçekleme maliyeti aradaki farka de§meyebilir. Yine yukardaki 1 2 örnekle sürdürürsek, stanbul-Ankara karayolunun 274. kilometresi gibi bilgilerden söz edecekseniz yolu do§ru parçalaryla modellemeniz gerekecektir çünkü gerçek ya³amda bu nokta büyük olaslkla o iki ³ehri birle³tiren çizginin üzerinde bir yere dü³meyecektir. Ancak yollarn yalnzca uzunluklaryla ilgileniyorsanz do§rularla modellemeniz yeterlidir; bu durumda da do§ru parçalaryla modellemek yolun uzunlu§unun bulunmasnda zorluk çkaracaktr. Istanbul Istanbul Ankara Izmir Ankara Izmir (a) (b) ekil 1.1: Karayollarnn gösterilmesi. Çözümün nasl ifade edilece§i. Bir problem için dü³ündü§ünüz çözümü ba³ka birine (insan ya da bilgisayar) anlatabilmeniz gerekir. Adm adm hangi i³lemlerin yaplaca§nn açklanmas ³eklinde anlatlan bir çözüme algoritma ad verilir. Algoritmalara günlük ya³amdan skça verilen bir örnek yemek tarieridir. A³a§da, bezelyeli Jamaika pilav yapmak için nternet'ten alnm³ bir tarif algoritma biçiminde yazlm³tr: 1. 1 1/2 kutu bezelyeyi 4-5 ncan suya koy. 2. 1/4 kutu hindistan cevizi sütü, 1 tutam kekik ve a§z tadna göre tuz ve biber ekle. 3. Bezelyeler yumu³ayncaya kadar ha³la. 4. Bir so§ann dibini ez ve 2 ncan pirinç, 1/4 kutu hindistan cevizi sütü ve 2 tutam kekik ile birlikte suya ekle. 5. Pirincin üstünden 2 cm kadar su kalacak ³ekilde fazla suyu al. 6. 5 dakika kaynat. 7. Pirinç yumu³ayncaya kadar pi³irmeye devam et. Algoritmann bir bilgisayar tarafndan yürütülebilmesi için iki önemli özellik sa§lanmaldr: • Her admda ne yaplaca§ açk olarak belli olmal, hiçbir ³ekilde yorum gerektirmemelidir. Yukardaki örnek bu bakmdan bir algoritma saylamaz çünkü pek çok admda ne yaplaca§ yoruma braklm³tr. Sözgelimi, 4-5 bardak, a§z tadna göre, bezelyeler yumu³ayncaya kadar gibi deyimler yeterince kesin de§ildir. • Sonlu sayda admda ya çözüm bulunmal ya da bulunamad§ bildirilmelidir. 3 Giri³ 1.1 Veriler Modelinizde kulland§nz büyüklükler programnzn verilerini olu³turur. Her büyüklük programda bir de§i³ken ile temsil edilir. De§i³ken aslnda o büyüklü§e verilmi³ simgesel bir isimden ba³ka bir ³ey de§ildir. De§i³kenler, programn i³leyi³i srasnda de§erler alrlar. De§i³kenlerin bellekte tutulduklar gözönüne alnrsa, de§i³ken bir bellek gözünün ad, de§er ise bu gözün içeri§idir. Örne§in, bir ³ehri modellemek için üç büyüklük öngörmü³tük: isim, enlem ve boylam. Her büyüklü§e bir de§i³ken kar³ dü³ürmemiz gerekti§inden isim bilgisini ve boylam bilgisini boylam isim, enlem bilgisini enlem de§i³kenleriyle temsil etti§imizi varsayalm. Bu durumda temsil etti§imiz ³ehre göre bu de§i³kenlere uygun de§erler vermemiz gerekir. Sözgelimi, stanbul ³ehrini temsil etmek için isim de§i³kenine stanbul, 1 29 de§erleri verilmelidir (ekil 1.2). isim enlem de§i³kenine 41, enlem "Istanbul" boylam de§i³kenine boylam 41 29 ekil 1.2: ehri temsil eden de§i³kenler ve örnek de§erler. Bir de§i³kene bir de§er verilmesi i³lemine atama denir ve sola bakan bir ok i³aretiyle gösterilir: enlem ← 41. 2 Atama i³aretinin sol tarafna bir de§i³ken ad, sa§ tarafna bir deyim yazlr. Deyim, bir de§er üreten bir hesaplama olarak tanmlanabilir. Bir deyim, tek bir de§er ya da bir de§i³ken olabilece§i gibi, bunlarn i³lemler ile çe³itli ³ekillerde ba§lanmalarndan da olu³abilir: • 41: yalnzca bir de§er • boylam: yalnzca bir de§i³ken • 4 * boylam: bir de§er ile bir de§i³kenin çarpma i³lemiyle ba§lanmas • enlem + boylam: iki de§i³kenin toplama i³lemiyle ba§lanmas 41 ← enlem atamasnn bir anlam i ← i + 1 atamas, i de§i³keninin de§erinin o anki de§erine göre bir Atama i³lemi bir matematiksel e³itlik de§ildir. Örne§in yoktur. Benzer ³ekilde, artrlmas demektir; yani de§eri bu i³lemden önce 5 ise, i³lemden sonra 6 olur. Oysa, bu bir e³itlik olsayd yanl³ olurdu (0 = 1). Örnek. Takas Programlarda skça gerekebilen i³lemlerden biri, iki de§i³kenin de§erlerini kar³lkl de§i³tir- say1 de§i³keninin de§eri 32 ve say2 de§i³keninin de§eri 154 ise bu i³lemsay1 de§i³keninin 154, say2 de§i³keninin de 32 de§erini almas istenir (ekil 1.3). mektir. Sözgelimi, den sonra Takas i³lemini yapmak üzere ³u atamalarn kullanld§n dü³ünelim: 1 Burada kuzey enlemlerinin ve do§u boylamlarnn pozitif saylarla gösterildi§i varsaylm³tr. Güney enlem- leri ve bat boylamlar negatif saylarla gösterilirse örne§in New York ³ehrinden söz edildi§inde New York, 2 boylam de§i³keni -74, enlem de§i³keni 40 de§erini almaldr. Bu i³lem için programlama dilleri genelde = ya da := i³aretini kullanrlar. isim de§i³keni 4 Veriler sayi1 sayi2 32 154 (a) Önce sayi1 sayi2 154 32 (b) Sonra ekil 1.3: Takas i³lemi. say1 ← say2 say2 ← say1 Birinci atama i³leminden (ekil 1.4a) sonra say1 de§i³keni 154 de§erini alr, ninde ise bir de§i³iklik olmaz. kinci atama i³lemi (ekil 1.4b) ise de§i³keninin o anki de§erini atad§ndan say2 say2 say2 de§i³ke- de§i³kenine say1 de§i³kenine yine 154 de§eri atanr ve sonuçta her iki de§i³ken de 154 de§erini alm³ olur (ekil 1.4c). sayi1 sayi2 32 154 (a) sayi1 sayi2 154 154 (b) sayi1 sayi2 154 154 (c) ekil 1.4: Takas i³lemi çözümü (hatal). ki atama i³leminin yetersiz oldu§u görülmektedir. Yaplmas gereken, de§i³kenlerin de§erlerini yitirmemek için, bir de§i³kenin de§erini ba³ka bir de§i³kende yedeklemektir: ara ← say1 say1 ← say2 say2 ← ara 5 Giri³ ara de§i³keni 32 de§erini alr. kinci atamada (ekil 1.5b) say2 de§i³kenine 32 de§eri atanr (ekil 1.5d). Bu atamalardan sonra ara de§i³keninin de§erinin ne oldu§unun bir önemi Birinci atama (ekil 1.5a) sonucunda say1 de§i³kenine 154, üçüncü atama (ekil 1.5c) sonucunda da yoktur. sayi1 sayi2 32 154 ara xxx (a) sayi1 sayi2 32 154 ara 32 (b) sayi1 sayi2 154 154 ara 32 (c) sayi1 154 sayi2 ara 32 32 (d) ekil 1.5: Takas i³lemi çözümü (do§ru). De§i³kenlerin, temsil ettikleri varl§a göre, bir tip leri vardr. Baz programlama yakla³mlarnda programcnn de§i³kenin hangi veri tipinden oldu§unu belirtmesi ³art ko³ulurken, bazlarnda de§i³kenin tipi, içinde kullanld§ ba§lamdan kestirilmeye çal³lr. 1.1.1 Taban Tipler En sk kullanlan de§i³ken tipi saylardr. Örnekteki enlem ve boylam de§i³kenleri duruma göre birer tamsay ya da kesirli say olarak seçilebilir. Ço§u programda gerekecek temel veri tipleri ³unlardr: tamsay Bir insann do§um yl, soyadndaki harf says, boyunun santimetre cinsinden uzunlu§u, bir i³lemin kaç kere yapld§n sayan sayaç gibi bilgiler. kesirli say Bir insann boyunun metre cinsinden uzunlu§u, iki snavdan alnan notlarn ortalamas, bir saynn karekökü gibi bilgiler. 6 Veriler mantksal Bir ö§rencinin bir dersten ba³arl olup olmad§, bir insann onsekiz ya³ndan büyük olup olmad§, kullancnn bast§ tu³un bir rakam tu³u olup olmad§ gibi bilgiler. Bu tipten de§i³kenler Do§ru ya da Yanl³ 3 de§erini alabilirler. Birinin adnn ba³ har, programn çal³mas srasnda Devam simge musunuz (E/H)? etmek istiyor sorusuna kar³lk hangi tu³a bast§, bir tarih bilgisinde gün, ay ve yl arasna hangi i³aretin konaca§ (nokta, tire, bölü, vs.) gibi bilgiler. Simgeler ço§unlukla tek trnak i³aretleri içinde yazlrlar: 'E', ' ?', '4' gibi. Burada ayrm yaplmas gereken önemli bir nokta, rakamlar ile rakamlar gösteren i³aretleri birbirine kar³trmamaktr. Örne§in 5 rakam ile '5' simgesi farkl büyüklüklerdir (bkz. Ek A). katar Bir insann ad, do§du§u ³ehir, bir kitabn ISBN numaras gibi bilgiler katarlarla temsil edilmeye uygundur. Katarlar ço§unlukla çift trnak içinde yazlrlar: Dennis Ritchie, 0-13-110362-8 gibi. Bir büyüklük bütünüyle rakamlardan olu³sa bile baz durumlarda say yerine katarla göstermek daha uygun olabilir. Bir de§i³kenin ancak üzerinde aritmetik bir i³lem yaplacaksa say tipinden olmas anlaml olur. Örne§in, stanbul Teknik Üniversitesi'nde ö§renci numaralar dokuz haneli tamsaylardr ancak bunlar tamsay olarak temsil etmenin bir anlam yoktur çünkü ö§renci numaralar üzerinde aritmetik i³lem yapmak gerekmeyecektir (iki ö§rencinin numaralarn toplamak ya da çarpmak gibi). 1.1.2 Kaytlar Birden fazla büyüklü§ü ortak bir tip altnda toplarlar. Burada gruplanan büyüklükler ayn tipten ya da farkl tiplerden olabilir. Örne§in bir ³ehri temsil etmek üzere kullanlan üç büyüklük (³ehrin ismi, enlemi ve boylam) birle³tirilerek ³ehirleri gösterecek bir kent veri tipi olu³turu- labilir. Bu veri tipinin biri bir katar (³ehir ismi), di§er ikisi de birer kesirli say olan (enlem ba³kent de§i³keni tanmlanismi, ba³kent kentinin enlemi ve boylam) üç alan olacaktr (ekil 1.6a). Bu tipten diyelim bir d§nda, de§i³kenin alanlarna eri³mek için ba³kent kentinin gibi deyi³ler kullanlmaldr. Bu amaçla ço§unlukla noktal gösterilimden yararlanlr; örne§in ba³kent de§i³keninin isim alanna Ankara de§erini atamak için ba³kent.isim ← Ankara yazlr (ekil 1.6b). Kaytlar alan olarak ba³ka kaytlar da içerebilirler. Örne§in, bir yolu temsil için yolun kodu (katar), uzunlu§u (tamsay) ve ba³langç ve biti³ kentleri bilgileri kullanlabilir (ekil 1.7). Eri³im, tek düzeyli kaytlara benzer ³ekilde yaplr (tem.son_kent.isim tem.kod ← E-6 1.1.3 ← Ankara ve gibi). Diziler Ayn tipten varlklardan olu³an bir grubu tek bir çat altna toplamak için kullanlrlar. Bir dizinin bütünü tek bir de§i³ken olarak de§erlendirilir. Örne§in 50 ö§rencili bir snfta bir snavdan alnan notlar i³lenece§inde, her bir ö§rencinin notunu göstermek üzere · · ·, not50 3 gibi ayr ayr 50 tamsay de§i³ken tanmlanaca§na, Bu de§erler örneklerde D ve Y ³eklinde ksaltlacaktr. notlar not1, not2, adnda 50 elemanl 7 Giri³ baskent kent kent isim isim enlem enlem boylam boylam (a) "Ankara" (b) ekil 1.6: Kayt tipinden de§i³ken örne§i. tem yol kod uzunluk son_kent ilk_kent isim isim enlem enlem boylam boylam ekil 1.7: çiçe kaytlar tipinden de§i³ken örne§i. 8 Veriler bir tamsay dizisi tanmlanabilir. Ayr ayr de§i³kenler bellekte da§nk bir yap olu³tururken dizinin elemanlar bellekte birbirini izleyen gözlere yerle³tirilir (ekil 1.8). not4 not13 not1 not22 notlar 1 2 3 50 ekil 1.8: Dizi tipinden de§i³ken örne§i. Elemanlar üzerinde i³lem yapmak için dizinin kaçnc elemanndan söz etti§inizi söylemeniz gerekir. Sözgelimi, 22. ö§rencinin ald§ not 95 ise yaplacak atama 4 gösterilir . notlar22 ← 95 ³eklinde Katarlar ço§u programlama dilinde simge dizileri olarak görülürler; yani bir katar her bir eleman bir simge olan bir dizidir. Sözgelimi, birinin ad ve soyad adsoyad isimli bir de§i³- kende tutulacaksa, bu de§i³ken simge dizisi tipinden olacaktr (ekil 1.9). Örnekte adsoyad7 büyüklü§ünün de§eri 'D', adsoyad1 büyüklü§ünün de§eri ' ' (bo³luk) simgesidir. adsoyad ’D’ ’e’ ’n’ ’n’ ’i’ ’s’ ’ ’ ’R’ ’i’ ... 1 2 3 4 5 6 7 8 9 10 ekil 1.9: Katar tipinden de§i³ken örne§i. Dizilerle kaytlar birlikte de kullanlabilir. Sözgelimi, bir saynn asal çarpanlarn temsil etmek üzere bir dizi kullanabiliriz (6776 = 23 ∗ 71 ∗ 112 ). Dizinin her bir eleman bir asal çarpan gösterir, her bir asal çarpan da bir taban ve bir üs de§erinden olu³tu§u için bir kaytla temsil edilir (ekil 1.10). Elemanlara eri³im daha önce belirtilen kurallarda görüldü§ü gibi olacaktr: ç arpanlar2 .taban ← 7 carpanlar taban 2 taban 7 taban 11 ... üs 3 üs 1 üs 2 ... 1 2 3 ekil 1.10: Kayt dizisi tipinden de§i³ken örne§i. 4 Bu i³lem için programlama dillerinde kö³eli ayraçlar kullanlr: notlar[22] gibi. 9 Giri³ Örneklerden de görülebilece§i gibi, bir dizinin bütünüyle temsil edilmesi için dizinin eleman de§erlerinin yansra kaç eleman oldu§u bilgisinin de bir ³ekilde tutulmas gerekir. 1.2 Algoritmalar Algoritmalar göstermek için skça kullanlan yöntemlerden biri ak³ çizenekleridir. Ak³ çizeneklerinde ³u simgeler kullanlr: • Kutu: Bir i³lemi gösterir. Kutunun içine i³lemi anlatan bir komut yazlr. • Ok: Ak³ yönünü belirtir. Algoritmann bir sonraki admnn hangisi oldu§unu gösterir. • E³kenar dörtgen: Karar noktalarn gösterir. çine yazlan sorunun yantnn do§ru ya da yanl³ olmasna göre farkl bir yöne gidilmesini sa§lar. • Paralelkenar: Giri³/çk³ i³lemlerini gösterir. Algoritmann tamam belirtilmi³se ak³ çizene§i kö³eleri yuvarlatlm³ kutular içinde bulunan ba³la komutuyla ba³lar ve dur komutuyla biter. Algoritmann tamam de§il, yalnzca ilgilenilen bir parças belirtilmek isteniyorsa çizenek bo³ bir yuvarlak ile ba³lar ve bo³ bir yuvarlak ile sona erer. Ak³ çizene§inin büyümesi ve topluca görülmesinin zorla³mas durumunda ak³ çizene§i parçalarnn ba³ndaki ve sonundaki yuvarlaklarn içine etiketler yazarak hangi parçann hangi parçaya nereden ba§land§ belirtilebilir. Algoritmalarn örnek de§erler üzerinde i³leyi³lerini daha kolay izleyebilmek amacyla tablolar kullanlabilir. Tablonun her bir satr algoritmann bir admna kar³ dü³er ve o admda çe³itli de§i³kenlerin ya da deyimlerin aldklar de§erlerin görülmesini sa§lar; yani de§i³kenler ve deyimler tablonun sütunlarn olu³turur. Örnek. En Büyük Eleman Bulma Bir dizinin en büyük elemann bulma algoritmasn, 50 ö§rencili bir snfta bir snavdan alnan en yüksek notun bulunmas örne§i üzerinde inceleyelim. Bu i³i yapacak bir algoritma ³öyle yazlabilir: 1. Dizideki ilk notu en yüksek not olarak seç ve sray ikinci ö§renciye geçir. 2. Srada ö§renci varsa 3. adma, yoksa 5. adma git. 3. Sradaki ö§rencinin notu ³u ana kadarki en yüksek nottan büyükse bu yeni notu en yüksek not olarak seç. 4. Sray bir sonraki ö§renciye geçir ve 2. adma dön. 5. En yüksek notu bildir. 10 Algoritmalar Daha çok gündelik dil kullanlarak yazlm³ bu algoritmay biçimsel olarak ifade edebilmek için ö§rencilerin notlarn 50 elemanl bir tamsay dizisi (bu de§i³kene notlar adn verelim), o ana kadar bulunmu³ en yüksek notu bir tamsay (max de§i³keni diyelim) ile ve sradaki ö§rencinin kaçnc ö§renci oldu§unu tutmak için bir sayaç (i de§i³keni) tanmlarsak: 1. max ← notlar1 , i←2 2. i ≤ 50 3. notlari > max 4. i ← i + 1 ise 3. adma, de§ilse 5. adma git. ise max ← notlari ve 2. adma dön. 5. en yüksek not: max Yukarda verilen algoritma örne§inin ak³ çizene§i ekil 1.11'de görüldü§ü gibidir. 50 eleman yerine 6 elemanl bir dizide en büyük elemann bulunmas algoritmasnn i³leyi³i Tablo 1.1'de verilmi³tir (notlarn srasyla 43, 74, 65, 58, 82, 37 olduklar varsaylm³tr, sürme ko³ulu i ≤ 6 ³eklinde de§i³melidir). basla max ← notlar1 i←2 i ≤ 50 Y D notlari > max Y bas: max D dur max ← notlari i←i+1 ekil 1.11: En büyük eleman bulma algoritmasnn ak³ çizene§i. Örnek. Say Tahmin Etme Arkada³nzn önceden aranzda kar³la³trd§nz iki snr arasnda bir tamsay tuttu§unu ve sizin bu sayy bulmaya çal³t§nz varsayn. Siz bir say söyledi§inizde arkada³nz, tuttu§u 11 Giri³ max 43 74 i 2 3 4 5 6 7 82 D D D D D Y i ≤ 6 (2 < 6) (3 < 6) (4 < 6) (5 < 6) (6 = 6) (7 > 6) notlari > max D (74 > 43) Y (65 < 74) Y (58 < 74) D (82 > 74) Y (37 < 82) Tablo 1.1: En büyük eleman bulma algoritmasnn örnek de§erlerle i³leyi³i. say sizin söyledi§inizden büyükse büyük, küçükse küçük diyecek, do§ru sayy söyledi§inizde oyun sona erecektir. Bu oyunu oynarken nasl bir algoritma kullanrsnz? Kararla³trd§nz snr de§erlerinden küçük olann taban, büyük olann tavan isimli birer de§i³ken ile gösterelim. Ayrca, biri arkada³nzn tuttu§u sayy temsil edecek (tutulan isimli), di§eriyse sizin söyledi§iniz sayy temsil edecek (söylenen isimli) iki tamsay de§i³ken daha kullanalm. Algoritma 1. Alt snrdan ba³la, bulana kadar birer artrarak ilerle. 1. söylenen ← taban 2. söylenen = tutulan 3. söylenen ← söylenen + 1 Algoritma 2. ise buldun, dur ve 2. adma dön Deneme aral§nn ortasndaki sayy söyle. Büyük derse deneme aral§n ³u anki aral§n üst ksmna, küçük derse alt ksmna daralt. Bu algoritmay gerçeklemek için o anki deneme aral§nn alt ve üst snrlarn gösterecek iki yeni de§i³kene (alt ve üst diyelim) gerek duyulur. 1. alt ← taban, üst ← tavan 2. söylenen ← (alt + üst) / 2 3. söylenen = tutulan ise buldun, dur 4. söylenen > tutulan ise üst ← söylenen - 1, de§ilse alt ← söylenen + 1 ve 2. adma dön. Bu algoritmann ak³ çizene§i ekil 1.12'de verilmi³tir. Alt snrn 1, üst snrn 63 oldu§unu ve arkada³nzn 19 saysn tuttu§unu varsayarsak, her turda de§i³kenlerin aldklar de§erler Tablo 1.2'de görüldü§ü gibi olacaktr. 1.2.1 Algoritmalarn Kar³la³trlmas Yukardaki örneklerde görüldü§ü gibi, ço§u zaman bir problemi çözmenin birden fazla yolu vardr. Ayn problemi çözen iki algoritmadan hangisinin daha iyi oldu§una karar vermek üzere algoritmalar iki özelliklerine göre kar³la³trlrlar: 12 Algoritmalar basla alt ← taban üst ← tavan söylenen ← (alt + üst) / 2 söylenen = tutulan D bas: söylenen Y Y söylenen > tutulan alt ← söylenen + 1 D dur üst ← söylenen - 1 ekil 1.12: Say tahmin etme algoritmasnn ak³ çizene§i. alt 1 17 19 üst 63 31 23 19 söylenen 32 16 24 20 18 19 söylenen = tutulan Y (32 > 19) Y (16 < 19) Y (24 > 19) Y (20 > 19) Y (18 < 19) D (19 = 19) Tablo 1.2: Say tahmin etme algoritmasnn örnek de§erlerle i³leyi³i. 13 Giri³ 1. Hzlar: Hangi algoritma çözümü daha çabuk buluyor? Bu sorunun yant da iki durum için incelenir: (a) en kötü durumda (b) ortalama durumda Say bulma için verilen yukardaki iki algoritmay bu bakmdan kar³la³trrsak, birinci algoritmann örnek de§erlerle sayy en kötü durumda 63, ortalama durumda 32 denemede bulaca§ görülür. Oysa ikinci algoritma sayy en kötü durumda 6, ortalama durumda 5.09 denemede bulur. 2. Harcadklar yer: Hangi algoritma bellekte daha fazla yer kullanyor? Say bulma algoritmalarnda gördü§ümüz gibi, ikinci algoritma birinci algoritmann kullandklarna ek olarak iki de§i³ken daha gerektirmektedir. Günümüzde bilgisayarlarn kapasiteleri eskiye oranla çok yükselmi³ oldu§u için harcanlan yer ölçütünün önemi göreli olarak azalm³tr. Yine de projenin boyutuna ve çal³lan ortamn yeteneklerine göre algoritma geli³tirirken hzn yansra harcanacak yerin de gözönüne alnmas gerekebilir. Algoritmalarn hzlarnn ve harcadklar yerlerin incelenmesi algoritma analizi dalnn konusudur. Bu dalda geli³tirilmi³ bulunan karma³klk kuram, benzer problemlerin çözümü için önerilen algoritmalarn kar³la³trlmasnda ba³vurulan en önemli araçtr. 1.3 Blok Yapl Programlama Blok yapl programlamann temelinde blok kavram yatar. Blok, birbiriyle ili³kili komutlarn olu³turdu§u gruptur. Her algoritma birbirlerine çe³itli ³ekillerde ba§lanm³ bloklardan olu³ur. Bloklar ba§lamann üç yolu vardr: Sra Bloklarn yukardan a³a§ya do§ru yazldklar srayla yürütülürler (ekil 1.13a). Sra yaps, komutlarn yazl³ sralarnn önemli oldu§unu vurgular. Bölüm 1.1'de görülen takas örne§i için verilen do§ru çözümde yaplan üç atama i³leminin sralar de§i³tirilirse varlacak sonuçlar yanl³ olabilir. Seçim Bir ko³ulun do§ru olup olmamasna göre farkl bir blo§un yürütülmesidir. Yani ko³ul do§ruysa bir blok, yanl³sa ba³ka bir blok yürütülür (ekil 1.13b). ki bloktan herhangi biri bo³ olabilir, yani ko³ul do§ruysa ³u blo§u yürüt, yanl³sa hiçbir ³ey yapma ³eklinde bir yap kurulabilir. Yineleme Belirli bir ko³ul sa§land§ sürece (ya da sa§lanana kadar) bir blok yinelenebilir. Ak³ çizene§inden (ekil 1.13c) görülebilece§i gibi, bu yapdan çklabilmesi için blo§un ko³ulu de§i³tiren bir komut içermesi gerekir, aksi durumda ko³ul ba³langçta do§ruysa hep do§ru olaca§ndan yapdan çklamayacaktr. Yine ak³ çizene§inden görülebilecek bir di§er özellik de, ko³ul ba³langçta yanl³sa blo§un hiç yürütülmeyece§idir. Baz uygulamalarda blok ko³uldan önce de yer alabilir (ekil 1.12 böyle bir örnektir); böyle durumlarda ko³ul ba³tan yanl³ olsa bile blok en az bir kere yürütülür. 14 Soyutlama D blok1 blok2 Y kosul kosul blok1 blok2 Y D blok (a) (b) (c) ekil 1.13: Temel yaplarn ak³ çizenekleri. Bu yaplarn ortak bir özelli§i, hepsinin bir giri³ ve bir çk³larnn olmasdr. Böylelikle bir blo§un çk³ öbür blo§un giri³ine ba§lanabilir; ba³ka bir deyi³le, bloklar ardarda eklenebilir. Ayrca, bir blo§un içinde ba³ka bir blok yer alabilir. ekil 1.12'de ³uluyla belirlenen seçim yaps, söylenen = tutulan söylenen > tutulan ko- ko³uluyla belirlenen yineleme yapsnn bir alt bile³eni durumundadr. Bir programn okunmasn ve anla³lmasn en çok zorla³tran etkenlerden biri programda yer alan dallanma komutlardr. imdiye kadar yazd§mz baz algoritmalarda geçen n. adma git tipi komutlar için -programlama dillerinde genellikle goto olarak adlandrlan- bir komut bulunmas gerekti§i dü³ünülebilir (özellikle yineleme yaplar için). Ancak blok yapl programlamada yineleme için özel yaplar vardr ve 1.4 goto 5 komutunun kullanlmamas özendirilir. Soyutlama Programlamann temel düzeneklerinden biri soyutlama kavramdr. Soyutlama, programn yapaca§ i³in daha küçük ve birbirinden olabildi§ince ba§msz alt-i³lere bölünmesidir. Alt-i³ler de, benzer ³ekilde, yapacaklarn alt-alt-i³lere bölebilirler (ekil 1.14). Bu tip tasarma yukardan a³a§ya tasarm ad verilir. 6 Her i³ bir yordam (C dilindeki adyla fonksiyon ) tarafndan gerçeklenir. Ana-yordamn görevi, alt-i³leri gerçekleyen yordamlar ba³latmak ve bunlar arasnda e³güdümü sa§lamaktr. Bir üstyordam, kulland§ alt-yordamlarn nasl çal³tklaryla de§il, yalnzca sonuçlaryla ilgilenir. Soyutlamann kazandrdklar ³öyle özetlenebilir: • Bir i³i gerçekleyen yordam yazlrken, kulland§ alt-yordamlarn ayrntlaryla u§ra³lmaz; alt-yordamn do§ru çal³t§ varsaylarak yordamn kendi i³ine yo§unla³labilir. Böy- 5 Bu konuyla ilgili olarak, Edsger W. Dijkstra'nn Go To Statement Considered Harmful ba³lkl klasik makalesini 6 http://www.acm.org/classics/oct95/ adresinde bulabilirsiniz. Bu konuyla ilgili olarak, Niklaus Wirth'ün Program Development by Stepwise Renement ba³lkl klasik makalesini http://www.acm.org/classics/dec95/ adresinde bulabilirsiniz. 15 Giri³ ana-is alt-is-1 alt-is-2 alt-is-1a alt-is-3 alt-is-3a alt-is-3b ekil 1.14: Ana i³in alt i³lere bölünmesi. lelikle büyük ve çözülmesi zor olan bir sorunla u§ra³mak yerine, her biri küçük ve çözülebilir sorunlarla u§ra³lr ve bunlar daha sonra biraraya getirilir. • Programn bakm kolayla³r. Alt-yordamlarn çal³malar birbirlerinden ba§msz oldu§undan bir alt-yordamda bir de§i³iklik yapld§nda bunu kullanan üst-yordam (üstyordamla olan etkile³im de§i³medi§i sürece) de§i³iklikten etkilenmez. Yordamlar olabildi§ince genel amaçl yazlmaldr. Sözgelimi bir yordamn i³i BL105E dersini alan ö§rencilerin ylsonu snav notlarnn en büyü§ünü bulmak ³eklinde tanmlanabilir. Oysa i³i herhangi bir dizinin en büyü§ünü bulmak olarak tanmlanan bir yordam geli³tirmek ve bu yordam kullanrken hangi dizinin en büyü§ünün bulunmasnn istendi§i belirtmek daha etkin bir çal³ma biçimidir. Bu durumda hangi dizi üzerinde i³lem yaplaca§ bilgisi yordamn giri³ parametresi olur. Yordam, çal³mas sonucu üretti§i de§eri çk³ parametresi olarak döndürür. Örnekteki yordam kullanlrken giri³ parametresi olarak BL105E dersini alan ö§rencilerin ylsonu snav notlar verilirse snavda alnan en yüksek not, Los Angeles Lakers basketbol takmnn oyuncularnn ayakkab numaralar belirtilirse takmn en büyük ayakl oyuncusunun ayakkab numaras çk³ parametresi olur. Örnek. En Büyük Ortak Bölen Bulma ki saynn en büyük ortak bölenini bulma i³i ³u ³ekilde alt i³lere bölünebilir: 1. Birinci sayy asal çarpanlarna ayr. 2. kinci sayy asal çarpanlarna ayr. 3. Saylarn ortak çarpanlarn belirleyerek en büyük ortak bölenin asal çarpanlarn bul. 4. Bir önceki admda belirledi§in asal çarpanlardan en büyük ortak böleni hesapla. Saylarn 9702 ve 945 olduklar varsaylrsa: 16 Soyutlama 1 * 32 * 72 * 111 1. 9702 = 2 * 3 * 3 * 7 * 7 * 11 = 2 3 * 51 * 71 2. 945 = 3 * 3 * 3 * 5 * 7 = 3 2 * 71 3. ortak çarpanlar: 3 4. en büyük ortak bölen: 63 1. ve 2. admlar için herhangi bir sayy asal çarpanlarna ayran bir yordam yazlabilir ve asal çarpanlarna ayrlacak say bu yordama parametre olarak yollanabilir. Benzer ³ekilde, 3. admdaki ortak çarpanlarn bulunmas i³i de bir alt-yordama verilebilir. 4. admda ortak çarpanlardan en büyük ortak bölenin hesaplanmas i³lemleri için alt-yordam kullanmann fazla bir anlam yoktur, ana yordama brakmak daha yerinde olur. Böylece ekil 1.15'deki yap ortaya çkar. Örnek saylar üzerinde yordamlarn hangi giri³ ve çk³ parametreleriyle çal³tklar ekil 1.16'da verilmi³tir. 1. sayi en büyük ortak bölen hesapla 2. sayi 1. sayinin çarpanlari 2. sayinin çarpanlari 1. sayinin çarpanlari asal çarpanlara ayir ortak çarpanlar 2. sayinin çarpanlari ortak çarpanlari bul ekil 1.15: En büyük ortak bölen hesaplama algoritmasnn yukardan a³a§ya tasarm. Asal çarpanlara ayrma algoritmasnda görülen bir sonraki asal sayy bulma i³i de asal çarpanlarna ayrma i³inin bir alt-i³i olarak dü³ünülerek bir ba³ka yordama braklabilir. Bu yordam kendisine parametre olarak gönderilen saydan bir sonraki asal sayy bularak sonucu geri yollayacaktr. Benzer ³ekilde bu yordam da bir saynn asal olup olmad§n snamak üzere ba³ka bir yordamdan yararlanmak isteyebilir. Bu örnek için verilen yordamlar gerçekleyecek algoritmalar bölümün sonundaki uygulamada verilmi³tir. Örnek. Euclides Algoritmas Yukarda verilen algoritmann en önemli sorunu, özellikle büyük saylar asal çarpanlarna ayrmann zorlu§udur. Bilinen en eski algoritma örneklerinden biri olan Euclides algoritmas, iki saynn en büyük ortak böleninin çarpanlara ayrmadan hzl biçimde hesaplanmasn sa§lar. En büyük ortak böleni bulunacak saylardan büyük olanna a, küçük olanna b dersek: 17 Giri³ 9702 en büyük ortak bölen hesapla 945 2 × 32 × 72 × 11 33 × 5 × 7 32 × 7 2 × 32 × 72 × 11 33 × 5 × 7 asal çarpanlara ayir ortak çarpanlari bul ekil 1.16: Örnek saylar üzerinde en büyük ortak bölen hesaplama algoritmasnn i³leyi³i. a = q 1 b + r1 ³eklinde yazlabilir. Burada ile b r1 = 0 ise iki saynn en büyük ortak böleni saylarnn en büyük ortak böleni b ile r1 b'dir. De§ilse a saylarnn en büyük ortak bölenine e³ittir. Dolaysyla, bölümden kalan 0 olana kadar a³a§daki e³itlikler yazlabilir: b = q 2 r1 + r2 r1 = q 3 r 2 + r 3 ... rn−2 = qn rn−1 + rn rn−1 = qn+1 rn + rn+1 (rn+1 = 0) Bu durumda a ile b'nin en büyük ortak böleni rn 'dir. Yine a = 9702, b = 945 örne§ini alrsak: 9702 = 10 ∗ 945 + 252 945 = 3 ∗ 252 + 189 252 = 1 ∗ 189 + 63 189 = 3 ∗ 63 + 0 a, küçük olann b r de§i³keninde tutarsak (kalan i³lemi % Her denklem için en büyük ortak böleni alnacak saylardan büyük olann de§i³keninde, bu ikisinin bölümünden kalan de§eri de i³aretiyle gösterilsin), bu algoritma bir yineleme yapsyla gerçeklenebilir. Bir bölme i³leminde 18 Soyutlama her zaman kalan, bölenden küçük olaca§ için her yinelemede de r'nin de§erini alarak ilerlenir ve b a de§i³keni 0 oldu§unda en büyük ortak bölen a b'nin, b de§i³keni de§i³keninde elde edilmi³ olur. Bu algoritmann ak³ çizene§i ekil 1.17'de, örnek de§erlerle i³leyi³i Tablo 1.3'de verilmi³tir. 7 D sayi1 > sayi2 Y a ← sayi1 b ← sayi2 a ← sayi2 b ← sayi1 b>0 Y D bas: a r←a%b a←b b←r ekil 1.17: Euclides algoritmasnn ak³ çizene§i. a 9702 945 252 189 b 945 252 189 63 r 252 189 63 0 Tablo 1.3: Euclides algoritmasnn örnek de§erlerle i³leyi³i. Uygulama: Algoritmalar Örnek. Asal Çarpanlarn Bulunmas Herhangi bir saynn asal çarpanlarna ayrlmas için kullanlabilecek bir algoritma ekil 1.18'de verilmi³tir. Bu algoritmada 7 x asal çarpanlarna ayrlacak sayy, c çarpan olup olmad§ o anda Orijinal haliyle algoritmada bölmeden kalan i³lemi yerine çkartma i³lemi kullanlyordu. Bölmeden kalan i³lemi algoritmann önemli ölçüde hzlanmasn sa§layan bir de§i³iklik olarak sonradan getirilmi³ bir yöntemdir. 19 Giri³ snanmakta olan asal sayy, u da sradaki çarpann kuvvetini gösterir. 945 says örnek olarak alnrsa algoritmann i³leyi³i Tablo 1.4'de verilmi³tir. c←2 x>1 Y D x%c=0 Y D c bir carpandir u←0 x%c=0 Y D u←u+1 x←x/c c ← sonraki asal sayi ekil 1.18: Bir sayy asal çarpanlarna ayrma algoritmas. Örnek. Ortak Çarpanlarn Bulunmas ki saynn çarpanlarndan en büyük ortak bölenin çarpanlarn bulma i³ini yapacak yordamn algoritmas geli³tirilirken, asal çarpanlara ayrma yordamnn çal³ma ³ekli nedeniyle çarpanlarn küçükten büyü§e do§ru sral olduklar varsaylabilir. Bu varsayma gören çal³an algoritma ekil 1.19'da verilmi³tir. Bu algoritmada carpanlar1 birinci saynn asal çarpanlar dizisini, carpanlar2 ikinci saynn asal say çarpanlar dizisini, c1 birinci saynn sradaki asal çarpann, c2 de ikinci saynn sradaki asal çarpann gösterir. Her iki dizinin elemanlarna eri³mek için de srasyla i1 ve i2 sayaç de§i³kenleri kullanlm³tr. Örnek dizilerle algoritmann i³leyi³i Tablo 1.5'de verilmi³tir. 20 Soyutlama x 945 315 105 35 7 1 2 3 x > 1 D (945 > 1) D (945 > 1) 5 D (35 > 1) 7 D (7 > 1) 11 Y (1 = 1) c Y D D D D Y D D Y D D Y x % c = 0 (945 mod 2 = (945 mod 3 = (945 mod 3 = (315 mod 3 = (105 mod 3 = (35 mod 3 = (35 mod 5 = (35 mod 5 = (7 mod 5 = (7 mod 7 = (7 mod 7 = (1 mod 7 = 1) 0) 0) 0) 0) 2) 0) 0) 2) 0) 0) 1) carpan u 3 0 1 2 3 5 0 1 7 0 1 Tablo 1.4: Asal çarpanlarna ayrma algoritmasnn i³leyi³i. c1 c2 taban 1 2 3 3 2 < 3 2 3 2 7 1 11 3= 3 1 7 > 5 1 7 7= 7 5 us carpan 2 < 3 3 2 1 < 2 7 1 - Tablo 1.5: Ortak çarpanlar bulma algoritmasnn i³leyi³i. 21 Giri³ c1 ← carpanlar11, c2 ← carpanlar21 i1 ← 1, i2 ← 1 c1 ve c2 bos değil Y 1 D c1.taban < c2.taban D i1 ← i1 + 1 c1 ← carpanlar1i1 Y c1.taban > c2.taban D i2 ← i2 + 1 c2 ← carpanlar2i2 Y D c1.us < c2.us c1 bir carpandir Y c2 bir carpandir i1 ← i1 + 1, i2 ← i2 + 1 c1 ← carpanlar1i1, c2 ← carpanlar2i2 ekil 1.19: Ortak çarpanlar bulma algoritmas. 22 Giri³ / Çk³ 1.5 Giri³ / Çk³ Bir programlama dilinin kullanlabilir olmas için dilde blok yapl programlamann kavramlarn desteklemenin d³nda baz gereklilikler de yerine getirilmelidir: Giri³ Bir program her seferinde ayn veri de§erleri üzerinde çal³maz, i³leyece§i verileri çal³ma srasnda bir ³ekilde ö§renmesi gerekir. Bunun en sk kar³la³lan yöntemi verileri program kullanan ki³iye sormak olmakla birlikte verileri bir dosyadan okumak ya da ortamdan ö§renmek (sözgelimi odann scakl§n ölçen bir duyargadan almak) gibi seçenekler de bulunabilir. Programlama dillerinin girdi komutlar giri³ birimlerinden aldklar de§erleri de§i³kenlere aktarrlar. Aksi belirtilmedikçe standart giri³ birimi kullancnn tu³takmdr. Çk³ Program, verilerin i³lenmesi sonucu elde etti§i sonuçlar bir ³ekilde de§erlendirmelidir. En sk görülen yöntem sonucun kullancnn ekranna yazlmasdr ama giri³te oldu§u gibi sonuçlarn bir dosyaya yazlmas ya da ortama gönderilmesi (oda scakl§n denetleyen klimaya bir sinyal yollanmas gibi) sözkonusu olabilir. Programlama dillerinin çkt komutlar, de§i³ken de§erlerini istenen çk³ birimine yönlendirirler. Aksi belirtilmedikçe standart çk³ birimi kullancnn ekrandr. Programn çal³mas srasnda kar³la³lan hata durumlarnn bildirilmesi de çktnn bir parçasdr. Ancak, hatalarn daha kolay farkedilmelerini sa§lamak amacyla, bu iletilerin normal çkt iletilerinden ayrlabilmeleri istenir. Bu nedenle, hata iletileri hata birimine yönlendirilir. Aksi belirtilmedikçe bu birim -standart çk³ta oldu§u gibi- kullancnn ekrandr. Bu notlarda i³lenecek örnek programlarda çal³ma hep ayn ³ekilde olacaktr: verilerin girilmesi, i³lenmesi, sonuçlarn gösterilmesi. Bu tip programlara konsol program, komut satr program ya da metin kipi program gibi adlar verilir. Grak arayüzle çal³an programlar ise olaya dayanan bir mantkla çal³rlar. Program çal³maya ba³lad§nda kullancyla ileti³imi için gerekli arayüzü kurar (pencere çizer, menü olu³turur, dü§me koyar, v.b.) ve sonra kullancnn bir edimde bulunmasn bekler. Kullancnn edimine göre ilgili yordamlar çal³trr. 1.6 Program Geli³tirme Bir programn geli³tirilmesi çe³itli a³amalardan olu³ur: Tasarm Bu a³amada yazlacak program ka§t üzerinde tasarlanr. Yani programn algorit- masna, hangi programlama dilinin kullanlaca§na, kullancyla nasl bilgi al³veri³inde bulunulaca§na, ksacas neyin nasl yaplaca§na karar verilir. Dikkatli bir tasarm, programn hem geli³tirilmesinde hem de bakmnda büyük kolaylklar sa§lar. Kodlama Bu a³amada program tasarm srasnda verilen kararlara göre bir programlama di- 8 Kaynak kodunu bilgisayar liyle yazlr. Bunun sonucunda yazlmn kaynak kodu olu³ur. ortamnda olu³turmak için editör ad verilen yazlmlar kullanlr. 8 Metinde bunda sonra geçen kod sözcü§ü aksi belirtilmedikçe kaynak koduna kar³ dü³ecektir. 23 Giri³ Snama Bu a³amada program çal³trlarak çe³itli senaryolar için do§ru sonuçlar üretip üret- medi§ine, beklendi§i gibi davranp davranmad§na baklr. Bu i³lemin etkinli§i gözönüne alnan senaryolarn gerçekte olu³abilecek durumlarn ne kadarn örttü§üyle ba§lantldr. Hata Ayklama Bu a³amada snama a³amasnda bulunan hatalarn nedenleri belirlenerek gerekli düzeltmeler yaplr. Programlarn ilk yazldklar ³ekliyle do§ru olmalar neredeyse olanakszdr. Hatta üstüne çok çal³lm³, pek çok hatas bulunup düzeltilmi³ programlarda bile bütün hatalarn bulunup düzeltilmi³ olmas son derece dü³ük bir olaslktr. Ayrca programlara yeni yetenekler eklendikçe yeni hatalar olu³aca§ndan a³a§ yukar hiçbir program hiçbir zaman tam olarak hatasz olmayacaktr. Hata ayklama i³lemine yardmc olmak üzere hata ayklayc ad verilen yazlmlar kullanlr. Programlarda iki tür hata sözkonusu olabilir: 1. Yazm hatalar: Programcnn yazd§ baz komutlar kulland§ programlama dilinin kurallarna uymuyordur. 2. Mantk hatalar: Programcnn yazd§ kod dilin kurallar açsndan do§rudur ama çal³trlmasnda sorun çkar. Sözgelimi bir tamsayy ba³ka bir tamsay de§i³kene bölmek geçerli bir i³lemdir ama bölen say 0 olursa bu i³lem gerçekle³tirilemez. Bu tür hatalara çal³ma-zaman hatas da denir. 1.6.1 Programlarn De§erlendirilmesi Bu a³amalar sonucunda ortaya çkan bir programn iyi bir program olup olmad§nn, ya da ne kadar iyi bir program oldu§unun de§erlendirilmesinde ³u ölçütlere ba³vurulur: Etkinlik Bu konu algoritmalarn kar³la³trlmalarnda kullanlan ölçütlerle ayndr. Program ne kadar hzl çal³yor? Düzgün kullanlabilmesi için ne kadar sistem kayna§ gerekiyor (hangi i³lemci, ne kadar bellek, ne kadar disk, v.b.?). Sa§lamlk Program, kullancnn yapaca§ kullanm hatalarna kar³ dayankl m? Sözgelimi, kendisine bir yl bilgisi soruldu§unda kullanc yanl³lkla (ya da kötü niyetle) bir isim yazarsa ne oluyor? Ta³nabilirlik Program, üzerinde fazla de§i³iklik yaplmas gerekmeden, ba³ka bir donanm ve ba³ka bir i³letim sistemi üzerinde çal³acak hale getirilebiliyor mu? Anla³labilirlik Ba³ka biri program okudu§unda anlayabilecek mi? Hatta üstünden bir süre geçtikten sonra kendiniz bakt§nzda anlayabilecek misiniz? Bakm kolayl§ Programda hata oldu§unda hatann kayna§nn belirlenmesi ve düzeltilmesi kolay m? Geli³tirilebilirlik Program yeni yeteneklerin eklenmesiyle geli³tirilmeye açk m? Bu tip ek- lemelerin yaplmas kolay m? Program Geli³tirme 24 Geli³tirme a³amalarnda daha az sorunla kar³la³mak ve daha kaliteli yazlmlar üretmek için çe³itli yöntemler geli³tirilmi³tir. Bu yöntemlerin temel fark, problemin nasl modellenece§ine ili³kin yakla³mlardr. Blok yapl yakla³m, nesneye dayal yakla³m, fonksiyonel yakla³m gibi yöntemler çe³itli alanlarda yaygn olarak kullanlmaktadr. Seçti§iniz programlama dili hangi programlama yakla³mn kullanaca§nz da belirler. Sözgelimi C dili blok yapl, Java dili nesneye dayal, Haskell diliyse fonksiyonel dillerdir. C++ dili hem blok yapl hem de nesneye dayal özellikler gösteren karma bir dildir. 1.6.2 Programlarn Çal³trlmas Bilgisayarlarn çal³tracaklar programlarn belli bir biçimi olmas zorunludur. Bu biçim, bilgisayardan bilgisayara ve i³letim sisteminden i³letim sistemine göre farkllklar gösterir. Sözgelimi, bir ki³isel bilgisayar üzerinde Windows i³letim sisteminde çal³an bir program, Sun marka bir i³istasyonunda Solaris i³letim sisteminde çal³maz. Hatta, yine ayn ki³isel bilgisayar üzerinde Linux i³letim sisteminde de çal³maz. Programlarn bu çal³trlabilir biçimine makina kodu ad verilir. Makina kodu, insanlarn anlamas ve üzerinde çal³mas son derece zor bir biçim oldu§undan programclar programlar do§rudan bu kod ile yazmazlar. nsann anlamas daha kolay (insan diline daha yakn) yüksek düzeyli bir dil ile kaynak kodunu olu³turup yardmc yazlmlar aracl§yla makina koduna çevirir ve çal³trrlar. Kaynak kodunun makina koduna çevrilmesi ve çal³trlmas i³lemi üç farkl yakla³mla gerçekle³tirilebilir: Yorumlama Programn komutlar bir yorumlayc tarafndan teker teker okunur, makina koduna çevrilir ve çal³trlr. Yani yorumlayc, önce birinci komutu okur, makina koduna çevirir ve çal³trr. Sonra ikinci komutu alr ve ayn i³lemleri yapar. Programn her çal³masnda çevirme i³lemi yeniden yaplr. Herhangi bir komutun çevrilmesinde ya da çal³trlmasnda bir hatayla kar³la³t§nda bunu kullancya bildirir ve çal³may durdurur. Basic, Perl, Tcl gibi diller genellikle yorumlayclar aracl§yla kullanlrlar. Derleme Program bir derleyici tarafndan bir bütün halinde okunur ve makina koduna çev- rilerek bir çal³trlabilir dosya olu³turulur. Bu dosya daha sonra istendi§i zaman çal³trlr, yani çevirme ile çal³trma i³lemleri birbirinden ayrlr. Böylelikle çevirme i³lemi yalnzca bir kere yaplr. Herhangi bir komutta hata varsa çevirme i³lemi tamamlanmaz, yani çal³trlabilir kodun olu³mas için hiçbir yazm hatas olmamas gerekir; ancak program daha sonra çal³trlrken çal³ma-zaman hatalaryla kar³la³labilir. Fortran, Pascal, C gibi diller genelde derleyicilerle kullanlrlar. Karma Hem derleme hem de yorumlama tekni§i kullanlr. Bu tip çal³mada kaynak kodu sanal bir bilgisayarn makina koduna (bytecode) çevrilir ve daha sonra bu sanal bilgisayar gerçekleyen bir program yardmyla yorumlanarak çal³trlr. Örne§in Java dilinde yazlm³ bir kaynak kodu önce Java derleyicisinden geçirilerek Java sanal makinasnn (Java Virtual Machine - JVM) makina koduna dönü³türülür; sonra da bu sanal makinay gerçekleyen bir Java çal³ma ortam (Java Runtime Environment - JRE) yardmyla çal³trlr. Yorumlama yönteminde kodun okunmas ve çevrilmesi programn çal³mas srasnda yapld§ndan hz dü³üktür. Ayrca yorumlayc yalnzca kar³la³t§ ilk hatay rapor edebilir. Bu 25 Giri³ hata düzeltildi§inde sonraki çal³mada da program ancak bir sonraki hataya kadar ilerleyebilir. Oysa derleyici kaynak kodundaki bütün hatalar bulabilir. Buna kar³lk hata ayklama i³lemi yorumlayclarla daha kolaydr. Ayrca derleyicilerle gelen baz snrlamalarn kalkmas nedeniyle daha esnek bir çal³ma ortam sa§lanr. Son yllarda iki yöntemin üstün yanlarn birle³tiren karma diller (Java ve Python gibi) öne çkmaya ba³lam³lardr. 1.6.3 Kitaplklar Bir programcya gerekebilecek her ³eyi programlama dilinin içine almak o dili i³leyecek araçlarn hantalla³malarna neden olur. C dili bu nedenle oldukça küçük bir dil olarak tasarlanm³tr. Örne§in basit aritmetik i³lemlerin ötesindeki matematik i³lemleri dilin tanm içinde yer almaz; sözgelimi karekök alma i³lemi için bir C komutu yoktur. Bununla birlikte, pek çok programcnn bu tip i³lemlere gereksinim duyacaklar da açktr. Böyle bir durumda programc, isterse karekök alma i³lemini yapacak kodu kendisi yazabilir. Ancak programcnn bu tip i³lemler için kendi kodlarn yazmasnn önemli sakncalar vardr: 1. Her programcnn ayn i³leri yapan kodlar yazmas büyük zaman kaybna yol açar. 2. Programcnn yazaca§ kod hatal olabilir, yani yanl³ sonuç üretebilir. Ya da do§ru sonuç üretse bile, yeterince etkin olmayabilir, yani i³lemi yapmak için gere§inden fazla zaman ya da sistem kayna§ harcayabilir. Hem dilin tanmn küçük tutmak hem de bu sakncalar giderebilmek için, ço§u programcya gerekebilecek i³lemler (yordamlar) kitaplk ad verilen ar³ivlerde toplanm³tr. Bir saynn karekökünü almak isteyen bir programc matematik kitapl§ndaki sqrt yordamn kullanabi- lir. Kitapl§n kullanlmas yukarda sözü geçen sakncalar giderir, yani programcya zaman kazandrd§ gibi, do§ru ve etkin çal³t§ snanm³ oldu§undan dikkatini programn di§er ksmlarna yo§unla³trma frsat verir. 1.6.4 Standartlar C dilinin geli³tirilmesinde gözetilen ana hedeerden biri ta³nabilirlikti. Bunun için de§i³ik ortamlardaki araçlar arasnda bir standart olmas gerekti§i açktr. C dilinde yaplan standartla³ma çal³malar sonucunda olu³an ANSI C standard, hem C dilinin kurallarn belirler, hem de bir C geli³tirme ortamnda bulunmas zorunlu olan standart kitaplklar ve bu kitaplklarda yer alacak yordamlar tanmlar. Uluslararas Standartlar Organizasyonu'nun (ISO) C++ dili için hazrlad§ ISO-C++ standard da son yllarda yazlm³ bütün C/C++ geli³tirme ortamlar için en temel kaynaklardan birini olu³turmaktadr. Di§er önemli bir standart olan POSIX standard ise programlama dili ile i³letim sistemi arasndaki ba§lantlar belirler. Örne§in dosya silmek, dosya ad de§i³tirmek, sistemdeki ba³ka bir programla haberle³mek gibi i³lemler için gereken yordamlar bu standartta yer alrlar. Yine de skça gereksinim duyulan bütün i³lemler için bütün kitaplklarda bir standart henüz sa§lanamam³tr. Örne§in grak bir arayüze sahip uygulamalardaki grak i³lemlerini yapacak kitaplklar standartla³trlmam³ oldu§undan çe³itli rma ve kurumlar bu i³lemleri yapan farkl 26 Program Geli³tirme kitaplklar geli³tirmi³lerdir. Dolaysyla bu kitaplklar kullanlarak yazlan programlar tam anlamyla ta³nabilir olmamakta, yalnzca bu kitapl§n destekledi§i ortamlara ta³nabilmektedir. Son zamanlarda farkl i³letim sistemlerinde çal³abilen grak kitaplklar yaygnla³t§ için do§ru araçlar seçildi§inde bu sorunun da üstesinden gelinebilmektedir. 1.6.5 Derleme A³amalar Kaynak koddan üretilecek olan çal³trlabilir makina kodunda hem programcnn kendi yazd§ yordamlarn, hem de yararland§ kitaplk yordamlarnn makina koduna çevrilmi³ hallerinin bulunmas gerekir. Bu nedenle, kaynak kodunun makina koduna çevrilmesi iki a³amada gerçekle³ir (ekil 1.20): derleme kaynak kodu baglama ara kod çalistirilabilir kod kitapliklar ekil 1.20: Tek kaynak kodlu projelerin derleme a³amalar. Derleme lk a³amada kaynak kodu derlenerek bir ara koda dönü³türülür. Bu kod, kullancnn yazd§ yordamlarn makina kodu kar³lklarn içeren bir dosyadr. Ancak, programcnn kullanm³ oldu§u kitaplk yordamlarn içermedi§inden henüz çal³trlabilir durumda de§ildir. Ba§lama kinci a³amada ara kod ile programcnn kulland§ kitaplk yordamlar arasnda ba§lantlar kurulur ve çal³trlabilir dosya üretilir. Sözgelimi, programc karekök alma için matematik kitapl§ndaki bir yordam kullandysa, ba§layc ara kodda karekök yordamnn kullanld§ yerlerde gerekli düzenlemeleri yapar. Sorular 1. Bölüm 1.1'de verilen takas i³lemi için yazlan üç atama komutunun sralarn de§i³tirerek ne sonuçlar elde edildi§ini belirleyin. Problemin kaç do§ru çözümü vardr? 2. Bölüm 1.2.1'de yaplan algoritma hz kar³la³trmalarnda verilen en kötü ve ortalama n - 1 ³eklinde verildi§i genel durum de§erlerini kendiniz çkarn. Alt snrn 1, üst snrn 2 durumda en kötü ve ortalama de§erleri n cinsinden hesaplayn. 3. ki saynn en büyük ortak bölenini hesaplamak için verilen iki algoritmay, basitlik ve etkinlik açlarndan kar³la³trn. kiden fazla saynn en büyük ortak bölenlerini hesaplamak için bir algoritma geli³tirin. 27 Giri³ a say2 de§erleri atanarak yineleme yapsna girildi§ini say1 > say2 ya da say1 < say2 olmas durumlarnda al- 4. Euclides algoritmasnda iki saydan büyük olannn hangisi oldu§una baklmakszn de§i³kenine say1, b de§i³kenine varsayalm. Ba³langçta goritma do§ru sonuç üretir mi? 5. Çarpanlara ayrarak en küçük ortak kat hesaplamak için gereken en küçük ortak katn çarpanlarn bulma yordamnn ak³ çizene§ini çizin ve örnek de§erler üzerinde nasl i³leyece§ini gösteren tabloyu olu³turun. Program Geli³tirme 28 Bölüm 2 C Diline Giri³ Bu bölümde de§i³kenler, atama, deyimler, giri³-çk³ gibi konularn C dilinde nasl gerçeklendikleri üzerinde durulacaktr. Örnek 1. Daire Çevresi ve Alan Yarçapn kullancdan ald§ bir dairenin çevresini ve alann hesaplayarak ekrana yazan bir program yazlmas isteniyor. Programn örnek bir çal³masnn ekran çkts ekil 2.1'de verilmi³tir. Yarçap yaznz: 4.01 Çevresi: 25.1828 Alan: 50.4915 ekil 2.1: Örnek 1 ekran çkts. Örnek üzerinde bir C programnn baz temel özelliklerini görelim: Açklamalar Anla³labilirli§i artrmak için kodun içinde gerekli yerlere açklamalar yazmakta büyük yarar vardr. Özellikle kolayca anla³lmayacak programlama tekniklerinin kullanld§ kod parçalarnn açklanmas gerekir. Açklamalar derleyici tarafndan gözard edilir, yani programn i³leyi³lerine hiçbir etkileri yoktur. Kodun içine açklama iki ³ekilde yazlabilir: • Birinci yöntemde, açklamann ba³na bölü-yldz, sonuna yldz-bölü simgeleri konur. Bu ³ekildeki açklamalar birden fazla satr sürebilir. Örnekteki birinci açklama birinci satrdaki lk alann hesaplar. C programm sözcükleriyle ba³lar ve üçüncü satrdaki sözcükleriyle biter. Bu tip açklamalar içiçe yazlamaz, yani bir açklamann içinde ikinci bir açklama olamaz. çiçe açklamalar ³u ³ekilde bir yap olu³turur: ...a... /* ...b... /* ...c... */ ...d... */ ...e... 29 30 Örnek 1 Bir dairenin çevresini ve alann hesaplayan program. /* lk C programm. * * * * Yarçap verilen bir dairenin çevresini ve alann hesaplar. */ #include <iostream> #include <stdlib.h> // cout,cin,endl için // EXIT_SUCCESS için using namespace std; #define PI 3.14 int main(void) { float radius; float circum, area; } cout << "Yarçap yaznz: "; cin >> radius; circum = 2 * PI * radius; area = PI * radius * radius; cout << "Çevresi: " << circum << endl; cout << "Alan: " << area << endl; return EXIT_SUCCESS; 31 C Diline Giri³ Bu yapda birinci /* /* ile açklama ba³lar. Açklamann içinde görülen ikinci zard edilir ve gelen ilk */ açklamay sona erdirir; yani açklamay b ve c gö- bölgeleri olu³turur. Bundan sonra gelen bölüm (d bölgesi) normal C kodu gibi de§erlendirilece§inden hataya yol açar. • 1 Ksa kinci yöntemde, açklama çift bölü ile ba³lar ve satrn sonuna kadar sürer. açklamalar için bu yöntem daha kullan³ldr. Örnekteki ikinci açklama be³inci satrdaki cout,cin,endl satrdaki EXIT_SUCCESS Komutlar için sözcüklerinden olu³ur. Üçüncü açklama da altnc için sözcüklerini kapsar. C dilinde komutlar noktal virgül ile sona erer. Pe³pe³e birden fazla bo³luk derleyici tarafndan tek bo³luk olarak de§erlendirilir; dolaysyla bir komutun bir satr içinde ba³layp sona ermesi zorunlulu§u yoktur. Yani cout < < Alan: < < area < < endl; komutu cout < < Alan: < < area < < endl; biçiminde ya da cout < < Alan: < < area < < endl; biçiminde yazlabilirdi. C dilinde komutlarn noktal virgül ile sona ermesi ve fazla bo³luklar ile satr geçi³lerinin Gelenek öneminin olmamas nedeniyle komutlar satrlara istendi§i ³ekilde yerle³tirilebilir.Ancak bu konuda bir düzene uyulmazsa kodun okunmas ve anla³lmas son derece zorla³r. Okunabilirli§i artrmak amacyla alt-bloklar bir miktar içeriden ba³latlrlar (girintileme ). Böylece ayn düzeydeki (ayn blo§a ait) komutlar ayn hizadan ba³larlar. Örnekte fonksiyon blo§undaki bütün komutlar satr ba³ndan dört harf içeriden ba³lamaktadr. Özellikle içiçe yaplarn kullanld§ durumlarda (seçimin içindeki yinelemenin içindeki seçimin içindeki seçim gibi) bloklar hiyerar³ik bir ³ekilde girintilemek büyük önem ta³r. Atama Atama i³lemi e³it i³aretiyle yaplr. Örnekteki circum = 2 * PI * radius; komutu bir atama komutudur, nine atar. 1 2 2 2 * PI * radius deyiminin sonucunu circum de§i³ke- Bu açklama yöntemi C++ ile getirilmi³ bir yeniliktir, C dilinde geçerli de§ildir. Tek atama komutuyla birden çok de§i³kene ayn de§er atanabilir. Örne§in a = b = c = 24; komutu a, b ve c de§i³kenlerinin üçüne de 24 de§erini atar. Bu i³lem sa§dan sola do§ru gerçekle³tirilen pe³pe³e atamalar ³eklinde dü³ünülebilir: c = 24; b = c; a = b; 32 simler Fonksiyonlar Blok yapl programlamadaki yordamlar C dilinde fonksiyonlar ile gerçekle³ti- rilir. Ana i³i yapan fonksiyonun ad main olarak verilmelidir. Programn yürütülmesine ana i³ten ba³lanaca§ için her programn bir ve yalnz bir main fonksiyonu bulunmas zorunludur. C dilinde bir fonksiyonun içerdi§i komutlar bir blok olarak de§erlendirilir. Bloklar açsüslü-ayraç ile ba³lar ve kapa-süslü-ayraç ile sona erer. Bu notlardaki ço§u örnekte main fonksiyonu ³u ³ablona uyacaktr: int main(void) { ... return EXIT_SUCCESS; } Ba³lk dosyalar Kitaplklarda tanmlanm³ olan fonksiyonlar, birimler ya da büyüklükler kullanld§ zaman derleyiciye bunlarla ilgili bilgileri nerede bulabilece§ini söylemek gerekir. Bu bilgilerin yer ald§ ba³lk dosyalar program ba³nda belirtilir. Örne§in cout birimi iostream #include komutuyla ba³lk dosyasnda bulundu§undan örnek prog- ramda #include <iostream> komutu yer almaktadr. stdlib.h 3 Benzer ³ekilde, EXIT_SUCCESS sözcü§ünün kullanlabilmesi için dosyas içerilmelidir. Bir kitaplktan yararlanaca§nz zaman gerekli bilgilerin hangi ba³lk dosyalarnda yer ald§n bilmeniz gerekir. Temel fonksiyonlar standartlarda belirlenmi³ oldu§undan (bkz. Bölüm 1.6.4) bunlarn ba³lk dosyalarn ço§u C/C++ kitabnda bulabilirsiniz. Standartlara girmemi³ fonksiyonlar içinse kulland§nz derleyici ve kitaplklarn yardmc belgelerine ba³vurmalsnz. 2.1 4 simler Programlardaki de§i³ken, fonksiyon gibi varlklara verilen isimlerin baz kurallara uymalar gerekir: • simler, ngilizce büyük ve küçük harer, rakamlar ve altçizgi i³aretinden olu³abilir. Bu kurala göre weight-1 • 3 pi, weight, weight1 ve weight_1 geçerli isimlerdir, ancak ve geçerli isimler de§ildir. smin ilk simgesi bir rakam olamaz. Bu kurala göre 2weight geçerli bir isim de§ildir. .h uzants verilir. C++ standardnda ise baz ba³lk dosyalarnn uzaniostream ba³lk dosyas C++ ile tanmlanm³ yeni ba³lk dosyalarna bir ör- C standardnda ba³lk dosyalarna ts bulunmayabilir. Örnekteki nektir. 4 π , a§rlk Unix i³letim sistemlerinde yardmc belgeler ile ilgili bilgi için bkz. Ek B.1. 33 C Diline Giri³ • smin en az ilk 31 simgesi anlamldr. Ba³ka bir deyi³le, ilk 31 simgesi ayn olmayan iki ismin farkl olaca§ kesindir ama aynlarsa derleyici bu iki ismin farkl olmad- population_increase_between_years_2000_and_2001 ile population_increase_between_years_2001_and_2002 isimli iki de§i³ken tanmlanrsa §na karar verebilir. Örne§in ilk 31'er simgeleri ayn oldu§undan baz derleyiciler bu ikisinin ayn de§i³ken olduklarna karar verebilir. • simlerde büyük-küçük harf ayrm vardr. Yani weight1, Weight1, WEIGHT1 ve wEiGHT1 isimlerinin hepsi geçerli olmakla birlikte hepsi birbirinden farkldr. • C dilinin sözcükleri isim olarak seçilemez. Yani örne§in int, main, void, return geçerli isimler de§ildir. Kitaplklardan alnan fonksiyon ya da di§er varlklarn isimleri sakl isimler arasnda de§ildir. Sözgelimi, istenirse bu durumda çkt için kullanlan cout cout isimli bir de§i³ken kullanlabilir ancak kitaplk biriminden artk yararlanlamaz. Büyük projelerde isim çak³malar sorun yaratmaya ba³lar. Bu durumu düzeltmek amacyla isim uzaylarndan yararlanlr. Bu kitaptaki örnekler küçük boyutta olduklar için bu sorunlar gözard edilecek ve standart isim uzaynn kullanld§n belirtmek üzere programn ba³nda using namespace std; bildirimi yaplacaktr. Bu bildirim cin, cout endl de§erlerine kolay std:: eklemek gerekir: ve kullanlmazsa bu de§erlere eri³im için ba³larna eri³imi sa§lar; std::cin > > radius; std::cout < < Area: < < ... < < std::endl; simlerin seçiminde ço§u programcnn uydu§u baz gelenekler vardr: • Gelenek De§i³ken ve fonksiyon isimleri küçük harerle ba³lar. Ba³ka bir deyi³le, büyük harer ya da altçizgi i³aretiyle ba³lamaz. • De§i³ken ve fonksiyonlara gösterdikleri bilgiye ya da yaptklar i³e uygun dü³en, anlaml bir isim verilir. Sözgelimi bir insann a§rl§ bilgisini tutacak bir de§i³kene anlamsz ya da • height x4szb gibi gibi yanltc isimler verilmez. Anlaml isimler verilmek istendi§inde bazen birden fazla sözcü§e gereksinim duyulabilir. Bu durumda ya ismi olu³turan iki sözcük bir altçizgi i³aretiyle birle³tirilir (örne§in birth_month) 2.2 ya da ikinci sözcük büyük hare ba³lar (örne§in birthMonth). De§erler Tamsaylarn do§al gösterilimleri onlu düzendedir, ancak istenirse sekizli ya da onaltl düzende de gösterilebilirler. Örnekte 2 says onlu gösterilimde yazlm³ bir tamsaydr. 0 rakamyla ba³layan saylarn sekizli, 0x ile ba³layanlarn onaltl düzende olduklar varsaylr. Buna göre, 59 says sekizli düzende 073, onaltl düzende 0x3b olarak yazlr. 34 De§i³kenler Kesirli saylarn do§al gösterilimi noktal gösterilimdir, ancak istenirse bilimsel gösterilim us ) de kullanlabilir. Örnekte 3.14 says noktal gösterilimde yazlm³ bir ke- (mantis * 10 sirli saydr. Saynn yazl³nda E simgesi geçiyorsa bu simgenin öncesi mantis, sonras üs olarak de§erlendirilir. Buna göre, 3.14 says bilimsel gösterilimde 314E-2 (314 * 10 −2 ) olarak yazlabilir. Simgeler tek, katarlar çift trnak i³aretleri arasnda yazlrlar. Örnekte Alan: de§eri bir katardr; yalnzca A harnden söz edilmek isteniyorsa 'A' ³eklinde yazlr. Katar içinde yazlan her bo³lu§un önemi vardr, yani sözgelimi pe³pe³e be³ bo³luk brakld§nda bu bir bo³luk olarak de§il, be³ bo³luk olarak de§erlendirilir. Örne§in Alan : katarnda Alan sözcü§ü ile iki nokta üstüste i³areti arasnda be³ bo³luk bulunacaktr. 2.3 De§i³kenler C dilinde, bir de§i³kene bir de§er vermeden ya da de§erini bir hesapta kullanmadan önce de§i³kenin tanmlanmas gerekir. Tanmlama i³lemi, bellekte gerekti§i kadar yerin bu de§i³ken için ayrlmasn sa§lar; böylece sistem, bellekte ayrlan bu yeri bu de§i³ken için kullanr ve ba³ka i³lerde kullanmaz. Tanmlama, de§i³kenin tipinin ve adnn belirtilmesinden olu³ur. Örnekte float radius; tanm derleyiciye radius adnda bir de§i³ken oldu§unu ve bir kesirli say tutaca§n belirtmeye yarar. Ayn tipten olan de§i³kenler ayn tanmn içinde yer alabilirler. Örnekteki float circum, area; tanm, her ikisi de birer kesirli say olan, circum ve area adnda iki de§i³ken kullanaca§mz anlamna gelir. Örnekteki tanmlar istenirse float radius; float circum; float area; ³eklinde ayrlarak ya da float radius, circum, area; ³eklinde birle³tirilerek de yazlabilirdi. Tanm srasnda istenirse de§i³kene ba³langç de§eri de verilebilir: float radius, circum = 0.0, area = 0.0; 35 C Diline Giri³ Bu durumda tanm srasnda radius Gelenek circum ve area de§i³kenlerinin her ikisine de 0.0 de§eri verilir, de§i³kenine bir ba³langç de§eri verilmez. De§i³kenlere ba³langç de§eri atanmas yararl bir al³kanlktr. Ba³langç de§eri atanmazsa de§i³ken rasgele bir de§er alabilir ve programcnn dikkatsiz davranmas durumunda bu rasgele de§er yanl³lkla hesaplarda kullanlabilir ve istenmeyen sonuçlara yol açabilir. Genelde bir blok içindeki de§i³ken tanmlar ile komutlar birbirlerinden ayrlr, yani kullan- Gelenek 5 Tanmlarn sona erdi§i lacak bütün de§i³kenlerin tanmlar bittikten sonra komutlar ba³lar. ve komutlarn ba³lad§ yerin kolayca görülmesini sa§lamak amacyla tanmlar ile komutlar arasnda bir satr bo³luk braklr. 2.4 Veri Tipleri C dilinde tanmlanan taban veri tipleri ³unlardr (bkz. Bölüm 1.1.1): int sakl sözcü§üyle belirtilir. Bu veri tipi short ve long belirteçleriyle geli³tirilerek ksa tamsay (short int) ve uzun tamsay (long int) tipleri olu³turulabilir. tamsay Aksi belirtilmedikçe tamsay tiplerinin i³aretli olduklar varsaylr, yani hem pozitif hem de negatif de§erler alabilirler. De§i³ken yalnzca pozitif saylardan (0 da olabi- unsigned sözcü§ü kullanlabiint, short int, long int, unsigned int, unsigned long int. lir) de§er alacaksa i³aretsiz olarak tanmlamak için lir. Ksacas, 6 adet tamsay tipi vardr: unsigned short int kesirli say float ve sakl sözcü§üyle belirtilir. Say daha yüksek duyarllkla gösterilmek iste- nirse çifte duyarllkl (double) ya da uzun çifte duyarllkl (long double) tipleri kullanlabilir. simge char sakl sözcü§üyle belirtilir. Simgeler kullanlan kodlamadaki sralarna göre de§erler alrlar (bkz. Ek A). Örne§in 'A' har ASCII kodlamasnda 65. srada oldu§undan 'A' simgesinin say de§eri 65'tir. mantksal bool sakl sözcü§üyle belirtilir. Bu tipten de§i³kenler alabilirler. 6 true ya da false de§erini Bir de§i³kenin tanmlanaca§ veri tipi, o de§i³kenin alabilece§i de§er aral§n belirledi§inden son derece önemlidir. Bu nedenle bir de§i³kenin veri tipine karar verirken o veri tipinin izin verdi§i de§er aral§na dikkat etmek gerekir. Sözgelimi short int veri tipi yalnzca -32768 ile +32767 arasndaki saylarn gösterilebilmesine olanak veriyorsa ve sizin tanmlayaca§nz de§i³kenin 45000 de§erini almas sözkonusu olabilecekse de§i³keninizi bu tipten tanmlamamalsnz. Bir veri tipinin boyu sizeof i³lemi yardmyla belirlenebilir. Her de§i³ken bellekte bu boy kadar yer kaplar (sekizli cinsinden). Ksa tamsay veri tipinin boyunun 2 sekizli yani 16 bit oldu§unu varsayalm. Bu boy hem i³aretli hem de i³aretsiz ksa tamsaylar için geçerlidir. Bu durumda i³aretsiz ksa tamsay cinsinden tanmlanan bir de§i³kenin alabilece§i en küçük de§er 0, en büyük de§er ise 216 − 1 yani 65535 olacaktr. 5 6 C++ dilinde komutlar ba³ladktan sonra da de§i³ken tanmlanabilir. C dilinde buna izin verilmez. C dilinde mantksal verileri temsil edecek özel bir veri tipi yoktur, bu tip C++ dilinde getirilmi³tir; yani bool, true ve false sözcükleri geçerli C sözcükleri de§ildir. 36 De§i³mezler 2.5 De§i³mezler Programda kullanlan baz bilgiler de programn farkl çal³malar arasnda de§er de§i³tirmezler. Örnekteki PI says ve dairenin çevresinin hesaplanmasnda kullanlan 2 says bu tipten büyüklüklerdir. De§i³mezlerin bazlarna isim vermek birtakm kolaylklar sa§lar: • Anla³lrl§ artrr. Programn içinde 3.14 yazmak yerine PI yazmak program okuyan birinin bu saynn neye kar³ dü³tü§ünü daha kolay anlamasn sa§lar. • De§i³tirmek kolay olur. Diyelim programn geli³tirilmesinin ileri a³amalarnda 3.14 de§erinin yetersiz kald§na ve 3.14159 de§erinin daha uygun oldu§una karar verirsek kod içinde tek bir noktada de§i³tirmek yeterli olur. Öbür türlü, kodun içindeki bütün 3.14 saylarnn yerine 3.14159 yazmamz gerekir. Daha da kötüsü, kodun içindeki ba³ka büyüklükleri gösteren 3.14 de§erlerinin de geçmesi olasl§dr. Bu durumda bütün 3.14 de§erlerini tek tek inceleyerek de§i³tirilip de§i³tirilmeyece§ine karar vermek gerekir. De§i³mezler iki ³ekilde tanmlanabilirler: 1. #define bildirimiyle tanmlama. Bu yöntem bir de§ere bir isim vermekte kullanlr. PI ismini vermektir. Bu bildirimin sonucu, programcnn PI geçen her yere kendisinin 3.14 de§erini yazm³ olmasyla ayndr. Bu ³ekilde Örnekte yaplan 3.14 saysna kod içinde tantlan de§i³mezlere gelenek olarak tamam büyük harerden olu³an isimler verilir. Bu bildirim yönteminde de§i³mezlerin tipleri ayrca belirtilmez. Tamsay de§i³mezler int tipine s§myorlarsa eklenirse long, u ya da U long int eklenirse varsaylrlar. De§erlerinin sonuna unsigned l ya da L hareri belirteci seçilmi³ olur. #define MAXSHORT 0x7FFF #define MAXUSHORT 65535U f ya da F eklenmemi³se double long double tipinden olurlar. Kesirli de§i³mezlerin de§erlerinin sonuna duklar varsaylr. l ya da L eklenirse tipinden ol- #define EULER 2.81782F #define PERCENT 1E-2 2. De§i³ken tanmna benzer ³ekilde ancak veri tipinin önüne const niteleyicisi koyarak tanmlama. Böylece de§eri de§i³tirilemeyen bir de§i³ken tanmlanm³ olur. Bu ³ekilde tanmlanan de§i³mezlere büyük harerden olu³an isimler verilmez. Örnekteki PI de§i³- mezinin bu yöntemle tanm ³öyle olurdu: const float pi = 3.14; Her iki tanmda da de§i³mez olarak bildirilmi³ bir büyüklü§e de§er atanmaya çal³rsa derleyici 7 hata verir. 7 C dili const ile tanmlanm³ de§i³mezlerin de§erlerinin de§i³tirilebilmesine izin verir. Bu tipten bir de§i³- kene atama yaplmak istendi§inde derleyici hata de§il, yalnzca bir uyar üretecektir. 37 C Diline Giri³ 2.6 Aritmetik Deyimler Aritmetik deyimlerde kullanlabilecek i³lemler ³unlardr: + • Toplama: • Çkartma: • Çarpma: • Bölme: / i³leciyle gerçeklenir. • Kalan: % i³leciyle gerçeklenir. Yalnzca iki tamsay arasnda yaplabilir, kesirli saylarda * i³leciyle gerçeklenir. - i³leciyle gerçeklenir. i³leciyle gerçeklenir. tanml de§ildir. Bunlarn yansra matematik kitapl§nda yer alan fonksiyonlar da aritmetik deyimlerde yer alabilirler (bkz. Bölüm 2.9). Komutlarn okunurlu§unu artrmak amacyla C programclarnn uyduklar geleneklerden biri Gelenek de, e³it i³aretinin öncesinde ve sonrasnda birer bo³luk brakmaktr. Benzer ³ekilde, deyimlerde yer alan i³leçlerin (örnekte + simgesi) önce ve sonralarnda da birer bo³luk braklr. C'de deyimlerin hesaplanmasnda izlenen öncelik sras, matematikten al³k olunan sradr. Yüksek öncelikliden alçak öncelikliye do§ru öncelik gruplar ³öyledir: 1. Ayraç içindeki deyimler 2. Say i³areti belirten + ve - i³lemleri, artrma, azaltma 3. Çarpma, bölme, kalan 4. Toplama, çkarma E³it öncelik gruplar kendi içlerinde soldan sa§a do§ru de§erlendirilirler. Örnek. a+b+c+d+e 5 aritmetik deyimi C'de (a + b + c + d + e) / 5 ³eklinde yazlmaldr. Ayraçlar kullanlmazsa ortaya çkan a + b + c + d + e / 5 38 Tip Dönü³ümleri C deyimi a+b+c+d+ e 5 aritmetik deyimine kar³ dü³er. Örnek. p * r % q + w / x - y deyimi ³u srayla hesaplanr: t1: t2: t3: t4: t5: 2.7 p * r t1 % q w / x t2 + t3 t4 - y Tip Dönü³ümleri ³leme giren saylarn her ikisi de tamsay ise sonuç da tamsay olur. Saylardan herhangi birinin kesirli say olmas durumunda sonuç da kesirli say olacaktr. Bu durum bölme i³leminde dikkat edilmesi gere§ini do§urur. Bölme i³lemine giren her iki say da tamsay ise sonuç da tamsay olacaktr, yani sonucun varsa kesir ksm atlacaktr. Örne§in 14 / 4 deyiminin sonucu 3.5 de§il 3 olacaktr. ³leme giren her iki say da tamsay ise ve sonucun kesir ksmnn yitirilmemesi isteniyorsa saylardan en az birinin kesirli say olmasn sa§lamak gerekir. Yukardaki örnek için çözüm ³u yazl³larla sa§lanabilir: 14.0 / 4 14 / 4.0 14.0 / 4.0 Bir bölme i³lemine giren iki de§i³kenin ikisinin de tamsay tipinden olmas durumunda sonuç yine tamsay olacaktr. Örne§in int num1 = 14, num2 = 4; float quotient; quotient = num1 / num2; i³lemleri sonucui mak için num1 ve quotient de§i³keni 3.0 de§erini alr. ³lemin do§ru olarak yaplmasn sa§lanum2 de§i³kenlerinden en az birinin kesirli say tipine çevrilmesi gerekir. Bu i³leme tip zorlama ad verilir ve bir deyimin ba³na ayraç içinde deyimin sonucunun almas istenen tipin adnn yazlmasyla yaplr. Yukardaki örne§in do§ru çal³mas için ³u komutlardan herhangi biri kullanlabilir: 39 C Diline Giri³ quotient = (float) num1 / num2; quotient = num1 / (float) num2; quotient = (float) num1 / (float) num2; Birinci komutta yalnzca num1 de§i³keni, ikinci komutta yalnzca num2 de§i³keni, üçüncü ko- mutta ise her ikisi birden kesirli sayya çevrilmektedir. Buna kar³lk quotient = (float) (num1 / num2); komutu ise önce bölmeyi sonra tip zorlamasn yapaca§ndan quotient de§i³kenine yine 3.0 de§erini atar. Genel olarak, bir i³leme giren saylar farkl tiptense, bunlarn ortak bir tipe çevrilmeleri gerekir. Dar tipten geni³ tipe geçi³ i³lemleri derleyici tarafndan otomatik olarak yaplr. Örne§in, bir toplama i³leminin i³lenenlerinden biri tamsay di§eri kesirli say ise tamsay olan kesirli sayya çevrilir ve toplama yaplr. A³a§daki örnekte toplama i³leminin ikinci i³leneni kesirli say oldu§undan toplamadan önce num1 de§i³keni kesirli sayya çevrilecektir: int num1 = 14; float sum; sum = num1 + 7.32; Geni³ tipten dar tipe geçi³ler ise bilgi yitirilmesine neden olabilirler. Örne§in kesirli say tipinden bir de§i³kenin tamsay tipinden bir de§i³kene atanmas srasnda saynn kesir ksm yitirilebilir: int num1; float num2 = 65.717; num1 = num2; Derleyiciler bu gibi durumlarda genelde hata de§il yalnzca uyar üretirler. 2.8 Artrma / Azaltma Bir atamann sa§ tarafndaki deyim, atamann sol tarafndaki de§i³keni içeriyorsa, yani de§i³ken = de§i³ken ◦ deyim; (◦ herhangi bir i³lem simgesi olabilir) ³eklindeyse bu komut de§i³ken ◦= deyim; 40 Matematik Kitapl§ ³eklinde ksaltlabilir. Örne§in: a += 5; a /= 2; a *= c + d; // a = a + 5; // a = a / 2; // a = a * (c + d); Buna göre, bir de§i³kenin de§erini artrmak ya da azaltmak için a³a§daki komutlar kullanlabilir: a = a + 1; a += 1; a = a - 1; a -= 1; Ancak artrma ve azaltma i³lemleri programlarda skça gereksinim duyulan i³lemlerden olduk- ++ i³leci, önüne ya da arkasna yazld§ -- i³leciyse önüne ya da arkasna yazld§ i³lecin de§erini 1 azaltr. larndan C'de bunlar için özel i³leçler tanmlanm³tr. de§i³kenin de§erini 1 artrr; Her iki i³leç de yalnzca tamsay veri tipleri ile çal³rlar ve basit kullanmda i³lecin de§i³kenin önüne mi arkasna m yazld§nn bir önemi yoktur: 8 a++; a--; ++a; --a; 2.9 Matematik Kitapl§ ANSI standard, bir C derleme ortamnn matematik kitapl§nda bulunmas zorunlu olan fonksiyonlar belirler. Bu fonksiyonlarn kullanlabilmesi için programlarn ba³nda math.h ba³lk dosyasnn alnmas gerekir. Matematik kitapl§nn en sk kullanlan fonksiyonlar Tablo 2.1'de verilmi³tir. Bütün bu fonksiyonlardaki x ve y giri³ parametreleri double tipindendir ve çk³ parametresi de double tipinden olacaktr. 8 Artrma ve azaltma i³lemleri ba³ka i³lemlerle birlikte kullanlabilir. Sözgelimi bir artrma i³lemiyle bir atama i³lemi ayn komut içerisinde yaplabilir. Böyle durumlarda artrma/azaltma i³lecinin de§i³ken adnn önüne ya da arkasna yazlmas önem kazanr. Önüne yazld§nda önce artrma, sonra atama yaplacaktr. Arkasna yazld§ndaysa önce atama, sonra artrma yaplr. Yani y = ++x; komutu x++; y = x; koduna kar³ dü³erken y = x++; komutu 41 C Diline Giri³ Ad ³levi sin(x) cos(x) tan(x) asin(x) acos(x) atan(x) sinh(x) cosh(x) tanh(x) exp(x) log(x) log10(x) pow(x,y) sqrt(x) floor(x) ceil(x) fabs(x) trigonometrik fonksiyonlar ters trigonometrik fonksiyonlar hiperbolik trigonometrik fonksiyonlar ex e ve 10 xy √ x tabannda logaritma fonksiyonlar alt ve üst snr fonksiyonlar: bxc dxe |x| Tablo 2.1: Matematik kitapl§ fonksiyonlar. Trigonometrik fonksiyonlarda giri³ parametresi derece de§il radyan cinsinden verilmelidir; örne§in sin(30) deyimi 0.5 de§il -0.988032 de§erini üretir. 30 derecenin sinüsünü sin(30*3.141529/180) ya da sin(3.141529/6) deyimini yazmak gerekir. almak için Alt ve üst snr fonksiyonlarnn çal³masnda giri³ parametresinin pozitif ya da negatif olmasna dikkat edilmelidir. Alt snr fonksiyonu her zaman o saydan daha küçük olan ilk tamsayy, üst snr fonksiyonu ise o saydan daha büyük olan ilk tamsayy verir. • floor(3.1) → 3, floor(-3.1) → -4 • ceil(3.1) → 4, ceil(-3.1) → -3 Tamsaylar için de tamsay giri³ parametresi alan ve tamsay çk³ parametresi üreten abs isimli bir mutlak de§er fonksiyonu vardr. 2.10 Giri³ / Çk³ C dilinde kullancyla ileti³imi sa§layan i³lemler giri³/çk³ birimleri üzerinden yaplr (bkz. Bölüm 1.5). Girdiler 9 gönderilir. cin biriminden alnrken, çktlar cout, hatalar da cerr biriminebirimine Örnekteki cin > > radius; y = x; x++; koduna kar³ dü³er. 9 C dilinde cin, cout ve cerr birimleri yoktur, bunlarn yerine standart girdi/çkt kitapl§ndaki fonksiyon- larn kullanlmas gerekir (bkz. Ek 8). 42 Giri³ / Çk³ komutu sonucunda radius de§i³keni kullancnn tu³takmndan yazd§ saynn de§erini alr. Birden fazla de§i³ken birlikte okunmak isteniyorsa bunlar birbiri ardna > > i³aretleriyle belirtilebilir. Sözgelimi, iki tane say de§eri okunacak ve kullancnn yazd§ birinci saynn de§eri num1, ikinci saynn de§eriyse num2 de§i³kenine aktarlacaksa: cout < < Saylar yaznz: ; cin > > num1 > > num2; gibi bir program parças kullanlabilir. Bu örnekte kullancnn saylar yazarken aralarnda bir bo³luk brakmas gerekir. Çk³ birimlerine katarlar ya da deyimler gönderilebilir. Katarlar olduklar gibi yazlrken deyimlerin de§erleri görüntülenir. Örnekteki cout < < Alan: < < area < < endl; komutu ekrana önce Alan: katarn, daha sonra area de§i³keninin de§erini yazar ve yeni circum ve area de§i³kenleri tanmlanmadan ve atama komutlar satra geçer. Programda kullanlmadan çkt i³lemleri cout < < Çevresi: < < 2 * PI * radius < < endl; cout < < Alan: < < PI * radius * radius < < endl; komutlaryla da yaplabilirdi. Uygulama: Geli³tirme Ortam Bu uygulamada basit giri³/çk³ i³lemlerine ve matematik kitapl§nn kullanmna örnek verilmesi istenmektedir. Grak bir editör (kate) tantlacak ve C derleyicisinin nasl kullanlaca§ 10 ö§retilecektir. Basit hatalarda derleyicinin hangi mesajlar üretti§i gözlenecektir. Örnek 2. Formül Hesab y = e−πx formülünde x de§erini kullancdan alarak y de§erini hesaplayan ve ekrana yazdran bir program yazlmas isteniyor. • Örnekte verilen program yazn, derleyin ve çal³trn. y'nin x için 0.002 de§erini verdi§inizde ald§ de§eri gözleyin. • PI de§i³mezinin tanmn 3.14 yerine 3.14159 olarak verin ve ayn x de§erinde y'nin ald§ de§eri gözleyin. • 10 De§i³ken tanmlarnn yapld§ Unix i³letim sistemlerinde derleme a³amalar ile ilgili bilgi için bkz. Ek B.2. 43 C Diline Giri³ Örnek 2 y = e−πx formülünü hesaplayan program. #include <iostream> #include <stdlib.h> #include <math.h> // cout,cin.endl // EXIT_SUCCESS // exp using namespace std; #define PI 3.14 int main(void) { float x, y; cout << "x: "; cin >> x; y = exp(-PI * x); cout << "y: " << y << endl; return EXIT_SUCCESS; } float x, y; satrndaki 'x' harni 'X' ile de§i³tirin ve derleme sonucunda olu³an hatay gözleyin. • Örnekteki cin > > x; satrnn ardna PI = 3.14159; komutunu ekleyin ve derleme sonucunda olu³an hatay gözleyin. • Bir önceki admda yapt§nz de§i³ikli§i silmeden, örnekte #define PI de§i³mezinin tanmland§ satrn silin ve float x, y; satrnn ardna const float PI = 3.14; de§i³mez tanmn ekleyin. Derleme sonucunda olu³an hatay gözleyin. • Ba³taki #include <math.h> satrn silin ve derleme sonucunda olu³an hatay gözleyin. 44 Giri³ / Çk³ Sorular 1. Çal³t§nz geli³tirme ortamnda int tabanl veri tiplerinin de§er aralklarn belirleyin ve bu aralklar d³nda bir de§er atand§nda nasl bir sonuç elde edildi§ini gözleyin. 2. A³a§daki deyimlerin sonuçlarn bulun: 8 + 17 % 3 * 5 45 / (4 + 7) - 5.0 / 2 3. A³a§daki aritmetik deyimleri gerçekleyen C deyimlerini yazn: k← − cd efh−g x(y + z) 1 2ab 4. A³a§daki C deyimlerinin gerçekledi§i aritmetik deyimleri yazn: a + 3 * b - (c + d) / 2 * y; Bölüm 3 Ak³ Denetimi Bu bölümde blok yapl programlamada gereken seçim ve yineleme yaplarnn C dilinde nasl gerçeklendikleri üzerinde durulacaktr. Örnek 3. kinci Derece Denklem Kökleri 2 kinci dereceden (ax + bx + c = 0 ³eklinde) bir denklemin köklerinin yerlerini belirleyen bir program yazlmas isteniyor. Diskriminantn x1,2 = b2 − 4ac −b ± ³eklinde tanmland§n ve köklerin √ b2 − 4ac 2a formülüne göre hesaplanaca§n gözönünde bulundurarak, program denklemin katsaylarn kullancdan aldktan sonra a³a§daki i³lemleri gerçekle³tirecektir: • Denklemin gerçel kökü yoksa (diskriminant negatifse) bu durum kullancya bildirilir. • Denklemin kökleri çak³ksa (diskriminant sfrsa) bu durumu kök de§eriyle birlikte kullancya bildirilir. • Denklemin iki farkl gerçel kökü varsa (diskriminant pozitifse) bunlar hesaplanarak ekrana çkartlr. Programn örnek bir çal³masnn ekran çkts ekil 3.1'de verilmi³tir a, b ve c katsaylarn yaznz: -2 1 9.2 -1.90928 ve 2.40928 noktalarnda iki gerçel kökü var. ekil 3.1: Örnek 3 ekran çkts. 45 46 Örnek 3 kinci dereceden bir denklemin köklerini bulan program. #include <iostream> #include <stdlib.h> #include <math.h> // cout,cin,endl // EXIT_SUCCESS // sqrt using namespace std; int main(void) { float a, b, c; float disc; float x1, x2; } cout << "a, b ve c katsaylarn yaznz: "; cin >> a >> b >> c; disc = b * b - 4 * a * c; if (disc < 0) cout << "Gerçel kök yok." << endl; else { if (disc == 0) { x1 = -b / (2 * a); cout << x1 << " noktasnda çak³an iki kök var. " << endl; } else { x1 = (-b + sqrt(disc)) / (2 * a); x2 = (-b - sqrt(disc)) / (2 * a); cout << x1 << " ve " << x2 << " noktalarnda iki gerçel kök var." << endl; } } return EXIT_SUCCESS; 47 Ak³ Denetimi 3.1 Ko³ul Deyimleri Blok yapl programlamadaki seçim ve yineleme yaplarnda bir ko³ula göre bir karar verilmesinin sa§lanmas gerekti§i görülmü³tü (bkz. Bölüm 1.3). Ko³ullar, ko³ul deyimleriyle gösterilirler. C dilinde bir ko³ul deyimi, iki saysal büyüklü§ün (aritmetik deyimin) kar³la³trlmas ile olu³turulur ve mantksal bir de§er (do§ru ya da yanl³) üretir. Di§er bütün veri tipleri gibi mantksal de§erler de saylarla temsil edilirler; yanl³ de§eri 0, do§ru de§eriyse 1 saysyla gösterilir. 3.1.1 Kar³la³trma ³lemleri ki say de§eri arasnda ³u kar³la³trma i³lemleri yaplabilir: • E³itlik: == i³leciyle gerçeklenir. ³lecin solundaki de§erle sa§ndaki de§er aynysa do§ru, farklysa yanl³ sonucunu üretir. • Farkllk: != i³leciyle gerçeklenir. E³itlik kar³la³trmasnn tersidir. ³lecin solundaki de§erle sa§ndaki de§er farklysa do§ru, aynysa yanl³ sonucunu üretir. • Küçüklük: < i³leciyle gerçeklenir. ³lecin solundaki de§er sa§ndaki de§erden küçükse do§ru, küçük de§ilse yanl³ sonucunu üretir. • Büyüklük: > i³leciyle gerçeklenir. ³lecin solundaki de§er sa§ndaki de§erden büyükse do§ru, büyük de§ilse yanl³ sonucunu üretir. • Küçüklük veya e³itlik: <= i³leciyle gerçeklenir. Büyüklük kar³la³trmasnn tersidir. ³le- cin solundaki de§er sa§ndaki de§erden küçük veya e³itse do§ru, büyükse yanl³ sonucunu üretir. • Büyüklük veya e³itlik: >= i³leciyle gerçeklenir. Küçüklük kar³la³trmasnn tersidir. ³le- cin solundaki de§er sa§ndaki de§erden büyük veya e³itse do§ru, küçükse yanl³ sonucunu üretir. Örnekler • Yl 4'e kalansz bölünebiliyor mu? (year % 4) == 0 • Ya³ 18'den büyük ya da e³it mi? age >= 18 Kar³la³trma i³lemleri tam ya da kesirli saylarn kar³la³trlmasnda kullanlabilece§i gibi, harerin abecedeki sralarna göre kar³la³trlmasnda da kullanlabilir. Sözgelimi 'm' < 'u' 48 Ko³ul Deyimleri ko³ul deyimi do§ru de§erini üretir. Ancak bu i³lem yalnzca ngilizce harer arasnda do§ru sonuç üretecektir. Ayrca, büyük-küçük harf kar³la³trmalarnda da abece srasndan farkl sonuçlar çkabilir. Örne§in ³u ko³ul deyimi do§ru de§erini üretir: 'Z' < 'a' Bu nedenlerle, simgelerin kar³la³trlmas yalnzca ngilizce harer için ve ikisi de büyük ya da ikisi de küçük harerin kar³la³trlmasnda kullanlmaldr. 1 Ayrca, kar³la³trma i³leçleriyle katarlar abece srasna göre kar³la³trlamaz, yani a³a§daki komut geçerli de§ildir (do§ru ya da yanl³ sonucunu üretmez, derleyicinin hata vermesine neden olur): dennis < ken Kesirli saylarn e³itlik açsndan kar³la³trlmasnda da dikkatli olunmas gerekir. Kesirli saylar bilgisayarlarda tam olarak temsil edilemeyebileceklerinden bunlar arasnda e³itlik kar³la³trmas yapmak hatal sonuçlar do§urabilir. Genellikle farklarnn mutlak de§erinin yeterince küçük bir say olup olmad§na bakmak daha emin bir yöntemdir. Örne§in f1 == f2 yerine a³a§daki gibi bir ko³ul yazlabilir: fabs(f1 - f2) < 1E-6 3.1.2 Mantksal ³lemler Baz durumlarda tek bir kar³la³trma i³lemi bütün ko³ul deyimini olu³turmak için yeterli olmaz. Örne§in bir insann ya³nn 18 ile 65 arasnda olup olmad§n snamak istiyorsanz, bunu tek bir kar³la³trma i³lemiyle yapamazsnz (18 <= x < 65 gibi bir deyim yazlamaz). Böyle durumlarda, kar³la³trma i³lemleri mantksal i³lemlerle ba§lanarak karma³k ko³ul deyimleri üretilebilir. Üç tane mantksal i³lem vardr: • DEL i³lemi: ! i³leciyle gerçeklenir. Önüne yazld§ ko³ul deyimini de§iller, yani do§ruysa yanl³, yanl³sa do§ru de§erini üretir (bkz. Tablo 3.1). ko³ul !(ko³ul) do§ru yanl³ yanl³ do§ru Tablo 3.1: De§il i³lemi do§ruluk tablosu. Örnek Ya³ 18'den küçük de§il: !(age < 18) 49 Ak³ Denetimi ko³ul1 ko³ul2 (ko³ul1) && (ko³ul2) do§ru do§ru do§ru do§ru yanl³ yanl³ yanl³ do§ru yanl³ yanl³ yanl³ yanl³ Tablo 3.2: VE i³leminin do§ruluk tablosu. • VE i³lemi: && i³leciyle gerçeklenir. Ba§lad§ ko³ullarn hepsi do§ruysa do§ru, en az biri yanl³sa yanl³ de§erini üretir (bkz. Tablo 3.2). Örnek Ya³ 18'den büyük veya e³it ve 65'den küçük: (age >= 18) && (age < 65) • VEYA i³lemi: || i³leciyle gerçeklenir. Ba§lad§ ko³ullarn hepsi yanl³sa yanl³, en az biri do§ruysa do§ru de§erini üretir (bkz. Tablo 3.3). ko³ul1 ko³ul2 (ko³ul1) || (ko³ul2) do§ru do§ru do§ru do§ru yanl³ do§ru yanl³ do§ru do§ru yanl³ yanl³ yanl³ Tablo 3.3: VEYA i³leminin do§ruluk tablosu. Örnek Ya³ 18'den küçük veya 65'den büyük veya e³it: (age < 18) || (age >= 65) Örnek Bir yln artk yl olup olmad§n belirleyen ko³ul deyimi. Sonu 00 ile biten (100'e kalansz bölünen) yllar d³ndaki yllar 4 saysna kalansz bölünüyorlarsa artk yl olurlar. Sonu 00 ile bitenler ise 400 saysna kalansz bölünüyorlarsa artk yldrlar. Bunlarn d³nda kalan yllar artk yl de§ildir. Sözgelimi, 1996, 2000, 2004 ve 2400 yllar artk yldr ama 1997, 2001, 1900 ve 2100 yllar artk yl de§ildir. ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0) Ayraçlar kullanlmad§nda mantksal i³leçlerin öncelikleri yüksek öncelikliden ba³layarak DEL, VE, VEYA srasyladr. Buna göre yukardaki örnek (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0) ya da 1 Aslnda burada kar³la³trlan bu iki simgenen ASCII kodlamasndaki sralardr. 50 Seçim (year % 400 == 0) || (year % 4 == 0) && (year % 100 != 0) biçiminde de yazlabilirdi. 3.2 2 Seçim C dilinde seçim yaplar, alyorsa if if/else bloklaryla gerçeklenir. Verilen ko³ul deyimi do§ru de§erini ile ba³layan blok (blok1), yanl³ de§erini alyorsa else ile ba³layan blok (blok2) yürütülür: if (ko³ul ) { blok1 ; } else { blok2 ; } Örnekte içiçe iki seçim yaps vardr. çteki seçim yaps ³u ³ekildedir: if (disc == 0) { x1 = -b / (2 * a); cout < < x1 < < noktasnda çak³an iki kök var. < < endl; } else { x1 = (-b + sqrt(disc)) / (2 * a); x2 = (-b - sqrt(disc)) / (2 * a); cout < < x1 < < ve < < x2 < < noktalarnda iki gerçel kök var. < < endl; } Burada disc de§i³keninin de§eri 0 ise çak³k köklerle ilgili i³lemler yaplr (iki komuttan olu³an bir blok); de§ilse farkl iki gerçel kök bulunmas durumundaki i³lemler yaplr (üç komuttan olu³an bir blok). Seçim yaplarnda bir else blo§u bulunmas zorunlu de§ildir, yani yap if (ko³ul ) { blok ; } 2 Birden fazla ko³uldan olu³an mantksal deyimler de§erlendirilirken sonuç belli oldu§u zaman deyimin geriye kalan hesaplanmaz. Örne§in (year % 4 == 0) && (year % 100 != 0) (year % 4 == 0) ko³ulu yanl³ de§erini verirse deyimin (year % 100 != 0) ko³ulu snanmaz. Benzer ³ekilde deyiminde §ndan geri kalanna baklmaya gerek kalmayaca- (year % 4 == 0) || (year % 100 != 0) deyiminde (year % 4 == 0) ko³ulu do§ru de§erini verirse yine ikinci ko³ul snanmaz. 51 Ak³ Denetimi ³eklinde olabilir. Bu durumda ko³ul do§ruysa blok yürütülür, de§ilse hiçbir ³ey yaplmaz. Bir blok tek bir komuttan olu³uyorsa blo§un süslü ayraçlar ile snrlanmas zorunlu de§ildir. Örnekteki d³ seçim yapsnda dikkat edilirse ko³ulun do§ru olmas durumunda yürütülecek blokta süslü ayraçlar kullanlmam³tr: if (disc < 0) cout < < Gerçel kök yok. < < endl; else { ... ... ... } Burada istenseydi birinci blok da süslü ayraçlarla belirtilebilirdi: if (disc < 0) { cout < < Gerçel kök yok. < < endl; } else { ... ... ... } Gelenek olarak tek komutlu bloklarda süslü ayraçlar kullanlmaz, yani örnek programda kul- Gelenek lanlan yazl³ ³ekline uyulur. Ancak bu durumda süslü ayraç kullanlmayan blo§un tek komut içermesine çok dikkat etmek gerekir. Di§er bir gelenek de, ko³ulun do§ru ya da yanl³ olmasna göre yürütülecek bloklardan biri di§erine göre çok ksaysa, ksa olan blok üste gelecek (ko³ulun do§ru olmas durumunda yürütülecek) ³ekilde düzenlenmesidir. Örnekte bu gelene§e uyulmam³ olsayd d³ seçim yaps ³u ³ekilde yazlabilirdi: if (disc >= 0) { ... ... ... } else cout < < Gerçel kök yok. < < endl; Seçim ve ileride görülecek yineleme yaplar bir bütün olarak tek bir komut olarak de§erlendirilirler. Dolaysyla bir blokta yer alan tek yap ba³ka bir seçim ya da yineleme blo§uysa süslü ayraçlarn kullanlmas zorunlu de§ildir. Yani ³u blok if (ko³ul1 ) { if (ko³ul2 ) blok ; } 52 Seçim ³u ³ekilde de yazlabilir: if (ko³ul1 ) if (ko³ul2 ) blok ; Süslü ayraçlar kullanlmad§nda içiçe if / else yaplarnda belirsizlikler olu³abilir. Girinti- lenmeden yazlm³ ³u örne§e bakalm: if (ko³ul1 ) if (ko³ul2 ) blok1 ; else blok2 ; Burada blok2 hangi ko³ul sa§lanmazsa yürütülecektir? C dilinin bu konudaki kural kendinden önce gelen son ko³ul2 if ko³uluna ba§land§dr, yani örnekte blok2 , ko³ul1 else'in do§ru ve yanl³sa yürütülür. Do§ru bir girintilemeyle yazlrsa if (ko³ul1 ) if (ko³ul2 ) blok1 ; else blok2 ; Yine de kar³kl§a neden olmamas için böyle durumlarda süslü ayraçlar kullanmak daha do§rudur. DKKAT Herhangi bir aritmetik deyim ko³ul de§eri olarak de§erlendirilebilir; deyimin sonucu 0 ise yanl³, 0'dan farkl ise do§ru oldu§u varsaylr. Buna göre, sözgelimi 8 - 2 deyimi do§ru, 8 - 2 * 4 deyimiyse yanl³ bir ko³ul olarak de§erlendirilir. Bu davran³ özellikle e³itlik kar³la³trmalarnda hataya yol açabilir. En sk yaplan C hatalarndan biri bir e³itlik kar³la³trmasnda yerine = == i³areti kullanlmasdr. age = 12; ... ... if (age = 18) blok1 ; else blok2 ; Yukardaki programda ko³ulun snanmas srasnda e³itlik i³lemi de§il atama i³lemi belirtildi§inden age de§i³kenine 18 atanr, deyimin de§eri 18 olarak bulunur ve 0'dan farkl oldu§u için do§ru saylarak de§i³mez ve blok2 blok1 yürütülür. Oysa yürütülürdü. == simgesi kullanlsayd age de§i³keninin de§eri 53 Ak³ Denetimi 3.2.1 Ko³ullu ³leç Ko³ullu i³leç, bir ko³ulun gerçekle³ip gerçekle³memesine göre iki deyimden birini seçer. deyim1 ? deyim2 : deyim3 Burada öncelikle deyim1 de§erlendirilir. Sonuç do§ruysa deyim2 , yanl³sa deyim3 seçilir. Basit bir örnekle, iki saydan küçü§ünü seçmek için ³öyle bir kod kullanlabilir: if (x < y) z = x; else z = y; Ayn i³lem ko³ullu i³leç kullanlarak ³öyle de yazlabilirdi: z = x < y ? x : y; Adndan da anla³labilece§i gibi, ko³ullu i³leç bir i³leçtir, yani birtakm büyüklükler üzerinde bir i³lem yapar ve belli bir tipten bir sonuç üretir. Bir seçim yaps de§ildir, yani programn ak³nn nasl devam edece§i üzerinde bir etki yaratmaz; ak³ bir sonraki komutla devam eder. Örnek 4. ³lem Seçimi ³lemi ve i³lenenleri kullancnn belirtti§i hesaplamay yaparak sonucu ekrana yazan bir program yazlmas isteniyor. Programn örnek bir çal³masnn ekran çkts ekil 3.2'de verilmi³tir. ³lemi yaznz: 18 / 5 18/5 i³leminin sonucu: 3 ekil 3.2: Örnek 4 ekran çkts. 3.3 Çoklu Seçim Bir deyimin çok sayda de§er içinden hangisini alm³ oldu§unu snamak istiyorsak yazaca§mz if kodu uzun ve çirkin bir görünüm alr. Örne§imizde yaplacak i³lemin hangisi oldu§unu anlamak için yazlacak if if (op == '+') { ... } else { kodu ³u tip bir ³ey olurdu: 54 Çoklu Seçim Örnek 4 Kullancnn belirtti§i i³lemi yapan program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; int main(void) { int num1, num2, result; char op; } cout << "³lemi yaznz: "; cin >> num1 >> op >> num2; switch (op) { case '+': result = num1 + num2; break; case '-': result = num1 - num2; break; case '*': result = num1 * num2; break; case '/': result = num1 / num2; break; case '%': result = num1 % num2; break; default: cout << "Böyle bir i³lem yok." << endl; return EXIT_FAILURE; } cout << num1 << op << num2 << " i³leminin sonucu: " << result << endl; return EXIT_SUCCESS; 55 Ak³ Denetimi if (op == '-') { ... } else { if (op == '*') { ... Seçim bloklarnn tek bir komut olarak de§erlendirilmesi çoklu kar³la³trmalarda da daha kolay bir yazm olana§ sa§lar. Buna göre, yukardaki çoklu kar³la³trma yaps ³u ³ekilde de yazlabilir: if (op == '+') ... else if (op == '-') ... else if (op == '*') ... switch komutu bu tip kar³la³trmalar için daha okunakl bir yap sunar: switch (deyim ) { case de§er_1 : blok_1 ; break; case de§er_2 : blok_2 ; break; ... case de§er_n : blok_n ; break; default: blok ; break; } Bu komutun ak³ çizene§i ekil 3.3'de görüldü§ü gibidir. Deyim, önce birinci de§erle kar³la³trlr ve e³itse buna ili³kin blok yürütülür ve break komutuyla switch yapsnn d³na çklr. Birinci de§ere e³it de§ilse ikinci de§erle kar³la³trlr. Kar³la³trmalarn hiçbiri do§ru de§ilse default blo§u yürütülür ve switch sona erer. Her switch yapsnda bir default blo§u bulunmas zorunlu de§ildir. Burada dikkat edilmesi gereken bir nokta, deyimin di§er bir deyimle de§il, bir de§erle kar³la³trld§dr. Yani, kar³la³trlacak de§erlerin yazld§ deyimlerde de§i³kenler yer alamaz. Örne§in a³a§daki yazmda deyim yazl³ geçerlidir ancak de§erin yazl³ geçerli de§ildir: switch (5 * x) { ... case y: ... ... } 56 Çoklu Seçim case 1 D blok 1 break blok 2 break blok n break Y case 2 D Y case n D Y default blok ekil 3.3: switch komutunun ak³ çizene§i. 57 Ak³ Denetimi Kar³la³trlan deyim ve de§erler yalnzca tamsay ve simge tipinden olabilir (örnekte simge tipinden de§erlerle kar³la³trma yaplm³tr). Örne§in a³a§daki yazmlar geçerli de§ildir: switch (name) { ... case Dennis: ... ... } switch (x) { ... case 8.2: ... ... } Yine dikkat edilmesi gereken bir nokta, kar³la³trmann yalnzca e³itlik üzerinden yapld§dr. Bu yazmda, deyimin de§erden küçük ya da büyük olup olmad§ ya da di§er herhangi bir mantksal deyimin do§rulu§u belirtilemez. Ayrca, yazmdan görülebilece§i gibi, switch yaplarnda bloklar süslü ayraçlar içine alnmaz. C programlarnda skça yaplan hatalardan biri bloklardaki Örne§in birinci blo§un sonuna konmas gereken break break komutlarnn unutulmasdr. switch komutu komutu unutulursa ekil 3.4'de görüldü§ü gibi çal³r. Birinci kar³la³trma i³lemi ba³arsz olursa bir sorun çkmaz ama ba³arl olursa blok 1 yürütüldükten sonra blok 2 de yürütülür ve sonlanr. Yani, ba³arl olan ilk kar³la³trmadan ba³lanarak gelen bütün bloklar yürütülür. Örnek programdaki hiçbir 3 break break ile switch komutu görülene kadar break komutu konmam³ olsa i³lemin toplama oldu§u durumda önce toplama, sonra çkartma, çarpma, bölme ve son olarak da kalan i³lemi yaplr (yani yalnzca kalan i³lemi geçerli olur), ayrca da Böyle bir i³lem yok. denilerek herhangi bir sonuç görüntülenmeden programdan çklr. ³lem çkartma oldu§unda toplama ksm atlanr, gerisi deminki gibi devam eder. Uygulama: Seçim Yaplar Bu uygulamada Windows ortamnda bir tümle³ik geli³tirme ortam (Visual C++ ya da DevC++) tantlacaktr. Hata ayklaycda adm adm ilerleme ve de§i³ken de§erlerinin gözlenmesi gösterilecektir. Örnek 5. Birim Dönü³ümü Bu örnekte ngiliz uzunluk ve scaklk ölçü birimlerinin metrik birimlere dönü³ümünü yapan bir program yazlacaktr. inch biriminden verilen bir uzunlu§u santimetre birimine çevirmek için 3 Bu davran³, baz durumlarda yararl yönde de kullanlabilir (bkz. Örnek 10). 58 Çoklu Seçim case 1 D blok 1 Y case 2 D blok 2 break blok n break Y case n D Y default blok ekil 3.4: switch komutunda break kullanlmazsa olu³an ak³ çizene§i. 59 Ak³ Denetimi 1 inch = 2.54 cm e³itli§i ve Fahrenheit biriminde verilen bir sckl§ Celcius birimine çevirmek için de 5 C = (F − 32) 9 formülü kullanlacaktr. • Verilen örnek program yazn, çal³trn, birkaç de§er için deneyin • case 1 blo§unun sonundaki break komutunu silin ve program çal³trarak her iki dönü³üme de birer örnek deneyin • cm->inch ve c->f dönü³ümlerini yapmak üzere kodunuzu geli³tirin • 1f t = 12inch e³itli§ini kullanarak ft cinsinden verilmi³ bir uzunlu§u mt cinsine çevirecek eklemeyi yapn • mt->ft dönü³ümünü yapacak eklemeyi yapn Örnek 6. Euclides Algoritmas ki saynn en büyük ortak bölenini Euclides algoritmasn kullanarak bulan bir program yazlmas isteniyor. Bu algoritmaya ili³kin ak³ çizene§i ekil 1.17'de, programn örnek bir çal³masnn ekran çkts ekil 3.5'de verilmi³tir. Saylar yaznz: 9702 945 9702 ve 945 saylarnn en büyük ortak böleni: 63 ekil 3.5: Örnek 6 ekran çkts. 3.4 Ko³ul Denetiminde Yineleme C dilinde temel yineleme yaplar while (ko³ul ) { blok ; } while sözcü§üyle kurulur: 60 Ko³ul Denetiminde Yineleme Örnek 5 ngiliz-metrik birim dönü³ümü yapan program. #include <iostream> #include <stdlib.h> // cout,cin,endl // EXIT_SUCCESS,EXIT_FAILURE using namespace std; int main(void) { int choice; float inch, cm, f, c; cout << "1. inch-cm" << endl; cout << "2. f-c" << endl; cout << "3. Çk³" << endl; cout << "Seçiminiz: "; cin >> choice; } switch (choice) { case 1: cout << "inch cinsinden uzunluk: "; cin >> inch; cm = 2.54 * inch; cout << cm << " cm" << endl; break; case 2: cout << "f cinsinden scaklk: "; cin >> f; c = (f - 32) * 5.0 / 9.0; cout << c << " C" << endl; break; case 3: return EXIT_SUCCESS; default: cout << "Böyle bir i³lem yok." << endl; return EXIT_FAILURE; } return EXIT_SUCCESS; 61 Ak³ Denetimi Örnek 6 ki saynn en büyük ortak bölenini bulan program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; int main(void) { int num1, num2; int a, b, r = 1; cout << "Saylar yaznz: "; cin >> num1 >> num2; a = num1 > num2 ? num1 : num2; b = num1 > num2 ? num2 : num1; } while (b > 0) { r = a % b; a = b; b = r; } cout << num1 << " ve " << num2 << " saylarnn en büyük ortak böleni: " << a << endl; return EXIT_SUCCESS; 62 Döngü Denetimi Örnekteki while blo§u b de§i³keninin de§eri 0'dan büyük oldu§u sürece yinelenecek, 0 oldu- §unda sona erecektir. Bu örnekte algoritmann do§as gere§i bu de§i³ken eninde sonunda 0 de§erini alacaktr; ancak yineleme yaplar kurarken döngünün her durumda mutlaka sonlanmasnn sa§lanmasna özellikle dikkat edilmelidir. Benzer bir di§er yineleme yaps ise do-while sözcükleriyle kurulabilir: do { blok ; } while (ko³ul ); Bu yapnn while yapsndan en önemli fark, ko³ulun do§ru olup olmamasna baklmakszn blo§un en az bir kere yürütülmesidir. Örnekteki yineleme bölümü ³u ³ekilde de yazlabilirdi: do { r = a % b; a = b; b = r; } while (b > 0); Ba³langçta num1 ve num2 de§i³kenlerinden birinin 0 olmas durumunda b de§i³keni 0 de§erini alrd. lk örnekte ko³ul sa§lanmayaca§ için en büyük ortak bölen 1 olarak bildirilirdi; ikinci Gelenek örnekte ise sfra bölme yapmaya kalklaca§ndan bir çal³ma zaman hatas olu³urdu. Her ne kadar while ile kurulan yaplar ve do-while ile kurulan yaplar birbirlerinin e³i olacak ³ekilde while kullanlmas önerilir. düzenlenebilseler de, yineleme yaps kurmak için genelde 3.5 Döngü Denetimi Yineleme yaplarnda kullanlan di§er bir yöntemse, döngüyü bir sonsuz döngü olarak kurup döngüden çkma durumu olu³tu§unda break komutunu kullanmaktr: 4 while (true) { ... if (<çkma ko³ulu sa§lanyor >) break; ... // çkma ko³ulu sa§lanmad§ zaman yaplacaklar } Çoklu seçim (switch) yapsnda oldu§u gibi burada da break komutu içinde bulunulan yapdan çk³ sa§lar. Ancak örnekte görüldü§ü gibi içinden çklan yap if de§il while yapsdr. Yani, break komutu switch, while, do-while ve birazdan görece§imiz for yaplarndan çkartr, if yapsndan çkartmaz. çiçe döngüler kullanld§nda, beklenebilece§i gibi, break komutu yalnzca en içteki döngüden çkartr ve bir üstteki döngünün sradaki komutundan devam edilmesini sa§lar: 4 Bu tür bir yap Örnek 10'da görülebilir. 63 Ak³ Denetimi while (true) { ... while (true) { ... if (<çkma ko³ulu sa§lanyor >) break; ... } ... // üstteki break komutu sonucunda buraya gelinir } Döngülerde ak³ denetimine yönelik di§er bir komut ise continue komutudur. Bu komut dön- günün geri kalan ksmnn atlanarak döngü ba³na gidilmesini sa§lar: i = 0; while (i < 50) { i++; ... if (<ko³ul> ) { ... continue; } ... } if ile belirtilen ko³ul sa§lanyorsa birtakm i³lemlerin gerçekle³tirilmesinden sonra ba³na dönülür. Yani if blo§undan sonra gelen komutlar atlanarak i de§i³keninin Bu örnekte döngünün bir sonraki de§erinden i³lemler sürdürülür. Örnek 7. Yinelemeli Yaz-Tura At³ Kullancnn verdi§i say kadar yaz-tura atarak yaz ve turalarn kaçar kere geldi§ini sayan ve sonuçlar ekrana çkartan bir program yazlmas isteniyor. Bu programa ili³kin ak³ çizene§i ekil 3.6'da, programn örnek bir çal³masnn ekran çkts ekil 3.7'de verilmi³tir. 3.6 Sayaç Denetiminde Yineleme Örnekte yaz-tura simülasyonunun kullancnn belirtece§i sayda yinelenmesi isteniyor. Bir blo§un belli sayda yinelenmesi istendi§inde kullanlabilecek en uygun yap for yapsdr. Bir sayacn denetiminde yineleme yapmak için ³unlarn belirtilmesi gerekir: • Sayacn ba³langç de§eri: Örnekte bu de§er 1'dir. • Kaça kadar saylaca§: Örnekte bu de§er kullancdan alnan saynn tutuldu§u de§i³keniyle belirlenir. count 64 Sayaç Denetiminde Yineleme basla oku: count i←1 heads ← 0 tails ← 0 i ≤ count Y D Tura at bas: heads bas: tails Yazi dur bas: "Tura" bas: "Yazi" heads ← heads + 1 tails ← tails + 1 i←i+1 ekil 3.6: Yinelemeli yaz-tura at³nn simülasyonu. Kaç kere atlacak? 7 Yaz Tura Tura Yaz Yaz Yaz Yaz Tura says: 2, Yüzdesi: %28.5714 Yaz says: 5, Yüzdesi: %71.4286 ekil 3.7: Örnek 7 ekran çkts. 65 Ak³ Denetimi Örnek 7 Yinelemeli yaz-tura at³ simülasyonu yapan program. #include <iostream> #include <stdlib.h> #include <time.h> // cin,cout,endl // EXIT_SUCCESS,srand,rand,RAND_MAX // time using namespace std; int main(void) { int count, i; float number; int heads = 0, tails = 0; } cout << "Kaç kere atlacak? "; cin >> count; srand(time(NULL)); for (i = 1; i <= count; i++) { number = (float) rand() / RAND_MAX; if (number < 0.5) { cout << "Tura" << endl; heads++; } else { cout << "Yaz" << endl; tails++; } } cout << " Tura says: " << heads << ", Yüzdesi: %" << 100.0 * heads / count << endl; cout << " Yaz says: " << tails << ", Yüzdesi: %" << 100.0 * tails / count << endl; return EXIT_SUCCESS; 66 Sayaç Denetiminde Yineleme • for Kaçar kaçar saylaca§: Örnekte sayacn birer birer artrlaca§ belirtilmi³tir. yaps bu üç belirtimin ayn anda yaplmasna olanak sa§lar. Ay içinde önce ba³langç de§eri atamas, ikinci olarak hangi ko³ul sa§land§ sürece devam edilece§i ve son olarak da sayacn nasl artrlaca§ belirtilir. for (i = 1; i <= count; i++) komutu ³öyle okunabilir: i de§i³kenine 1 de§erini ver ve bu de§i³kenin de§eri count de§i³keninin de§erinden i de§i³keninin de§erini küçük veya e³it oldu§u sürece blo§u her yürütü³ünden sonra 1 artr. for döngüleri while döngüleri ³eklinde de yazlabilirler: for (ba³langç_atamas ; sürme_ko³ulu ; artrma_komutu ) { blok ; } döngüsü ba³langç_atamas ; while (sürme_ko³ulu ) { blok ; artrma_komutu ; } döngüsüne e³de§erlidir. Yine de sayaç denetiminde yinelemeler için yinelemeler için while for, ko³ul denetiminde kullanmak anla³lrlk açsndan daha do§rudur. Bu yapyla ilgili olarak baz noktalara dikkat etmek gerekir: • Döngü, belirtilen ko³ul sa§lanmad§ zaman sonlanr ve programn yürütülmesi döngünün arkasndan gelen komutla sürdürülür. Örnekte i de§i³keninin de§eri count de§i³ke- ninin de§erinden büyük oldu§u zaman döngü sona erer. • Artrma i³lemi döngü gövdesi yürütüldükten sonra yaplr. Örnekte döngünün gövdesi de§i³keninin 1, 2, ..., • count i de§erleri için yinelenir, 1 de§eri atlanmaz. Verilen ba³langç de§eri döngü ko³ulunu sa§lamyorsa döngünün gövdesi hiç yürütülmez. Örne§in for (i = 1; i == 10; i++) 67 Ak³ Denetimi döngüsünde ba³langç de§eri sürme ko³ulunu sa§lamad§ndan (1 == 10 do§ru olmad§ndan) döngüye hiç girilmez. • Artm miktar için artrma i³leci kullanlmas zorunlu de§ildir, herhangi bir C deyimi kullanlabilir. for (i = 1; i < count; i = i + 3) döngüsü 1, 4, 7, 10, 13, ... ³eklinde sayarken for (i = 1; i < count; i = i * 2) döngüsü 1, 2, 4, 8, 16, ... ³eklinde sayar. Rasgele Saylar Yaz-tura at³n temsil etmek için en kolay yol 0 ile 1 arasnda bir rasgele say üretmek ve bu saynn 0.5'den küçük olmas durumunu bir sonuca (diyelim tura), e³it ya da büyük olmasn da di§er sonuca (bu durumda yaz) atamaktr. rand fonksiyonu 0 ile RAND_MAX arasnda bir rasgele tamsay üretir. RAND_MAX standart kitaplkta tanmlanm³ bir de§erdir ve sistemden sisteme farkllk gösterebilir. rand fonksiyonundan gelen say RAND_MAX de§erine bölünürse 0 ile 1 arasnda bir rasgele C standart kitapl§ndaki kesirli say elde edilir. Rasgele saylarn kullanmnda daha çok 1 ile bir üst snr arasnda de§er alacak bir rasgele tamsayya gereksinim duyulur. Bu üst snr max ile gösterilirse 1 + rand() % max deyimi istenen türden bir say üretir (Neden?). Rasgele saylar, bir seri olarak üretilirler; yani her rasgele say seride bir önceki rasgele saydan üretilir. Bu serinin ba³layabilmesi için ilk sayy üretmekte kullanlacak bir ba³langç de§eri (tohum ) verilmesi gerekir. srand fonksiyonu bu tohumun belirtilmesini sa§lar. Ayn tohumla ba³lanrsa ayn seri üretilir. Her serinin programn çal³masndaki bir senaryoya kar³lk dü³tü§ü dü³ünülürse istendi§i zaman ayn senaryoyu üretebilmek programn hatalarnn ayklanmas açsndan yararldr. Her defasnda farkl bir tohumla ba³lamak için tohumun da her defasnda farkl verilmesi gerekir. Standart kitaplktaki time fonksiyonu, 1 Ocak 1970 tarihinden o ana kadar geçen saniyelerin saysn verdi§inden her ça§rl³nda farkl bir tohum üretebilir. Bu fonksiyona NULL giri³ parametresini göndermek yeterlidir. Uygulama: Döngüler Bu uygulamada Unix bir hata ayklayc (ddd) tantlacaktr. Hata ayklaycda adm adm ilerleme ve de§i³ken de§erlerinin gözlenmesi gösterilecektir. 68 Sayaç Denetiminde Yineleme Örnek 8. Seri Toplam Bu uygulamada görülecek programlarda, ex fonksiyonunun hesaplanmas için a³a§daki seri toplamndan yararlanlacaktr: f (x) = ∞ X xi i=0 i! =1+x+ x2 x3 x4 + + + ··· 2! 3! 4! Birinci programda (Örnek 8) içiçe iki döngü vardr. çerideki döngü o anda i³lenmekte olan terimde gerekecek faktöryel de§erinin hesaplanmasn sa§lar. D³ döngüyse her yineleni³inde serinin o anki terimi hesaplayarak toplama ekler. Hesaplanan terim kullancnn belirtti§i hatadan küçük oldu§unda de§erin istenen duyarllkta hesapland§na karar verilerek sonuç ekrana çkartlr. Örnek 8 ex deyimini genel terimden giderek hesaplayan program. #include <iostream> #include <stdlib.h> #include <math.h> // cin,cout,endl // EXIT_SUCCESS // pow using namespace std; int main(void) { float x, error, term, result = 1.0; int i = 1, f; float fact; cout << "x: "; cin >> x; cout << "Hata: "; cin >> error; term = error + 1; while (term > error) { fact = 1.0; for (f = 2; f <= i; f++) fact = fact * f; term = pow(x, i) / fact; result = result + term; i++; } cout << "Sonuç: " << result << endl; } return EXIT_SUCCESS; 69 Ak³ Denetimi kinci programdaysa (Örnek 9) ayn i³lemin nasl daha etkin (daha az hesap yüküyle) yaplabilece§i görülecektir. Serinin genel teriminin ai = elemann kendisinden önceki elemana bölümü kendisinden önceki terimin x ile çarplp i'ye ai ai−1 xi i! oldu§u gözönüne alnd§nda dizide bir = xi olarak hesaplanabilir. Yani her terim, bölünmesiyle bulunabilir. Böylece her admda üs alma ve faktöryel hesaplama i³lemlerine gerek kalmaz ve seri toplam çok daha hzl elde edilir. Örnek 9 ex deyimini bir önceki terimden giderek hesaplayan program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; int main(void) { float x, error, term, result = 1.0; int i = 1; cout << "x: "; cin >> x; cout << "Hata: "; cin >> error; term = 1; while (term > error) { term = term * x / i; result = result + term; i++; } cout << "Hata: " << result << endl; return EXIT_SUCCESS; } • Her iki program da yazarak çal³trn. • Ta³ma durumunun gözlenmesi Sorular 1. (x % 3 == 2) && (x > 4) || !(x % 3 == 2) && (x < 6) (a) do§ru yapacak bir x de§eri verin. (b) yanl³ yapacak bir x de§eri verin. mantksal deyimini 70 Sayaç Denetiminde Yineleme (c) x i³aretsiz bir tamsay ise, x'in hangi de§erleri için bu deyim do§ru de§erini alr? 2. A³a§da verilen program parças için x de§i³keninin ba³langç de§erinin 115 oldu§u var- saymyla de§i³kenlerin alacaklar de§erleri izlemek üzere bir çizelge olu³turun. Ak³ çizene§ini çizin. i = -1; while (x >= 1) { i++; y[i] = x % 8; x = x / 8; } for (j = i; j >= 0; j--) cout < < y[j]; 3. x ve m saylar aralarnda asalsa x saysnn m saysna göre evri§i r says, xr = 1 mod m e³itli§ini sa§layan saydr (r < m). Örne§in, x = 5 ve m = 7 ise r = 3 olur. Buna göre, kullancdan ald§ x ve m saylarna göre r de§erini hesaplayan ve ekrana çkartan bir program yazn. x = 8, m = 11 de§erleri için programnzdaki de§i³kenlerin alacaklar de§erleri bir çizelge halinde gösterin. 4. Kusursuz bir say, kendisinden küçük bütün çarpanlarnn toplamna e³it olan saydr. Örne§in, 28 = 1 + 2 + 4 + 7 + 14. Buna göre, ilk 10000 say içindeki kusursuz saylar ekrana döken bir program yazn. 5. nsan bedeninin alann hesaplamakta kullanlabilecek iki formül a³a§da verilmi³tir. DuBois formülü: Boyde formülü: bsa = h0.725 ∗ w0.425 ∗ 71.84 ∗ 10−4 bsa = h0.3 ∗ w(0.7285−0.0188 log w) ∗ 3.207 ∗ 10−4 h de§i³keni cm cinsinden boyu ve bsa de§i³keni de m2 cinsinden beden gösterirken, w de§i³keni kütleyi DuBois formülünde kg, Boyde formülündeyse Her iki formülde de alann g cinsinden gösterir. DuBois formülü yeti³kinlerde iyi sonuç verirken, çocuklarda (bu formülle elde edilen alan de§eri 0.6'dan küçükse) çok hatal olabilmektedir. Buna göre, boy ve kütlesini kullancdan ald§ bir insann (yeti³kin ya da çocuk) beden alann yukarda anlatlan ölçütlere göre hesaplayarak ekrana çkaran bir program yazn. 6. A³a§da verilen Pascal üçgeni için i. satr j. sütundaki de§er (binom katsays) yanda verilen formülle hesaplanr: 0 1 2 3 0 1 1 1 1 2 1 2 1 3 1 3 3 1 4 1 4 6 4 4 ( binomi,j = 1 binomi−1,j−1 + binomi−1,j j =0∨j =i aksi durumda 1 Buna göre, üçgenin ilk 30 satrn hesaplayp ekrana çkartacak bir program yazn. 7. A³a§daki seri toplam hesaplanmak isteniyor: 71 Ak³ Denetimi n X i=0 (a) Bu serinin i. (−1)i xi x0 x1 x2 x3 x4 x5 = − + − + − + ... (2i)! 0! 2! 4! 6! 8! 10! eleman ai ise, ai+1 /ai oran nedir? (b) Bu bilgiyi kullanarak, serinin toplamn hesaplayan bir program yazn (x ve n de- §erleri kullancdan alnacaktr). 8. Rasgele say üretirken kalan i³lecini (%) kullanarak sayy belli bir aral§a indirgemek saylarn üretilme olaslklarn bozar m? Sözgelimi, RAND_MAX'n de§erinin 32767 oldu§unu varsayarak 1 ile 6 arasnda üretece§iniz rasgele sayda bu alt saynn gelme olaslklar e³it midir? De§ilse, daha iyi bir yöntem önerebilir misiniz? Sayaç Denetiminde Yineleme 72 Bölüm 4 Türetilmi³ Veri Tipleri Bu bölümde programcnn var olan veri tiplerinden kendi veri tiplerini (sözgelimi kaytlar, bkz. Bölüm 1.1.2) nasl türetebilece§i üzerinde durulacaktr. C dilinin programcya kendi veri tiplerini tanmlayabilmesi için sundu§u temel olanak, var olan veri tiplerine yeni isimler verilebilmesidir. Bunun için typedef veri_tipi yeni_isim ; komutu kullanlr. Bunun sonucunda veri_tipi isimli tipe yeni_isim adnda bir isim daha verilmi³ olur. Örne§in bir ö§rencinin snav notlar i³lenmek isteniyor olsun. Notlarn 0 ile 100 arasnda birer tamsay olaca§ varsaymyla, ö§renci notu tipinden bilgileri temsil etmek üzere bir veri tipi tanmlanabilir: typedef int score_t; Böylece int veri tipine score_t diye yeni bir isim verilmi³ olur. Daha sonra bu tipten de§i³ken tanmlamak için score_t midterm1, midterm2, final; gibi bir komut yazlabilir. stenirse asl veri tipi isminin kullanlmasnda da bir saknca yoktur, yani int midterm1, midterm2, final; tanm da geçerlili§ini korur ve bu iki tanm birbirine e³de§erlidir. Bir veri tipine yeni bir isim vermenin yararlar ³öyle açklanabilir: • Anla³lrlk artar: Programn kodunu okuyan ki³i bu veri tipinin temsil etti§i bilgiyle ilgili daha iyi bir kir edinebilir. 73 74 • De§i³tirmek kolay olur: Programn geli³tirilmesinin ileri a³amalarnda ya da sonraki sürümlerde ö§renci notlarnn kesirli olabilece§i durumu ortaya çkarsa yalnzca veri tipine isim verme komutunun typedef float score_t; biçiminde de§i³tirilmesi yeterli olur. Veri tipi tanm olmasa bütün kodun taranarak ö§renci notuna kar³lk gelen int veri tiplerini bulup de§i³tirmek gerekir. Bu da baz int sözcüklerinin de§i³mesi, bazlarnn de§i³memesi anlamna gelir ve programn boyutlarna göre büyük zorluklar çkarabilir. Örnek 10. Barbut 1 Barbut oyununun kurallar ³öyledir: • Oyuncu bir çift zar atar. • Att§ zarlarn toplam 7 ya da 11 ise oyuncu kazanr. Att§ zarlarn toplam 2, 3 ya da 12 ise oyuncu kaybeder. Di§er durumlarda att§ zarlarn toplam oyuncunun says olur. Oyuncu ayn toplam veren zarlar bir daha atana kadar ya da att§ zarlarn toplam 7 olana kadar zar atmaya devam eder. Ayn toplam bir daha atarsa oyuncu kazanr. Att§ zarlarn toplam 7 olursa oyuncu kaybeder. switch yapsbreak kullanlmamasdr. Böylelikle durumlar gruplanarak Verilen örnek, bu oyunu simüle eden bir programdr. Bu örne§in ilginç bir yönü nn baz durumlarnda kastl olarak her bir grup için yaplacak i³lemlerin bir kere belirtilmesi sa§lanm³tr. Programn örnek bir çal³masnn ekran çkts ekil 4.1'de verilmi³tir. Zarlar: 1 + 4 = Say: 5 Zarlar: 5 + 1 = Zarlar: 5 + 5 = Zarlar: 6 + 5 = Zarlar: 4 + 1 = Oyuncu kazanr. 5 6 10 11 5 ekil 4.1: Örnek 10 ekran çkts. 1 Bu örnek, H.M. Deitel ve P.J. Deitel'in yazdklar C: How to Program kitabndan uyarlanm³tr. 75 Türetilmi³ Veri Tipleri Örnek 10 Barbut oyununu simüle eden program. #include <iostream> #include <stdlib.h> #include <time.h> // cin,cout,endl // EXIT_SUCCESS,srand,rand // time using namespace std; enum status_e { GAME_CONTINUES, PLAYER_WINS, PLAYER_LOSES }; typedef enum status_e status_t; int main(void) { int die1, die2, sum, point; status_t game_status = GAME_CONTINUES; srand(time(NULL)); die1 = 1 + rand() % 6; die2 = 1 + rand() % 6; sum = die1 + die2; cout << "Zarlar: " << die1 << " + " << die2 << " = " << sum << endl; switch (sum) { case 7: case 11: game_status = PLAYER_WINS; break; case 2: case 3: case 12: game_status = PLAYER_LOSES; break; default: game_status = GAME_CONTINUES; point = sum; cout << "Say: " << point << endl; break; } while (game_status == GAME_CONTINUES) { die1 = 1 + rand() % 6; die2 = 1 + rand() % 6; sum = die1 + die2; cout << "Zarlar: " << die1 << " + " << die2 << " = " << sum << endl; if (sum == point) game_status = PLAYER_WINS; else { if (sum == 7) game_status = PLAYER_LOSES; } } if (game_status == PLAYER_WINS) cout << "Oyuncu kazanr." << endl; else cout << "Oyuncu kaybeder." << endl; 76 Numaralandrma 4.1 Numaralandrma Örnekte oyunun içinde bulunabilece§i çe³itli durumlara birer say de§eri atanarak oyunun o an hangi durumda oldu§u izlenebilir. Örne§in kodumuzda oyunun durumunu gösteren game_status de§i³keninin de§erinin 0 olmas oyunun sürüyor olmasna, 1 olmas oyuncunun kazanmasna ve 2 olmas da oyuncunun kaybetmesine kar³lk dü³ürülebilir. Burada 0, 1 ve 2 de§erlerinin özel bir anlamlar yoktur, herhangi üç farkl de§er de ayn i³levi görür. Okunulurlu§u artrmak amacyla bu saylara birer isim vermek yararl olur. Öyleyse #define GAME_CONTINUES 0 #define PLAYER_WINS 1 #define PLAYER_LOSES 2 ³eklinde de§i³mez tanmlar yaplarak kodun içinde saylar yerine isimler yazlabilir. Bu tip, birbiriyle ilintili birden fazla de§i³mezi birlikte tanmlamak için numaralandrma yöntemi kullanlabilir. enum { GAME_CONTINUES, PLAYER_WINS, PLAYER_LOSES }; komutu yukarda yazlm³ olan üç #define komutuyla ayn etkiyi yaratr. Aksi belirtilmedikçe, süslü ayraçlar içinde yazlan de§i³mezlerden ilkine 0, sonrakine 1, sonrakine 2 vs. ³eklinde de§er verilir. Programc isterse ba³ka de§erler belirtebilir ancak bizim örne§imizde -demin de söylendi§i gibi- de§erlerin, farkl olduklar sürece, ne olduklarnn bir önemi yoktur: enum { GAME_CONTINUES = 58, PLAYER_WINS = 17, PLAYER_LOSES = 154 }; Herhangi bir de§i³meze de§er verilirse onu izleyen de§i³mezlerin de§erleri birer artarak devam eder: enum { JANUARY = 1, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER }; Numaralandrma ile olu³turulmu³ bir de§i³mezler kümesine de topluca bir isim verilerek yeni bir veri tipi olu³turulabilir: enum künye { de§i³mez_tanmlar }; Bu komutun sonucunda enum künye isimli yeni bir veri tipi olu³ur ve bu tipten de§i³kenler tanmlanabilir. Örnekte önce bu ³ekilde da bu tipe typedef enum status_e isimli bir tip olu³turulmu³, daha sonra komutuyla yeni bir isim verilmi³tir. Bu tipten de§i³ken tanmlarken her iki yeni isim de kullanlabilir, yani örnekteki status_t game_status = GAME_CONTINUES; 77 Türetilmi³ Veri Tipleri komutu enum status_e game_status = GAME_CONTINUES; komutuyla e³de§erlidir. 2 Düzenli bir çal³ma için numaralandrma tipinden tanmlanan de§i³kenlerin yalnzca o numaralandrmayla belirlenen de§i³mezler kümesinden de§er almas gerekir. Sözgelimi örne§imizde tanmlanan game_status de§i³keni GAME_CONTINUES, PLAYER_WINS ve PLAYER_LOSES d³nda herhangi bir de§er alamamaldr. Ancak C dili böyle bir kstlama getirmez, yani game_status = 25; gibi anlamsz olacak bir atama C dilinin kurallarna göre yasak de§ildir. Örnek 11. Paralel Direnç E³de§eri Dirençlerin paralel e³de§eri a³a§daki formülle hesaplanabilir: 1 R1 + 1 R2 1 + ··· + 1 Rn Buna göre, kullancdan ald§ dirençlerin paralel e³de§erini hesaplayarak sonucu ekrana çkartan bir program yazlmas isteniyor. Kullancnn kaç tane direnç de§eri girece§i ba³tan belli olmad§ için bu döngü for yapsyla de§il while yapsyla kurulmaya daha uygundur. Son- suz döngüden çkabilmek için kullancnn bir ³ekilde bunu belirtmesine olanak verilmelidir. Bu programda uygulanan yöntem, özel bir de§eri (örne§in 0) bitirme i³areti olarak seçmektir. Kullanc bu de§eri girerek ba³ka direnç de§eri yazmayaca§n belirtebilir. Sonlandrma de§erinin uygun seçilmesi gerekir; geçerli direnç de§erleri sonlandrma de§eri olmaya uygun de§ildir. Programn örnek bir çal³masnn ekran çkts ekil 4.2'de verilmi³tir. Bu programn çal³masnda dikkat çekici bir nokta, kullancnn yazd§ direnç de§erlerinin uygun ³ekilde toplama eklenmelerinin ardndan unutulmalardr. Yani ileride kullancnn girmi³ oldu§u de§erlerle bir i³lem yaplmak istense bunlar bir ³ekilde ula³labilir olmayacaklardr. Bu programn amac açsndan bu durum bir saknca do§urmaz ancak ba³ka problemlerde farkl yaplar kullanmak gerekebilir. 2 C dilinde mantksal bir veri tipi ve true, false de§erleri bulunmad§ daha önce söylenmi³ti. Ancak, do§ru ve yanl³ büyüklükleri programlarda skça gereksinim duyulan de§erler olduklarndan C programlarnda genellikle bunlar genellikle programn ba³nda de§i³mez olarak tanmlanrlar. #define TRUE 1 #define FALSE 0 Daha sk kullanlan bir yöntemse bunlar bir numaralandrma içinde tanmlayarak olu³acak veri tipine yeni bir isim vermektir. enum bool_e { FALSE, TRUE }; typedef enum bool_e bool_t; Böylelikle C++ dilinde oldu§u gibi mantksal bir veri tipi tanmlanm³ olur ve bu tipten de§i³kenler kullanlabilir. 78 Numaralandrma Örnek 11 Paralel direnç e³de§eri hesaplayan program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; struct rational_s { int nom; int denom; }; typedef struct rational_s rational_t; int main(void) { int res_value; rational_t equiv = { 0, 1 }; int a, b, r; int i = 0; while (true) { i++; cout << "R" << i << " (bittiyse 0): "; cin >> res_value; if (res_value == 0) break; equiv.nom = equiv.nom * res_value + equiv.denom; equiv.denom = equiv.denom * res_value; // kesiri basitle³tir a = equiv.nom; b = equiv.denom; while (b > 0) { r = a % b; a = b; b = r; } equiv.nom = equiv.nom / a; equiv.denom = equiv.denom / a; } } if (equiv.nom != 0) cout << "E³de§er direnç: " << equiv.denom << " / " << equiv.nom << " = " << (float) equiv.denom / equiv.nom << endl; else cout << "Hatal i³lem." << endl; return EXIT_SUCCESS; 79 Türetilmi³ Veri Tipleri R1 (bittiyse 0): 5 R2 (bittiyse 0): 8 R3 (bittiyse 0): 11 R4 (bittiyse 0): 4 R5 (bittiyse 0): 0 E³de§er direnç: 440/293 = 1.50171 ekil 4.2: Örnek 11 ekran çkts. 4.2 Yaplar Kayt tiplerinin özelliklerinden Bölüm 1.1.2'de söz edilmi³ti. C dilinde kaytlara yap ad verilir ve ³öyle tanmlanrlar: struct künye { alan_tanmlar ; }; Yap tanmnn sonucunda struct künye isimli yeni bir veri tipi olu³ur ve bu tipten de§i³ken- ler tanmlanabilir. Alan tanmlar de§i³ken tanmlarna benzer ³ekilde yaplr ancak de§i³ken tanm de§ildirler. De§i³ken tanmlarnn bellekte ilgili de§i³ken için yer ayrlmasna neden oldu§u görülmü³tü, oysa tip tanm bellekte yer ayrlmasna neden olmaz. Yer ayrlmas ancak bu yap tipinden bir de§i³ken tanmland§nda gerçekle³ir. Örnekte rasyonel saylar göstermek üzere iki alan olan bir yap kullanlm³tr: saynn pay ksmn gösteren nom ve payda ksmn gösteren denom. Rasyonel saylarn tanm gere§i her iki alan da tamsay tipindendir. Tip tanm sonucunda artk struct rational_s adnda bir veri tipi olu³mu³tur. Kullanm kolayl§ açsndan bu veri tipine 3 yeni bir isim verilmi³tir. Yap tipinden de§i³ken tanmlanrken istenirse künyeli isim, istenirse typedef komutuyla typedef ile verilen yeni isim kullanlabilir ve de§i³kenin alanlarna süslü ayraçlar içinde ba³langç de§erleri verilebilir. A³a§daki iki komut ayn i³i yaparlar, yani yapsnda olan iki de§i³ken tanmlarlar ve res ve equiv isimlerinde, her biri birer rasyonel say equiv de§i³keninin nom alanna 0, denom alanna 1 ba³langç de§erini verirler (ekil 4.3): 3 Tipin tanmlanmas ve yeni isim verilmesi i³lemleri istenirse tek komutta birle³tirilebilir: typedef struct rational_s { int nom, denom; } rational_t; Birle³tirilmi³ tanmlamada istenirse tipin künyesi de belirtilmeyebilir, yani yukardaki örnekte rational_s sözcü§ü yazlmasa da olurdu. Yine de ço§unlukla önerilen yöntem, belirtilmeleri zorunlu olmasa da künyeleri yazmaktr. Bu yazl³ numaralandrmalar için de geçerlidir. 80 Yaplar rational_t res, equiv = { 0, 1 }; struct rational_s res, equiv = { 0, 1 }; res equiv nom nom 0 denom denom 1 ekil 4.3: Yap tipinden de§i³ken tanmlama. Bu de§i³kenlerin her biri, yapda belirtilen alanlar barndrr. Alanlar üzerinde i³lem yapmak için, daha önce görüldü§ü gibi, noktal gösterilim kullanlr, yani de§i³kenin adndan sonra nokta i³aretiyle alann ad belirtilir. Bu durumda, e³de§er direnç de§erini tutan de§i³kenin payda ksmyla bir i³lem yaplacaksa equiv.denom yazlr. Yaplarn alanlar skalar tiplerden tanmlanabilece§i gibi, ba³ka yap tiplerinden ya da tipli numaralandrma tipinden de tanmlanabilir: enum month_e { JANUARY = 1, FEBRUARY, ..., DECEMBER }; typedef enum month_e month_t; struct date_s { int day; month_t month; int year; }; typedef struct date_s date_t; struct academic_year_s { date_t begin, end; }; typedef struct academic_year_s academic_year_t; tanmlar ekil 4.4'de görülen yapy olu³turur. Alanlara eri³im yine noktal gösterilimle sa§lanr: academic_year_t year_2001_2002; year_2001_2002.end.day = 31; year_2001_2002.end.month = MAY; year_2001_2002.end.year = 2002; Ayn yap tipinden de§i³kenler arasnda atama i³lemi yaplabilir. Atama sonucunda kaynak de§i³kenin bütün alan de§erleri var³ de§i³kenin ayn isimli alanlarna atanr. Bu gösterilim bütün alt alanlarn tek tek atanmas zorunlulu§unu giderir, yani 81 Türetilmi³ Veri Tipleri year_2001_2002 academic_year_t begin end day day month month year year ekil 4.4: Yap içinde yap kullanma. equiv.nom = res.nom; equiv.denom = res.denom; ³eklinde atama yapmak yerine yalnzca equiv = res; yazlabilir. Uygulama: Yaplar Örnek 12. Noktann Daireye Göre Konumu Koordinatlarn kullancdan ald§ bir noktann, merkez noktasnn koordinatlar ile yarçapn yine kullancdan ald§ bir dairenin içinde mi, d³nda m, üzerinde mi oldu§unu belirleyerek sonucu ekrana çkaracak bir program yazlmas isteniyor. Noktann koordinatlar merkezinin koordinatlar p xc (x − xc )2 + (y − yc )2 < r ve yc , dairenin yarçap r ise nokta dairenin d³nda p ise nokta dairenin üzerindedir. (x − xc )2 + (y − yc )2 = r daire ise nokta dairenin içinde p (x − xc )2 + (y − yc )2 > r x ve y , ile gösterilirse: • Program yazarak çal³trn. • Merkez noktasnn koordinatlarn (2.1,5.664), yarçapn 3.2, aranan noktann koordinatlarn (5.3,5.664) olarak verin. Bu nokta dairenin neresindedir? Program ne çkt veriyor? Hatalysa neden hataldr ve nasl düzeltilebilir? 82 Yaplar Örnek 12 Noktann daireye göre konumunu bulan program. #include <iostream> #include <stdlib.h> // cout,cin,endl // EXIT_SUCCESS using namespace std; typedef struct point_s { float x, y; } point_t; typedef struct circle_s { point_t center; float radius; } circle_t; int main(void) { circle_t circle1; point_t point1; float p, deltaX, deltaY; } cout << "Daire merkezinin koordinatlarn yazn (x y): "; cin >> circle1.center.x >> circle1.center.y; cout << "Dairenin yarçapn yazn: "; cin >> circle1.radius; cout << "Noktann koordinatlarn yazn (x y): "; cin >> point1.x >> point1.y; deltaX = point1.x - circle1.center.x; deltaY = point1.y - circle1.center.y; p = deltaX * deltaX + deltaY * deltaY; if (p < circle1.radius * circle1.radius) cout << "Nokta dairenin içinde." << endl; else { if (p > circle1.radius * circle1.radius) cout << "Nokta dairenin d³nda." << endl; else cout << "Nokta dairenen üzerinde." << endl; } return EXIT_SUCCESS; 83 Türetilmi³ Veri Tipleri • Bir noktann konumunun belirtilmesinden sonra programdan çkmadan kullancnn ayn daireye göre ba³ka noktalarn da konumlarn sorabilmesi için programda gerekli de§i³iklikleri yapn. • Merkez koordinatlar ve yarçaplar kullancdan alnan iki dairenin kesi³ip kesi³mediklerini belirleyen bir program yazn. Sorular 1. Örnek 11'da equiv de§i³kenine farkl bir ba³langç de§eri verilebilir miydi? Örne§in de§i³ken tanmlama komutu rational_t res, equiv = { 0, 0 }; ³eklinde olsayd program do§ru çal³r myd? 2. Ayn örnekte kullanc ilk direnç de§eri olarak 0 verirse programn davran³ nasl olur? Gerekiyorsa programda dazeltmeler yapn. 3. Örnek 10'da uygulamas yaplan barbut oyunu adil bir oyun mudur? Yani oyuncunun kazanma olasl§ ile kaybetme olasl§ ayn mdr? Yaplar 84 Bölüm 5 Diziler Bu bölümde programlamada skça gereken dizi tiplerinin (bkz. Bölüm 1.1.3) C dilinde nasl kullanlaca§ üzerinde durulacaktr. Örnek 13. statistik Hesaplar Kullancdan ald§ snav notlarnn ortalamasn, varyansn, standart sapmasn ve mutlak sapmasn hesaplayan bir program yazlmas isteniyor. Programn örnek bir çal³mas ekil 5.1'de verilmi³tir. Ö§renci says sapma ad n, i. ö§rencinin notu si , ortalama m, varyans v, standart sapma sd, mutlak ile gösterilirse: Pn i=1 si m = n Pn sd = − m)2 n−1 i=1 (si v = √ v Pn ad = i=1 |si − m| n Bu problemde dört döngü i³lemi görülebilir: 1. Kullancnn girdi§i notlar okumak için bir döngü. 2. Ortalama için gereken, notlarn toplamn hesaplamakta kullanlan döngü (birinci e³itlikteki P i³aretine kar³ dü³er). 3. Varyans ve standart sapma için gereken, her bir notun ortalamayla farklarnn karelerinin toplamn hesaplamakta kullanlan döngü (ikinci e³itlikteki P i³aretine kar³ dü³er). 4. Mutlak sapma için gereken, her bir notun ortalamayla farklarnn mutlak de§erlerinin toplamn hesaplamakta kullanlan döngü (dördüncü e³itlikteki 85 P i³aretine kar³ dü³er). 86 Örnek 13 Çe³itli istatistik hesaplar yapan program. #include <iostream> #include <stdlib.h> #include <math.h> // cin,cout,endl // EXIT_SUCCESS // fabs,sqrt using namespace std; #define MAXSTUDENTS 100 int main(void) { int score[MAXSTUDENTS]; int no_students = 0; float mean, variance, std_dev, abs_dev; float total = 0.0, sqr_total = 0.0, abs_total = 0.0; int i = 0; } cout << "Kaç ö§renci var? "; cin >> no_students; for (i = 0; i < no_students; i++) { cout << i + 1 << ". ö§rencinin notu: "; cin >> score[i]; total = total + score[i]; } mean = total / no_students; for (i = 0; i < no_students; i++) { sqr_total = sqr_total + (score[i] - mean) * (score[i] - mean); abs_total = abs_total + fabs(score[i] - mean); } variance = sqr_total / (no_students - 1); std_dev = sqrt(variance); abs_dev = abs_total / no_students; cout << "Ortalama: " << mean << endl; cout << "Varyans: " << variance << endl; cout << "Standart sapma: " << std_dev << endl; cout << "Mutlak sapma: " << abs_dev << endl; return EXIT_SUCCESS; 87 Diziler Kaç ö§renci var? 5 1. ö§rencinin notu: 65 2. ö§rencinin notu: 82 3. ö§rencinin notu: 45 4. ö§rencinin notu: 93 5. ö§rencinin notu: 71 Ortalama: 71.2 Varyans: 329.2 Standart sapma: 18.1439 Mutlak sapma: 13.04 ekil 5.1: Örnek 13 ekran çkts Burada birinci ve ikinci döngüler tek bir döngüde birle³tirilebilir, kullanc notlar girdikçe bunlar toplama eklenebilir. Ancak üçüncü ve dördüncü döngüler bu döngüye eklenemez, çünkü o döngülerde her bir notun ortalamayla farkna gereksinim vardr ve bu ortalama ancak birinci döngü sona erdi§inde elde edilmektedir. Döngü sayac ayn snr de§erleri arasnda de§i³ti§inden ve her yinelemede ayn ö§renci notu üzerinde i³lem yapld§ndan üçüncü ve dördüncü döngüler de kendi aralarnda tek bir döngüde birle³tirilebilirler. Örnek 11'da kullancnn girdi§i direnç de§erleri toplama eklendikten hemen sonra yitiriliyorlard. Oysa bu örnekte ö§renci notlarnn birinci döngünün çk³nda unutulmamas gerekir, çünkü ikinci döngüde de bunlar gerekecektir. Yani bu notlarn bir yerde tutulmas gerekir. Ayn tipten çok sayda eleman bulunan de§i³kenler için en uygun yapnn diziler oldu§u Bölüm 1.1.3'de görülmü³tü. Örne§imizde de ö§renci notlar bir dizi olarak temsil edilmektedir. 5.1 Tek Boyutlu Diziler Dizi tanmnn yazm veri_tipi dizi_ad [dizi_boyu ]; ³eklindedir. Burada dizi_ad dizi tipinden tanmlanan de§i³kenin adn, dizi_boyu bu dizide veri_tipi ise her bir elemann hangi tipten oldu§unu belirtir. kaç eleman bulundu§unu, Örnekte int score[MAXSTUDENTS]; komutu, her biri tamsay tipinden MAXSTUDENTS elemanl, score adnda bir dizi tanmlar. Bu MAXSTUDENTS * sizeof(int) sekizli yer ayrlr. dizi için bellekte birbirini izleyecek ³ekilde Di§er de§i³kenlerde oldu§u gibi, dizilere de tanm srasnda ba³langç de§eri verilebilir. Örne§in: 88 Tek Boyutlu Diziler int score[4] = { 85, 73, 91, 66 }; tanm 4 elemanl bir dizi tanmlar ve elemanlara srasyla 85, 73, 91 ve 66 de§erlerini atar. Özel bir durum olarak, bütün diziye 0 ba³langç de§eri verilmek isteniyorsa ³u komut kullanlabilir: int score[50] = { 0 }; Derleyicinin dizi için bellekte ne kadar yer ayrlaca§n bilmesi gerekir, yani derleme a³amasnda dizinin kaç elemannn olaca§ belli olmaldr. Bunun için iki yöntem kullanlabilir: açk belirtim Dizinin kaç eleman oldu§unun tanm srasnda açk olarak belirtildi§i, yuka- rda da örnekleri görülen yöntemdir. Boy olarak de§i³mez bir de§er vermek zorunludur. Örnekte snftaki ö§renci says no_students no_students de§i³keniyle gösterilmektedir, yani dizinin eleman olmas gerekli ve yeterlidir. Ancak no_students de§i³keninin de- §erinin ne olaca§ programn çal³mas srasnda belirlendi§inden derleyici bu de§eri dizi boyu olarak kullanamaz, yani int score[no_students]; ³eklinde bir dizi tanm yaplamaz. Ba³ka bir deyi³le, dizi boyu için yazlacak deyimde yalnzca saylar ve de§i³mezler yer alabilir, de§i³kenler yer alamaz. Bu durumda, dizinin kaç eleman olaca§ ba³tan bilinmiyorsa gerekebilecek en büyük eleman says boy olarak belirtilmelidir. Örnekteki MAXSTUDENTS de§i³mezi bu i³levi görmektedir. Burada belirtilen say, bir yandan gereksiz bellek kullanmna yol açabilir, di§er yandan da programn bir kstlamas haline gelir. Örnek programn yapt§ i³in açklamasn ³u ³ekilde düzeltmek gerekir: Bu program, en fazla 100 ö§rencili bir snfta, ö§renci notlarnn ortalamasn, varyansn ve standart ile mutlak sapmalarn hesaplar. örtülü belirtim Diziye ba³langç de§eri verilirse eleman saysn belirtmek zorunlulu§u yok- tur, yani int score[] = { 85, 73, 91, 66 }; tanm da dört elemanl bir tamsay dizisi tanmlar ve söylenen ba³langç de§erlerini atar. Bu durumda derleyici ba³langç de§eri olarak verilen dizideki eleman saysn sayarak boyu kendisi belirler. Dizideki eleman says ileride artmayacaksa bu yazm kullanmann bir sakncas yoktur, ancak artmas olasl§ varsa yine gerekebilecek en büyük eleman saysnn dizi tanmnda açk olarak belirtilmesi gerekir çünkü aksi durumda sonradan gelen elemanlar için yer ayrlmam³ olur. Dizinin bir eleman üzerinde i³lem yapmak için o elemann kaçnc eleman oldu§unu belirtmek gerekir. Bu belirtim de dizi adnn yannda elemann sra numarasnn kö³eli ayraçlar içine yazlmasyla yaplr, yani score[i], score dizisinin i. eleman anlamna gelir. Bu yazm 89 Diziler dizi tanmndaki yazmla ayn olmakla birlikte anlam olarak tamamyla farkldr: tanmda kö³eli ayraçlar içine yazlan say dizinin tutabilece§i eleman saysn gösterirken burada kaçnc eleman üzerinde i³lem yapld§n gösterir. C dilinde dizilerin ilk elemannn sra numaras her zaman 0'dr; yani ilk elemann sra numaras 0, ikinci elemann sra numaras 1 olacak ³ekilde ilerler (ekil 5.2a). Bu durumda n elemanl bir dizinin son elemannn sra numaras n - 1 olur. Bu özellik nedeniyle n elemanl bir dizi üzerinde i³lem yapacak tipik bir C döngüsü for (i = 0; i < n; i++) ³eklinde ba³lar. lk elemann sra numaras 0 oldu§undan for blo§una ilk giri³te dizinin ilk eleman ile i³lem yaplr. Son i³lem de n - 1 sra numaral elemanla yaplr, döngü sayac n de§erini ald§nda döngüden çklr. Burada dizinin tanmda belirtilen boyuyla gerçekten kullanlan eleman says arasndaki ayrma dikkat edilmelidir. Örnekte tanmda belirtilen boy MAXSTUDENTS olsa da döngü 0. elemandan MAXSTUDENTS - 1. elemana kadar gitmez çünkü son no_students - 1 olacaktr: geçerli elemann sra numaras for (i = 0; i < no_students; i++) score 0 1 2 MAXSTUDENTS-1 (a) score 0 1 2 MAXSTUDENTS (b) ekil 5.2: Dizi elemanlarnn sra numaralar. Derleyici dizilerin elemanlarna eri³imde dizi snrlarnn denetimini yapmaz; yani n elemanl bir dizinin n. ya da daha sonraki elemanlarna eri³ilmeye kalklrsa hata vermez. Dizi snrlarndan ta³mamak programcnn sorumlulu§undadr. Dizi snrndan ta³acak bir sra numaras verilirse bellekte ilk elemandan ba³lanarak istenen sayda eleman kadar ilerlenip orada ne bulunursa o de§erle i³lem yaplmaya çal³lr (ekil 5.2b). Böyle bir eri³im çal³ma annda iki tür soruna yol açabilir: 1. Gelinen bellek gözü, ba³ka bir de§i³ken için ayrlm³ bir bölgeye dü³ebilir. Bu durumda, ba³ka bir de§i³kenin de§eri istenmeden de§i³tirilmi³ olur ve programn çal³mas üzerinde beklenmedik etkiler yaratabilir. 2. Eri³ilmek istenen bellek bölgesi kullancnn izni olan bölgeler d³nda bir yere dü³ebilir. Bu durumda bir bellek hatas olu³ur. 90 Tek Boyutlu Diziler Örnek 14. Tümce Tersine Çevirme Kullancnn yazd§ tümceyi tersine çevirerek ekrana çkartan bir program yazlmas isteniyor. Programn örnek bir çal³mas ekil 5.3'de verilmi³tir. Tümce: Deneme bir ... Tersi: ... rib emeneD ekil 5.3: Örnek 14 ekran çkts. Örnek 14 Tümceyi tersine çeviren program. #include #include #include #include <iostream> <stdlib.h> <stdio.h> <string.h> // // // // cin,cout,endl EXIT_SUCCESS gets strlen using namespace std; #define MAXLENGTH 80 int main(void) { char sentence[MAXLENGTH]; int len, i; char tmp; } cout << "Tümce: "; gets(sentence); len = strlen(sentence); for (i = 0; i < len / 2; i++) { tmp = sentence[i]; sentence[i] = sentence[len - 1 - i]; sentence[len - 1 - i] = tmp; } cout << "Tersi: " << sentence << endl; return EXIT_SUCCESS; Örnek program, ba³tan ve sondan ayn srada olan simgelerin yerlerinin takas edilmesi algoritmasn kullanr. Yani ilk simgeyle son simge, ikinci simgeyle sondan bir önceki simge v.b. takas edilir. Bu algoritmann do§ru çal³mas için takasn katarn ortasna kadar sürmesi ve katar ortasn geçmemesi gerekir. (Neden?) 91 Diziler 5.2 Katarlar C dilinde katarlar birer simge dizisi olarak de§erlendirilir ve sonlarna konan '\0' simgesiyle sonlandrlrlar. Bu nedenle katar için bellekte ayrlmas gereken yer, katarn içerdi§i simge saysnn bir fazlasdr. Örnekteki char sentence[MAXLENGTH]; tanm, her biri simge tipinden, 80 elemanl, sentence adnda bir katar olu³turur. Bu eleman- lardan biri '\0' simgesi için kullanlaca§ndan kullancnn yazaca§ tümce en fazla 79 simge uzunlu§unda olabilir. Katar tipinden bir de§i³kenin tanmlanmas srasnda çift trnaklar içinde ba³langç de§eri belirtilebilir. Tanmlanan boyun katar için gereken yeri ayrmasna dikkat edilmelidir. stenirse boyut belirtilmeyebilir; bu durumda derleyici gerekli yeri kendisi ayrr. A³a§daki iki tanm ayn i³i görürler (ekil 5.4a): char sentence[15] = Deneme bir ...; char sentence[] = Deneme bir ...; sentence ’D’ ’e’ ’n’ ’e’ ’m’ ’e’ ’ ’ ’b’ ’i’ ’r’ ’ ’ ’.’ ’.’ ’.’ ’\0’ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 (a) sentence ’D’ ’e’ ’n’ ....... ’.’ ’.’ ’.’ ’\0’ 0 1 2 11 12 13 14 ........ 15 79 80 (b) ekil 5.4: Katarlara ba³langç de§eri atanmas. Tam gerekti§i kadar yer ayrmak riskli bir davran³tr. Programn içinde katarn uzamas sözkonusu olabilecekse gerekebilecek maksimum alan gözönüne alnmal ve tanm srasnda bu boy belirtilmelidir. char sentence[MAXLENGTH] = Deneme bir ...; komutu MAXLENGTH simgelik yer ayrr ancak yalnzca ilk 15 simgeyi doldurur (ekil 5.4b). Katarlarn elemanlarna dizilerde oldu§u gibi teker teker eri³ilebilir. Dizilerde oldu§u gibi, ilk elemann, yani katarn ilk simgesinin sra numaras 0 olacaktr. Son elemann sra numaras da ayrlan yerin bir eksi§idir. Yukardaki örnekte ' ', sentence[13] eleman '.', sentence[14] sentence[0] eleman 'D', sentence[6] eleman eleman '\0' de§erlerini alrlar. 92 Katar Kitapl§ cout birimi yardmyla çktya gönderilmelerinde herhangi bir cin ile girdi a³amasnda sorun çkabilir. Kullancnn yazd§ katarda bo³luk simgesi varsa, cin birimi birden fazla de§i³kenin girildi§ini dü³ünerek yalnzca ilk bo³lu§a kadar olan bölümü de§i³kene aktaracaktr. Örnekte bu amaçla katarn girdi i³lemi gets kitaplk Katar tipinden de§i³kenlerin sorun olmazken, fonksiyonuyla gerçekle³tirilmi³tir. 1 Bu komutun yerine cin > > sentence; komutu kullanlm³ olsayd programn çal³mas ekil 5.5'de görüldü§ü gibi olurdu. Tümce: Deneme bir ... Tersi: emeneD ekil 5.5: Örnek 14 hatal ekran çkts. 5.3 Katar Kitapl§ Katarlar birer dizi olduklarndan katarlar arasnda atama yapmak ya da katarlar kar³la³trmak için katar kitapl§ndaki fonksiyonlarn kullanlmas gerekir. Örnek programda, katarn uzunlu§unu belirlemek üzere bu kitaplktaki strlen fonksiyonundan yararlanlm³tr. Katar tipinden iki de§i³kenin birbirine atanmas ya da kar³la³trlmas i³lemleri standart i³leçler kullanlrsa beklenmedik sonuçlar do§urabilir. Ba³ka bir deyi³le, atama için str1 = str2; ya da kar³la³trma için if (str1 == str2) gibi yaplar kullanlmaz. 2 Katarlar üzerinde skça kullanlan temel i³lemler için bir katar kitapl§ tanmlanm³tr. Bu fonksiyonlarn kullanlabilmesi için programlarn ba³nda string.h ba³lk dosyasnn alnmas gerekir. Katar kitapl§nn en sk kullanlan fonksiyonlar Tablo 5.1'de verilmi³tir. Katar uzunlu§u fonksiyonu sondaki '\0' simgesini gözönüne almaz. • strlen(computer) → 8 1 Güvenlik nedenleriyle gets kitaplk fonksiyonunun kullanlmas tehlikelidir. Bu komutun yerine fonksiyonunun kullanlmas önerilir (bkz. Bölüm 8). 2 Daha ayrntl açklama için bkz. Bölüm .7.3. fgets 93 Diziler Ad ³levi strlen(s) strcopy(dest,src) strncpy(dest,src,n) strcmp(s1,s2) strncmp(s1,s2,n) strcat(dest,src) strncat(dest,src,n) katar uzunlu§u katar kopyalama katar kar³la³trma katar biti³tirme Tablo 5.1: Katar kitapl§ fonksiyonlar. Katar kopyalama fonksiyonlar ikinci giri³ parametresi olan katar, birinci giri³ parametresi olan katarn üstüne yazarlar. Biti³tirme fonksiyonlarysa ikinci giri³ parametresi olan katar, birinci giri³ parametresi olan katarn ardna eklerler. Her iki fonksiyon grubu da sonuç katarnn sonuna konmas gereken '\0' simgesini kendileri koyarlar. Katar i³lemi yapan fonksiyonlarn bazlarnda uzunluk denetimi yaplr, bazlarnda yaplmaz. Sözgelimi strcpy fonksiyonu src dest katarnn de§erini fonksiyonu da ayn i³levi görür, ancak en fazla katarnn üstüne yazarken, strncpy n simgeyi kopyalar. Güvenlik açsndan uzunluk 3 denetimi yapan fonksiyonlarn kullanlmas önerilir. Katar kar³la³trma fonksiyonlar giri³ parametresi olan katarlar arasnda ngilizce dilinin kurallarna göre sözlük sras kar³la³trmas yaparlar. ki katar e³itse 0, birinci katar ikinciden önce geliyorsa -1, sonra geliyorsa 1 de§erini döndürürler. • strcmp(abc, ad) → -1 • strcmp(abcd, abc) → 1 • strncmp(abcd, abcde, 4) → 0 Kopyalama ve biti³tirme fonksiyonlarnda dikkat edilmesi gereken bir nokta, hedef katarn yeterli uzunlukta olmasnn sa§lanmasdr. Örne§in, a³a§daki program parças hataya yol açabilir: char author1[] = Brian, author2[] = Dennis; ... strcpy(author1, author2); author1 katarna 6 simgelik, author2 katarnaysa 7 simgelik yer ayracaktr. Daha author1 katarnn üstüne author2 katar yazlmaya kalkld§nda author1 katarnda Derleyici sonra yeterli yer olmad§ için bu de§i³kenin snrlarndan ta³lr. Benzer ³ekilde, biti³tirme i³lemlerinde de hedef katar için iki asl katarn toplam uzunluklarn tutmaya yetecek kadar yer ayrlm³ olmaldr. 3 Uzunluk denetimi yapmayan katar fonksiyonlar tampon ta³rma ad verilen saldrlara yol açan kaynaklar arasnda en büyük yeri tutar. 94 Çok Boyutlu Diziler Uygulama: Tek Boyutlu Diziler Örnek 15. Polinom Hesab p(x) = an xn + an−1 xn−1 + · · · + a1 x + a0 ³eklinde yazlan n. dereceden bir polinomda verilen bir n(n+1) adet çarpma ve 2 n x de§eri için p(x)'in hesaplanmas adet toplama i³lemi gerektirir. çiçe çarpma ve toplama yöntemiyle bu say azaltlabilir. Polinomu ³u ³ekilde yeniden yazalm: p(x) = (((an x + an−1 )x + an−2 )x + · · · + a1 )x + a0 b de§eri, ba³langçta b = an ve i. admda b = bx+an−i olacak ³ekilde hesaplanarek a0 katsaysnn da toplanmasyla elde edilecek b de§eri hesaplanmak istenen p(x) de§eri Yaplmas gereken i³lem says da n çarpma ve n toplamaya iner. O halde bir gidilirse olur. • Çkts verilen program kullanarak p(x) = 13x7 − 9x6 + 12x4 − 4x3 + 3x + 5 polinomunun p(4), p(2.5) ve p(19) de§erlerini hesaplatn. Örnek 16. Matris Çarpm Bu bölümde üzerinde çal³lacak program, boyutlar ve elemanlar kullancdan alnan iki matrisi çarparak sonucu ekrana çkartr. Programn örnek bir çal³masnn ekran çkts ekil 5.6'da verilmi³tir. 5.4 Çok Boyutlu Diziler Çok boyutlu bir dizi tanmlanmasnda her boyut ayr bir kö³eli ayraç çifti içinde belirtilir. Örnekteki int left[MAXSIZE][MAXSIZE]; komutu, 30 satrl ve 30 sütunlu bir matris tanmlar. Bu matrisin, her biri birer tamsay olan, 30*30=900 eleman olacaktr, yani bellekte 900 tamsay tutacak kadar yer ayrlmasna neden olur. Daha çok boyutu olan bir dizi tanmlanmak istenseydi boyutlar yanyana sürdürülebilirdi: int m[30][20][7][12]; 95 Diziler Örnek 15 Polinom de§eri hesaplayan fonksiyon. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; #define MAXDEGREE 50 int main(void) { float a[MAXDEGREE]; float x, b; int n, i; char response = 'E'; cout << "Polinomun derecesi: "; cin >> n; cout << "Katsaylar: " << endl; for (i = n; i >= 0; i--) { cout << "a" << i << ": "; cin >> a[i]; } while (true) { cout << "x: "; cin >> x; b = a[n]; for (i = n - 1; i >= 0; i--) b = b * x + a[i]; cout << "p(x): " << b << endl; cout << "Devam etmek istiyor musunuz (E/H)? "; cin >> response; if ((response == 'H') || (response == 'h')) break; } } return EXIT_SUCCESS; 96 Çok Boyutlu Diziler Sol matrisin satr says: 5 Sol matrisin sütun says: 3 Sa§ matrisin sütun says: 4 Sol matris: [1,1]: 2 [1,2]: 7 [1,3]: -1 [2,1]: 3 [2,2]: 5 [2,3]: 2 [3,1]: 0 [3,2]: 4 [3,3]: 1 [4,1]: 9 [4,2]: 0 [4,3]: -3 [5,1]: 4 [5,2]: 7 [5,3]: 2 Sa§ matris: [1,1]: 0 [1,2]: 5 [1,3]: 2 [1,4]: -4 [2,1]: 1 [2,2]: 7 [2,3]: 3 [2,4]: 2 [3,1]: 5 [3,2]: 2 [3,3]: 0 [3,4]: -1 Çarpm sonucu: 2 57 25 7 15 54 21 -4 9 30 12 7 -15 39 18 -33 17 73 29 -4 ekil 5.6: Örnek 16 ekran çkts. 97 Diziler Örnek 16 ki matrisi çarpan program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; #define MAXSIZE 30 int main(void) { int left[MAXSIZE][MAXSIZE], right[MAXSIZE][MAXSIZE]; int product[MAXSIZE][MAXSIZE] = { 0 }; int rl, cl, cr; int &rr = cl; int i, j, k; cout << "Sol matrisin satr says: "; cin >> rl; cout << "Sol matrisin sütun says: "; cin >> cl; cout << "Sa§ matrisin sütun says: "; cin >> cr; cout << "Sol matris: " << endl; for (i = 0; i < rl; i++) { for (j = 0; j < cl; j++) { cout << " [" << i + 1 << "," << j + 1<< "]: "; cin >> left[i][j]; } } cout << "Sa§ matris: " << endl; for (j = 0; j < rr; j++) { for (k = 0; k < cr; k++) { cout << " [" << j + 1 << "," << k + 1 << "]: "; cin >> right[j][k]; } } for (i = 0; i < rl; i++) { for (j = 0; j < cr; j++) { for (k = 0; k < cl; k++) product[i][j] = product[i][j] + left[i][k] * right[k][j]; } } cout << "Çarpm sonucu:" << endl; for (i = 0; i < rl; i++) { for (k = 0; k < cr; k++) cout << "\t" << product[i][k]; cout << endl; } 98 Ba³vurular Bu i³lem sonucunda da bellekte 30*20*7*12=50400 tamsay tutacak kadar yer ayrlr. Tek boyutlu dizilerde oldu§u gibi, çok boyutlu dizilerde de ba³langç de§eri verilebilir. Bunun için her bir boyutun kendi içinde süslü ayraçlar içine alnmas gerekir: int m[2][3] = { { 1, 2, 1 }, { 3, 5, 1 } }; " tanm m= 1 2 1 3 5 1 # matrisini olu³turur. Tek boyutlu dizilerdekine benzer ³ekilde { 0 } ba³langç de§eri bütün elemanlara 0 ba³langç de§erini atar. Çok boyutlu dizilerde ilki d³nda bütün boyutlarn belirtilmesi zorunludur. Sözgelimi bir isim dizisi olu³turulmak isteniyorsa char names[][] = { Dennis, Brian, Ken }; tanmlamas derleyicinin hata vermesine neden olur. Birinci boyut d³ndakiler belirtilerek yazlrsa char names[][10] = { Dennis, Brian, Ken }; her bir eleman en fazla 10 simge uzunlu§unda olabilen 3 elemanl bir katar dizisi tanmlanm³ olur. Yani derleyici isim dizisinin eleman saysn sayar ancak belirtilen ba³langç katarlarnn uzunluklarn hesaplamaya çal³maz. Yine de belirtilen uzunluktan daha uzun bir ba³langç katar yazlrsa (diyelim 15 uzunluklu) derleyici bir hata üretebilir. 5.5 Ba³vurular 4 Örnekte sol matrisin satr Ba³vurular, ayn de§i³kene ikinci bir isim verilmesini sa§larlar. says ile sa§ matrisin sütun saylarnn ayn olmas zorunlulu§u nedeniyle bu bilgiyi tek bir cl de§i³keni tanmlanm³tr. Ancak döngülerde rr de§i³keninin de tanmlanmasnn yararl olaca§ dü³ünülerek de§i³kenle temsil etmek yeterli görülmü³ ve anla³lrl§ artrmak amacyla rr de§i³keninin cl de§i³kenine ba³vurmas sa§lanm³tr. Bu iki de§i³ken bellekte ayn gözde bulunurlar ve dolaysyla birinde yaplan de§i³iklik do§rudan do§ruya di§erini etkiler. Örnekte rr de§i³keni ba³vuru olmak yerine ikinci bir de§i³ken olarak da tanmlanabilirdi. Bu cl de§i³keni kullancdan okunduktan sonra rr = cl ³eklinde bir atamayla i³lem sür- durumda dürülebilirdi. Bu yakla³mda, iki de§i³ken birbirinden ayrlm³ olaca§ için birindeki de§i³iklik di§erini etkilemezdi, ancak programda boyut de§i³kenleri üzerinde bir de§i³iklik olmad§ için bir sorun çkmazd. Tek fark, gereksiz yere ikinci bir de§i³ken tanmlanm³ olmas olurdu. 4 Ba³vurular, C++ ile gelmi³ bir yeniliktir, C dilinde yoktur. 99 Diziler Uygulama: Matrisler Örnek 17. Gauss Eliminasyon Yöntemi ax = b ³eklinde yazlan n bilinmeyenli bir lineer denklem takmnda a katsay matrisini, b de§i³mezler vektörünü ve x çözüm vektörünü gösterir. Bu denklem takmnn çözümü iki a³amaldr: 1. a matrisi baz dönü³ümlerle bir üçgen matris haline getirilir. Bunun için önce sistemin i1 i = 2, 3, . . . , n. denklemlerinden x1 yok edilir (birinci denklem aa11 ile çarplp i. denklemden çkarlr). Benzer ³ekilde, i = 3, 4, . . . , n. denklemlerden x2 yok edilerek devam edilir. Birinci denklemin birinci eleman olan a11 'e pivot ad verilir ve x1 yok edilip ikinci denkleme geçildi§inde a22 eleman pivot olur. Yöntemin çal³abilmesi için bütün pivotlarn sfrdan farkl olmas gerekti§i açktr. 2. xn n. denklemden do§rudan hesaplanr. Bu de§er n − 1. denklemde yerine koxn−1 bulunur ve böylece geriye do§ru yerine koyma i³lemleriyle bütün bilinmeyen de§eri nursa de§erler hesaplanabilir. Denklem takm ³u ³ekilde verilmi³ olsun: x1 + x2 = 3.5 x1 − x2 + 5x3 = 11 2x1 − x2 + x3 = 3.3 a matrisi ve b vektörünün de§erlerini adm adm izlersek: ba³langçta: 1 1 0 3.5 a = 1 −1 5 b = 11 2 −1 1 3.3 x1 'in yok edilmesinden sonra: x2 'nin yok edilmesinden sonra: Son denklemden 7.5 1 1 0 3.5 a = 0 −2 5 b = 7.5 0 −3 1 −3.7 1 1 0 3.5 5 b = 7.5 a = 0 −2 0 0 −6.5 −14.95 x3 = 2.3 elde edilir. Bu de§er ikinci denklemde yerine konursa:−2x2 + 5x3 = x2 = 2 ve bu de§er birinci denklemde yerine konursa x1 + x2 = 3.5 denkle- denkleminden minden x1 = 1.5 bulunur. Gauss eliminasyon yöntemini kullanarak Örnek 17'da verilmi³tir. n bilinmeyenli bir denklem takmn çözen program 100 Ba³vurular Örnek 17 Gauss eliminasyon yöntemiyle denklem takm çözen program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; #define MAXEQUATIONS 5 int main(void) { float a[MAXEQUATIONS][MAXEQUATIONS], b[MAXEQUATIONS]; float x[MAXEQUATIONS]; float pivot, f; int n; int i, j, k; cout << "Denklem says: "; cin >> n; for (i = 0; i < n; i++) { cout << "Denklem " << i + 1 << ": "; for (j = 0; j < n; j++) { cin >> a[i][j]; } cin >> b[i]; } for (j = 0; j < n - 1; j++) { pivot = a[j][j]; for (i = j + 1; i < n; i++) { f = a[i][j] / pivot; for (k = j + 1; k < n; k++) a[i][k] = a[i][k] - f * a[j][k]; b[i] = b[i] - f * b[j]; } } x[n-1] = b[n-1] / a[n-1][n-1]; for (i = n - 2; i >= 0; i--) { f = b[i]; for (k = i + 1; k < n; k++) f = f - a[i][k] * x[k]; x[i] = f / a[i][i]; } for (i = 0; i < n; i++) cout << "x" << i + 1 << ": " << x[i] << endl; } return EXIT_SUCCESS; 101 Diziler Sorular 1. Kullancnn girdi§i bir tümcedeki sözcük saysn sayan bir program yazn. Sözcüklerin önünde ve arkasnda bo³luk oldu§u varsaylacaktr. Ancak sözcük arasnda istendi§i sayda bo³luk olabilece§i gibi tümcenin ba³nda ve sonunda da istendi§i kadar bo³luk olabilir. Örnek olarak kullanc the world is not enough tüm- cesini girerse programn çkts 5 olacaktr. 2. Eratosthenes kalburu yöntemini kullanarak ilk 10000 say içindeki asal saylar ekrana çkartan bir fonksiyon yazn. 3. Kullancdan alnan bir sayy yaz olarak ekrana çkartan bir program yazn. Örne§in kullanc 21355 saysn girerse program ekrana Yirmibirbinüçyüzellibe³ yazacaktr. 4. Kullancnn verdi§i sayy Roma rakamlarna çevirerek ekrana çkartan bir program yazn. Örne§in kullanc 523 saysn girerse ekrana DXXIII katar çkarlmaldr. 5. Verilen bir tarihin haftann hangi gününe geldi§ini bulan bir program yazn. Örne§in kullanc 24-09-2002 tarihini girerse ekrana Sal katar çkarlmaldr. 6. Kullancdan alnan iki tarih arasnda geçen gün saysn hesaplayan bir program yazn. 7. Kullancdan ald§ bir tarihin haftann hangi gününe geldi§ini bulan bir program yazn. Ba³vurular 102 Bölüm 6 Fonksiyonlar u ana kadar yaplan örneklerde bütün i³lemler tek bir fonksiyonda (main fonksiyonu) gerçekle³tiriliyordu. Gereken yerlerde kitaplk fonksiyonlarndan yararlanlmakla birlikte, kendi yazd§mz kod tek bir fonksiyonla snrlyd. Oysa blok yapl programlamada soyutlama kavramnn öneminden Bölüm 1.4'de söz edilmi³, i³leri alt-i³lere, alt-i³leri alt-alt-i³lere bölerek yazlan programlarn hem geli³tirme hem de bakm a³amalarnda sa§layaca§ kolaylklar görülmü³tü. Bu bölümde de programcnn kendi fonksiyonlarn nasl yazaca§n inceleyece§iz. C dilinde her i³ ya da alt-i³ bir fonksiyon tarafndan gerçeklenir. Fonksiyonlar yapacaklar i³i belirleyen giri³ parametreleri alrlar ve i³lemin sonucuna göre bir çk³ parametresi üretirler. Yani giri³ parametrelerinin says birden fazla olabilir ancak çk³ parametresi en fazla bir tanedir. imdiye kadar kullanlan kitaplk fonksiyonlarnn bazlarna parametreleri açsndan bakarsak: • sqrt: Kesirli say tipinden bir giri³ parametresi alr, kesirli say tipinden bir çk³ para- metresi üretir. • pow: kisi de kesirli say tipinden iki giri³ parametresi alr, kesirli say tipinden bir çk³ parametresi üretir. • strlen: Katar tipinden bir giri³ parametresi alr, tamsay tipinden bir çk³ parametresi üretir. • rand: Giri³ parametresi almaz, tamsay tipinden bir çk³ parametresi üretir. • srand: ³aretsiz tamsay tipinden bir giri³ parametresi alr, çk³ parametresi üretmez. Bir fonksiyonun bir alt-i³ini yaptrmak üzere ba³ka bir fonksiyonu kullanmasna fonksiyon ça§rs ad verilir. Örnek 7'da, main fonksiyonu, for blo§unun ilk komutunda rand fonksiyo- nunu ça§rmaktadr. Fonksiyon ça§rsnda üst fonksiyona ça§ran fonksiyon, alt fonksiyona da ça§rlan fonksiyon denir, yani örnekte main fonksiyonu ça§ran, rand fonksiyonuysa ça§rlan fonksiyondur. Fonksiyon ça§rsnn sona ermesinden sonra ça§ran fonksiyonda ak³ bir sonraki komutla devam eder. Ça§ran fonksiyon ça§rlan fonksiyona giri³ parametrelerini gönderir, ça§rlan fonksiyonsa üretti§i sonucu ça§ran fonksiyona döndürür. Döndürülen de§er ça§ran fonksiyonda bir de§i³kene 103 104 atanabilece§i ya da bir deyimde kullanlabilece§i gibi, do§rudan ba³ka bir fonksiyona giri³ parametresi olarak da gönderilebilir. 1 Örnekte time fonksiyonunun döndürdü§ü de§er, srand fonksiyonuna parametre olarak gönderilmi³tir: number = rand(); number = rand() % 6; srand(time(NULL)); // do§rudan atama // deyimde kullanma // ba³ka fonksiyona gönderme Çk³ parametrelerinin kullanmnda tip uyumuna dikkat edilmelidir. Sözgelimi, yonu tamsay tipinden bir de§er döndürdü§üne göre olmaldr, katar tipinden olamaz. number rand fonksi- de§i³keni de tamsay tipinden 2 Benzer ³ekilde, bir fonksiyondan gelen bir de§er kalan i³le- mine sokulacaksa bu de§erin tamsay tipinden olmasna dikkat etmek gerekir. Giri³ parametrelerinin aktarm için ça§ran fonksiyondaki parametreleri yollama ³ekliyle ça§rlan fonksiyonun parametreleri bekleme ³ekli uyumlu olmaldr. Bu uyumluluk ³u ³ekilde tanmlanabilir: 1. Ça§rlan fonksiyon kaç parametre bekliyorsa ça§ran fonksiyon o sayda parametre yollamaldr. 2. Ça§rlan fonksiyon her bir sradaki giri³ parametresinin tipinin ne olmasn bekliyorsa ça§ran fonksiyon bu tipe uyumlu bir de§er göndermelidir. Örne§in pow fonksiyonu iki tane kesirli say bekliyorsa bu fonksiyona iki tane kesirli say (ya da tamsay) de§eri yollanmaldr. Bir, üç ya da daha fazla de§er yollanmas, hiç de§er yollanmamas, yollanan iki de§erin say d³nda bir tipten (sözgelimi katar) olmas hataya yol açar. Örnek 18. Asal Çarpanlara Ayrma Kullancnn girdi§i bir saynn asal çarpanlarn ekrana döken bir program yazlmas isteniyor. Gerekli algoritmann ak³ çizene§i ekil 1.18'de, örnek bir çal³masnn ekran çkts ekil 6.1'de verilmi³tir. Programda bir saynn asal olup olmad§nn snanmasna ve asal saylarn bulunmasna gerek duyulacaktr. Soyutlama ilkesine göre bu i³lemler fonksiyonlarla gerçekle³tirilecek, ana fonksiyon, asal saylar bulan fonksiyondan srayla ald§ asal saylarn kullancnn verdi§i sayy bölüp bölmediklerini snayacaktr. Örnekte is_prime fonksiyonu kendisine gönderilen bir saynn asal olup olmad§n belirleyerek geriye asalsa do§ru, de§ilse yanl³ mantksal de§erini yollar. next_prime fonksiyonu ise kendisine gönderilen saydan daha büyük olan ilk asal sayy bularak kendisini ça§ran fonksiyona döndürür. 1 2 Aslnda bu durumlarn hepsi deyimde kullanma olarak de§erlendirilebilir. Eski C derleyicileri bu tip denetimlerde fazlasyla gev³ek davranabilmektedir. Bu durum programcnn hata yapmasna zemin hazrlar. 105 Fonksiyonlar Örnek 18 Bir sayy asal çarpanlarna ayran program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; int next_prime(int prime); int main(void) { int number, factor = 2; } cout << "Sayy yaznz: "; cin >> number; while (number > 1) { while (number % factor == 0) { cout << factor << " "; number = number / factor; } factor = next_prime(factor); } cout << endl; return EXIT_SUCCESS; bool is_prime(int cand) { int count; } if (cand == 2) return true; if (cand % 2 == 0) return false; for (count = 3; count * count <= cand; count += 2) { if (cand % count == 0) return false; } return true; int next_prime(int prime) { int cand = (prime == 2) ? 3 : prime + 2; } while (!is_prime(cand)) cand += 2; return cand; 106 Fonksiyon Bildirimi ve Tanm Sayy yaznz: 6468 2 2 3 7 7 11 ekil 6.1: Örnek 18 ekran çkts. 6.1 Fonksiyon Bildirimi ve Tanm Bir fonksiyon iki bile³enden olu³ur: • Fonksiyonun ba³l§, fonksiyonun adn ve giri³/çk³ parametrelerini belirtmeye yarar. Soyutlamadaki kar³l§yla fonksiyonun NE yapt§n anlatr. Fonksiyon ba³l§nn belirtilmesi i³lemine fonksiyonun bildirimi denir ve ba³l§n sonuna bir noktal virgül konarak yaplr. Bildirim komutunun yazm ³u ³ekildedir: çk³_parametresi_tipi fonksiyon_ad (giri³_parametresi_listesi ); Örnekte next_prime fonksiyonu için yaplan int next_prime(int prime); bildirimine göre, next_prime fonksiyonu tamsay tipinden bir giri³ parametresi alr ve yine tamsay tipinden bir çk³ parametresi döndürür. Çk³ parametresi herhangi bir skalar ya da bile³ke tipten olabilir ancak dizi olamaz. Giri³ parametresi listesiyse birbirinden virgülle ayrlm³ veri_tipi de§i³ken_ad çiftleri ³eklindedir. Çk³ parametresi döndürmeyen fonksiyonlarn çk³ parametresi tipi void sakl sözcü§üyle belirtilir. Benzer ³ekilde, giri³ parametresi almayan fonksiyonlarn giri³ listesi parametresine de void yazlr. Bu bilgileri gözönünde bulundurarsak, kulland§- mz baz kitaplk fonksiyonlarnn sistemde ³öyle bildirilmi³ olmalar gerekti§i görülebilir: double sqrt(double x); double pow(double x, double y); int rand(void); void srand(unsigned int seed); Giri³ parametresi listesindeki de§i³kenlerin yazm de§i³ken tanm yazmna benzer ancak ayn tipten de§i³kenler gruplanamaz. Sözgelimi a³a§daki bildirim hataldr: double pow(double x, y); Fonksiyon bildirimi, derleyiciye giri³ parametresi listesi tipinden de§i³kenler alan ve çk³ parametresi tipinden de§er üreten belirtilen isimde bir fonksiyon oldu§ununun bildirilmesini sa§lar. Böylelikle derleyici bu fonksiyon ça§rsn gördü§ü yerde parametrelerin uyumlu olup olmadklarn denetleyebilir. Çal³ma annda fonksiyon ça§rsna gelindi§inde uygun yere gidilmesini sa§layacak ba§lantlar kurmak derleyicinin de§il ba§laycnn görevidir. 107 Fonksiyonlar • Fonksiyonun gövdesi, fonksiyonun yapaca§ i³leri belirten bloktan olu³ur, yani fonksiyonun i³ini NASIL yapt§n anlatr. Bir fonksiyonun bütününün, yani giri³/çk³ parametrelerinin yansra gövdesinin de belirtildi§i yere fonksiyonun tanm denir. Örnekte is_prime fonksiyonu, main fonksiyonunun bitiminden sonra, next_prime fonksiyonu da is_prime fonksiyonunun bitiminden sonra tanmlanm³tr. return komutu yardmyla döndüreturn sakl sözcü§ünden sonra yazlan deyim fonksiyonun ba³l§nda belirtilen veri tipine uygun tipten bir de§er üretmelidir. Örnekte is_prime fonksiyonu mantksal tipten tanmlanm³tr ve fonksiyonun çe³itli noktalarnda false ya da true de§erlerini döndürmektedir. next_prime fonksiyonuysa tamsay tipinden tanmlanm³tr ve döndürdü§ü de§eri tutan de§i³ken de (cand) tamsay tipindendir. Ça§rlan fonksiyon üretti§i de§eri ça§ran fonksiyona rür. Bir fonksiyon ça§rsnn yaplabilmesi için ça§rlan fonksiyonun ya bildirimi ya da tanm ça- next_prime fonksiyonunu, next_prime fonksiyonu da is_prime fonksiyonunu ça§rr. Birinci ça§r, next_prime fonksiyonunun bildirimi main fonksiyonunun tanm ba³lamadan yapld§ndan ba³arl olur. kinci ça§rysa is_prime fonksiyonu next_prime fonksiyonundan önce tanmland§ndan ba³arl olur. Ancak örne§in main fonksiyonu is_prime fonksiyonunu ça§ramaz çünkü öncesinde is_prime §ran fonksiyondan önce yaplmaldr. Örnekte main fonksiyonu fonksiyonunun ne tanm ne de bildirimi vardr. Kendi yazd§nz fonksiyonlarda oldu§u gibi, kitaplk fonksiyonlarn da ça§rabilmeniz için bu fonksiyonlarn bildirimlerinin daha önceden yaplm³ olmas gerekir. Bu bildirimler kulland§nz derleyiciyle gelen ba³lk dosyalarnda yer alr; bir kitaplk fonksiyonunu kulland§nzda ba³lk dosyasn belirtmeniz zorunlulu§u da buradan do§ar. 6.2 Parametre Aktarm Giri³ parametrelerinin aktarmnda fonksiyon ça§rsnda belirtilen parametre listesiyle fonksiyonun ba³l§nda belirtilen liste uyumlu olmaldr. Ça§rda yazlan her de§er, ça§rlan fonksiyonun ba³l§nda ayn srada yazlm³ de§i³kene atanr. Bu parametre aktarm yöntemine de§er aktarm ad verilir. Örnekteki birinci fonksiyon ça§rsnda: factor = next_prime(factor); main fonksiyonundaki factor de§i³keninin de§eri next_prime fonksiyonunun giri³ parametresi olan prime de§i³kenine atanr. Dönü³te de next_prime fonksiyonunun return komutuyla geri yollad§ cand de§i³keninin de§eri main fonksiyonundaki factor de§i³kenine atanr. Fonksiyonun bir döngü içinde ça§rld§ gözönüne alnarak, parametre olarak ilk ça§rda 2 de§erinin gönderilece§i ve 3 de§erinin dönece§i, ikinci ça§rda 3 de§erinin gönderilece§i ve 5 de§erinin dönece§i, ileriki ça§rlarda 5, 7, 11, ... de§erlerinin gönderilece§i görülebilir. Benzer ³ekilde, ikinci fonksiyon ça§rsnda next_prime fonksiyonundaki cand cand de§i³kenine atanr. de§i³keninin de§eri is_prime fonksiyonunun giri³ parametresi olan Tipi uygun oldu§u sürece parametre olarak herhangi bir deyim belirtilebilir. Sözgelimi a³a§daki ça§rlar geçerlidir: 108 Yerel De§i³kenler number main 6468 factor 2 prime cand cand count next_prime is_prime ekil 6.2: Parametre aktarm örne§i - 1. adm. is_prime(13) is_prime(cand + 1) Benzer ³ekilde, geri döndürülecek de§er için uyumlu tipten de§er üreten bir deyim yazlabilir: return cand + 2; 6.3 Yerel De§i³kenler Parametre aktarm anlatlrken main fonksiyonundaki factor de§i³keninin de§eri next_prime prime de§i³kenine , next_prime fonksiyonundaki cand is_prime fonksiyonunun giri³ parametresi olan cand de§i³kenine gibi fonksiyonunun giri³ parametresi olan de§i³keninin de§eri sözler kullanld. Buradan da görülebilece§i gibi, de§i³kenler içinde tanmlandklar fonksiyon ile birlikte de§erlendirilirler ve yalnzca bu fonksiyon içinde geçerlidirler. daki factor de§i³keni ile next_prime fonksiyonundaki prime main fonksiyonun- de§i³keni farkl de§i³kenlerdir, bellekte farkl yerlerde bulunurlar; dolaysyla, birinde yaplan de§i³iklik di§erini etkilemez. De§i³ken adlarnn ayn olmasnn da bir önemi yoktur: de§i³keniyle is_prime fonksiyonundaki cand next_prime fonksiyonundaki cand de§i³keni de farkl de§i³kenlerdir. main fonksiyonunda factor de§i³kenine ba³next_prime fonksiyonunun prime adl giri³ parametre de§i³kenine aktarlr (ekil 6.2). next_prime fonksiyonunda cand de§i³keni 3 de§erini alr ve bu de§er asal olup olunmad§nn belirlenmesi için is_prime fonksiyonunun cand adl giri³ parametre de§i³kenine aktarlr (ekil 6.3). is_prime fonksiyonunda count de§i³keni 3 de§erini alr ancak döngü ko³ulu ba³tan sa§lanmad§ndan döngüden çklarak next_prime fonksiyonuna true de§eri döndürülür (ekil 6.4). Bu de§er !is_prime(cand) ko³ul deyiminin yanl³ sonucunu üretmesine neden oldu§undan döngüden çklr ve main fonksiyonuna cand de§i³keninin o anki de§eri, yani 3 döndürülür. Bu de§er de main fonksiyonundaki factor de§i³kenine atanr Örnekte ilk fonksiyon ça§rlar ³öyle gerçekle³ir. langçta atanm³ olan 2 de§eri (ekil 6.5) Fonksiyonun parametre olarak ald§ ya da fonksiyon gövdesinde tanmlanan de§i³kenlere o fonksiyonun yerel de§i³kenleri ad verilir ve bunlarn tanm bölgesi tanmlandklar fonksiyonla 109 Fonksiyonlar number main factor 6468 prime next_prime 2 cand 2 3 cand count is_prime ekil 6.3: Parametre aktarm örne§i - 2. adm. number main factor 6468 2 prime next_prime cand 2 3 cand count 3 3 !is_prime(cand) true is_prime ekil 6.4: Parametre aktarm örne§i - 3. adm. number main 6468 prime next_prime is_prime factor 2 cand 2 3 cand count 3 3 ekil 6.5: Parametre aktarm örne§i - 4. adm. 110 Genel De§i³kenler snrlanr. Örnekteki bütün fonksiyonlarn iki³er (main: ve count, next_prime: prime ve cand) number ve factor, is_prime: cand yerel de§i³keni vardr. Fonksiyonun sona ermesiyle tanmlad§ de§i³kenler de geçersiz hale gelir. Ba³ka bir deyi³le, de§i³kenlere tanm bölgeleri d³nda eri³ilemez. Yani sözgelimi main fonksiyonu number ve factor d³nda kalan de§i³kenleri kullanamaz. 6.4 Genel De§i³kenler Baz durumlarda birden fazla fonksiyonun ayn de§i³keni kullanabilmeleri istenir. Bu tip de§i³kenlere genel de§i³ken ad verilir ve tanm bölgeleri bütün fonksiyonlar olarak belirlenir. Genel de§i³kenler bütün fonksiyonlarn tanmlarndan önce tanmlanrlar. DKKAT Genel de§i³kenlere örnek vermek için programda baz de§i³iklikler yaplabilir. BU DEKLKLERN SONUCUNDA OLUACAK PROGRAM Y BR PROGRAM OLMAYACAKTIR. BU ÖRNEK YALNIZCA GENEL DEKEN KULLANIMINI AÇIKLAMAK AMA- next_prime ve is_prime fonksiyonlar aslnda cand de§i³kenini parais_prime bu de§i³kenin de§erinin asal olup olmad§n belirlemek, next_prime CIYLA VERLMTR. metre olarak aktarmak yerine ortak bir bellek gözünde payla³abilirler. Bu durumda fonksiyonunun i³levi fonksiyonunun i³leviyse bu de§i³kenin de§erini kendisinden büyük ilk asal sayya ilerletmek olarak dü³ünülebilir. Benzer ³ekilde, ana fonksiyon da çarpan aday olan sayy parametre aktarmyla almak yerine ayn genel de§i³kende eri³erek ö§renebilir. De§i³iklikler sonucu olu³an program Örnek 19'de verilmi³tir. Bir fonksiyon bir genel de§i³kenle ayn isimde bir yerel de§i³ken tanmlarsa o fonksiyonun çal³mas boyunca yerel de§i³ken genel de§i³keni ezer. Diyelim is_prime fonksiyonu int count, cand; ³eklinde bir de§i³ken tanm yapm³ olsayd, genel olan yerel olan cand de§i³keni olu³urdu ve is_prime cand de§i³keninin yannda bir de fonksiyonunun içindeyken genel olan cand de§i³kenine ula³lamazd. Genel de§i³kenler parametre aktarm yerine kullanlabilecek bir yöntem olmakla birlikte programn anla³lrl§n azalttklar ve fonksiyonlar birbirlerine ba§ml kldklar için gerekmedikçe kullanlmamalar önerilir. Soyutlamann kazandrdklarndan birinin ileride bir fonksiyonda de§i³iklik yapld§ zaman bunu ça§ran fonksiyonlarn de§i³iklikten etkilenmemesi oldu§u söylenmi³ti; oysa fonksiyonlarn de§i³ken payla³rlarsa bir fonksiyonda yaplan de§i³iklikler di§er fonksiyonlar etkileyebilir. 6.5 Ba³vuru Aktarm De§er aktarm yöntemiyle parametre aktarlmas baz i³lemlerde yeterli olmaz. Sözgelimi, kendisine giri³ parametresi olarak gönderilen iki tamsay de§i³kenin de§erlerini takas eden bir fonksiyonun Örnek 20'daki gibi yazld§n dü³ünelim. Bu program çal³trld§nda ekran çkts ³u ³ekilde olur: 111 Fonksiyonlar Örnek 19 Genel de§i³ken kullanarak bir sayy asal çarpanlarna ayran program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; int cand = 2; void next_prime(void); int main(void) { int number; } cout << "Sayy yaznz: "; cin >> number; while (number > 1) { while (number % cand == 0) { cout << cand << " "; number = number / cand; } next_prime(); } cout << endl; return EXIT_SUCCESS; bool is_prime(void) { int count; } if (cand == 2) return true; if (cand % 2 == 0) return false; for (count = 3; count * count <= cand; count += 2) { if (cand % count == 0) return false; } return true; void next_prime(void) { cand = (cand == 2) ? 3 : cand + 2; while (!is_prime()) cand += 2; } 112 Ba³vuru Aktarm Örnek 20 ki sayy takas eden fonksiyon ve kullanm (hatal). #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; void swap(int x, int y) { int tmp; } tmp = x; x = y; y = tmp; int main(void) { int m = 32, n = 154; } cout << m << " " << n << endl; swap(m, n); cout << m << " " << n << endl; return EXIT_SUCCESS; 113 Fonksiyonlar x swap y 32 m main tmp 154 xxx n 32 154 (a) x swap y 154 m main tmp 32 xxx n 32 154 (b) ekil 6.6: Takas fonksiyonunda parametre aktarm. 32 154 32 154 main fonksiyonundaki m de§i³keninin de§eri swap fonksiyonundaki x de§i³kenine, n de§i³keninin de§eri de y de§i³kenine aktarlr (ekil 6.6a). swap fonksiyonunda x ve y de§i³kenlerinin de§erleri takas edilir ancak ça§ran fonksiyondaki m ve n de§i³kenleri bu takastan etkilenmezler ve fonksiyon ça§rsndan dönüldü§ünde Programn neden istendi§i gibi çal³mad§n inceleyelim: eski de§erlerini koruyor olurlar (ekil 6.6b). Bu sorunun çözümü için yaplmas gereken, ça§rlan fonksiyonda girdi parametrelerini ba³vuru tipinden tanmlamaktr (bkz. Bölüm 5.5). Böylelikle ça§rlan fonksiyonun girdi parametresi, ça§ran fonksiyonun gönderdi§i parametreye verilmi³ ikinci bir isim haline gelir ve üstünde yaplan de§i³iklikler ça§ran fonksiyondaki de§i³keni do§rudan etkiler: Bu parametre aktarm yöntemine ba³vuru aktarm ad verilir. Bir parametrenin ba³vuru olarak aktarld§n göstermek üzere yaplmas gereken tek ³ey ça§rlan fonksiyondaki girdi parametre de§i³keninin adnn ba³na & simgesi koymaktr. Yani örnekteki tek de§i³iklik satrnn ³u ³ekle getirilmesi olacaktr: void swap(int &x, int &y) Uygulama: Fonksiyonlar Örnek 21. Kombinasyon Hesab Bu örnekte Cnm = m! n!(m−n)! de§erinin hesaplanmas istenmektedir. swap fonksiyonunun ba³lk 114 Ba³vuru Aktarm Örnek 21 Kombinasyon hesab (yava³). #include <iostream.h> #include <stdlib.h> // cout,cin // EXIT_SUCCESS using namespace std; int combin(int a, int b); int fact(int x); int main(void) { int n, r; } cout << "n ve r de§erlerini yaznz: "; cin >> n >> r; cout << combin(n, r) << endl; return EXIT_SUCCESS; int combin(int a, int b) { int f1, f2, f3; } f1 = fact(a); f2 = fact(b); f3 = fact(a - b); return f1 / (f2 * f3); int fact(int x) { int fx = 1; int i; } for (i = 2; i <= x; i++) fx = fx * i; return fx; 115 Fonksiyonlar Örnek 22 Kombinasyon hesab (hzl). #include <iostream.h> #include <stdlib.h> // cout,cin // EXIT_SUCCESS using namespace std; int combin(int a, int b); int main(void) { int n, r; } cout << "n ve r de?erlerini yaz?n?z: "; cin >> n >> r; cout << combin(n, r) << endl; return EXIT_SUCCESS; int combin(int a, int b) { int f1 = 1, f2, f3; int first = b, second = a - b; int i; if (b > a - b) { first = a - b; second = b; } } for (i = 2; i <= first; i++) f1 = f1 * i; f2 = f1; for (i = first + 1; i <= second; i++) f2 = f2 * i; f3 = f2; for (i = second + 1; i <= a; i++) f3 = f3 * i; return f1 / (f2 * f3); 116 Giri³ Parametreleri Üzerinden De§er Döndürme Örnek 23. En Büyük Ortak Bölen Bulma Bölüm 1.4'de anlatlan algoritmalar kullanarak iki saynn en büyük ortak bölenini hesaplayan bir program yazlmas isteniyor. Bunun için Örnek 18'de bir sayy asal çarpanlarna ayran programn benzeri bir fonksiyon (factorize) olarak yazlacak ve bu fonksiyon kendisine parametre olarak gönderilen saynn asal çarpanlarn bir dizide olu³turacaktr. Fonksiyon yine ayn örnekte yazlm³ olan next_prime ve is_prime fonksiyonlarn hiçbir de§i³iklik olma- dan kullanacaktr. Asal çarpan dizilerinden en büyük ortak bölenin asal çarpanlarn bulmak üzere gcd_factors fonksiyonu kullanlacak, bu fonksiyonun olu³turdu§u çarpanlar dizisinden en büyük ortak böleni ana fonksiyon kendisi hesaplayacaktr. Örnek 23 ki saynn en büyük ortak bölenini bulan program (ana fonksiyon). int main(void) { int number1, number2; factor_t factors1[MAXFACTOR], factors2[MAXFACTOR], factors3[MAXFACTOR]; int n1, n2, n3; long int gcd = 1L; int i; cout << "Saylar yaznz: "; cin >> number1 >> number2; factorize(number1, factors1, n1); factorize(number2, factors2, n2); gcd_factors(factors1, n1, factors2, n2, for (i = 0; i < n3; i++) gcd = gcd * (long int) pow((double) (double) cout << "En büyük ortak bölen: " << gcd return EXIT_SUCCESS; } 6.6 factors3, n3); factors3[i].base, factors3[i].power); << endl; Giri³ Parametreleri Üzerinden De§er Döndürme Asal çarpanlara ayrma i³ini yapan factorize fonksiyonunun giri³ parametresinin çarpan- larna ayrlacak say, çk³ parametresinin de çarpanlar dizisi olmas gerekti§i görülmü³tü. Burada iki sorunla kar³la³lr: 1. C dilinde çk³ parametresi olarak geriye dizi döndürülemez. 2. Dizinin elemanlarn döndürmek yeterli de§ildir, dizide kaç tane geçerli eleman oldu§unu da döndürmek gerekir. Oysa C fonksiyonlar ça§ran fonksiyona birden fazla de§er döndüremez. 117 Fonksiyonlar Birden fazla de§erin döndürülmesi gerekti§i durumlarda bu de§erler giri³ parametrelerinde de§i³iklik yapma yöntemiyle ana fonksiyona aktarlabilir. Buna göre, factorize fonksiyonunun i³levi ³öyle açklanabilir: Birinci giri³ parametresi olarak gönderilen saynn çarpanlarn ikinci giri³ parametresi olan dizide olu³turur ve bu dizinin kaç eleman oldu§unu üçüncü giri³ parametresine yazar. Geriye bir de§er döndürmez. Buna göre koddaki factorize(number1, factors1, n1); fonksiyon ça§rsnn i³levi: number1 saysn asal çarpanlarna ayr, sonuçlar factors1 dizisinde olu³tur ve bu dizideki geçerli eleman saysn n1 de§i³kenine yaz. 6.7 Dizilerin Fonksiyonlara Aktarlmas Bir giri³ parametresinin dizi tipinden oldu§unun belirtilmesi için fonksiyon ba³l§nda de§i³ken adnn ardna boyut belirtmeden kö³eli ayraçlar konur. Dizi de§i³kenlerinin giri³ parametresi olarak aktarmlarnda en önemli özellik, aksi belirtilmedikçe dizi elemanlarnn de§i³tirilebilir olmalardr. Yani dizi elemanlar de§i³tirilmek isteniyorsa dizi de§i³keninin ad oldu§u gibi yazlr, ba³vuru aktarm kullanlmaz (de§i³ken adnn ba³na & i³areti konmaz). 3 Aksine, dizi elemanlarnn de§er de§i³tirmemesi isteniyorsa önlem almak gerekir. Bu amaçla giri³ parametresi tanm const sakl sözcü§üyle ba³latlr. Örnekte sonuçlarn olu³tu§u factors1 dizisi ve n1 de§i³keninin ana fonksiyonun yerel de- §i³kenleri oldu§una dikkat edilmelidir. Fonksiyon ça§rsndan önce bu de§i³kenlerde herhangi anlaml bir de§er yer almazken ça§rdan dönüldükten sonra anlaml de§erlerle doldurulmu³ olmalar beklenmektedir. Bu nedenle, yukarda belirtilen yazm kurallarna göre, factorize fonksiyonunun ba³l§ ³öyle olmaldr: void factorize(int number, factor_t factors[], int &n) biçimindedir. Bu fonksiyonun tam çkts Örnek 24'de verilmi³tir. Ortak çarpanlar bulan fonksiyon ise iki tane asal çarpan dizisi alacak ve ortak çarpanlardan bir asal çarpan dizisi olu³turacaktr. Dizilerin eleman saylar da parametre olarak gönderilmesi gerekti§i için her çarpan dizisi, bir eleman dizisi ve bir eleman says ile gösterilecektir. Buna göre 3 gcd_factors fonksiyonunun i³levi ³u ³ekilde yazlabilir: Bunun nedeni Bölüm 7'de açklanacaktr. Dizilerin Fonksiyonlara Aktarlmas Örnek 24 118 ki saynn en büyük ortak bölenini bulan program (asal çarpanlara ayrma fonk- siyonu). void factorize(int x, factor_t factors[], int &n) { int factor = 2; } n = 0; while (x > 1) { if (x % factor == 0) { factors[n].base = factor; factors[n].power = 0; while (x % factor == 0) { factors[n].power++; x = x / factor; } n++; } factor = next_prime(factor); } Birinci parametrede verilen çarpanlar içeren ve ikinci parametrede verilen sayda eleman olan çarpan dizisiyle, üçüncü parametrede verilen çarpanlar içeren ve dördüncü parametrede verilen sayda eleman olan çarpan dizilerinden ortak çarpanlar bulur. Bu dizinin elemanlarn be³inci parametrede verilen dizide olu³turur ve bu dizinin eleman saysn altnc parametreye yazar. Geriye bir de§er döndürmez. Bu fonksiyonda ilk dört parametre gerçek anlamda giri³ parametresiyken son iki parametre aslnda çkt parametresi olup kstlamalar nedeniyle giri³ parametresi olarak gönderilen de§erlerdir Yani ilk dört parametre de§i³meyecek, son iki parametre de§i³ecektir. Buna göre gcd_factors fonksiyonunun ba³l§ ³öyle olmaldr: void gcd_factors(const factor_t factors1[], int n1, const factor_t factors2[], int n2, factor_t factors[], int &n); Burada const sözcüklerinin kullanlmamas programn do§ru çal³masna etki etmez, yalnzca programcnn aslnda de§i³memesi gereken bir de§eri yanl³lkla de§i³tirmesine engel olmak için konmu³tur. Fonksiyonun tanm Örnek 25'de verilmi³tir. Uygulama: Dizilerin Fonksiyonlara Aktarlmas Bu uygulamada proler kullanm gösterilecektir (gprof ). 119 Fonksiyonlar Örnek 25 ki saynn en büyük ortak bölenini bulan program (ortak çarpanlar bulma fonk- siyonu). void gcd_factors(const factor_t factors1[], int n1, const factor_t factors2[], int n2, factor_t factors[], int &n) { int i1 = 0, i2 = 0; } n = 0; while ((i1 < n1) && (i2 < n2)) { // iki dizi de bitmedi if (factors1[i1].base < factors2[i2].base) i1++; else if (factors1[i1].base > factors2[i2].base) i2++; else { factors[n].base = factors1[i1].base; if (factors1[i1].power < factors2[i2].power) factors[n].power = factors1[i1].power; else factors[n].power = factors2[i2].power; i1++; i2++; n++; } } 120 Dizilerin Fonksiyonlara Aktarlmas Örnek 26. Newton-Raphson Yöntemiyle Polinom Kökü Bulunmas f (x) fonksiyonunun kökü, f (x) = 0 ko³ulunu sa§layan x de§eridir. Bu de§ere x f (x) fonksiyonunun x civarnda Taylor açlmnn ilk iki terimi ³öyle yazlabilir Bir dersek f (x) = f (xi ) + (x − xi )f 0 (xi ) Bu de§er 0 olmas gerekti§inden denklem f (xi ) + (x − xi )f 0 (xi ) = 0 ³ekline getirilebilir ve buradan da x = xi − yazlabilir. Bu formülde x yerine xi+1 f (xi ) f 0 (xi ) konursa, fonksiyonun kökü ard³l yerine koyma yön- temiyle hesaplanabilir. Yani her admda o admdaki konarak bir sonraki admda kullanlacak Bu yöntemin x x de§eri formüldeki xi de§erinin yerine de§eri hesaplanr. p(x) = an xn + an−1 xn−1 + · · · + a1 x + a0 ³eklinde n. dereceden bir polinoma uyguland§n varsayalm. O halde yineleme formülü xi+1 = xi − p(xi ) p0 (xi ) olacaktr. Bir polinomun hesaplanmasnn içiçe çarpma ve toplama yöntemiyle nasl hzlandrlaca§ Örnek 15'de görülmü³tü. O örnekteki bde§erleri bir dizide tutularak hesaplanrsa: bn = an bn−1 = bn xi + an−1 b0 = b1 xi + a0 Bu durumda, p0 (x) polinomu ³u ³ekilde yazlabilir (Neden?): p0 (x) = bn xn−1 + bn−1 xn−2 + · · · + b2 x + b1 Bu da bir polinom oldu§undan, hesabnda yine içiçe çarpmlar yöntemi kullanlabilir: cn = bn cn−1 = cn xi + bn−1 c1 = c2 xi + b1 Bu yöntemi kullanarak katsaylarn kullancnn girdi§i bir polinomun köklerini hesaplayan program Örnek 26'de verilmi³tir. 121 Fonksiyonlar Örnek 26 Polinom kökü hesaplayan fonksiyon. #include <iostream> #include <stdlib.h> #include <math.h> // cin,cout,endl // EXIT_SUCCESS // fabs using namespace std; #define MAXDEGREE 50 float newton_raphson(float x, const float a[], int n); int main(void) { float a[MAXDEGREE]; int n, i; float xi, xj, error; cout << "Polinomun derecesi: "; cin >> n; for (i = n; i >= 0; i--) { cout << "a" << i << ": "; cin >> a[i]; } } cout << "Hata: "; cin >> error; cout << "x0: "; cin >> xi; while (true) { xj = newton_raphson(xi, a, n); if (fabs(xj - xi) < error) break; xi = xj; } cout << "Kök: " << xj << endl; return EXIT_SUCCESS; float newton_raphson(float x, const float a[], int n) { float b[MAXDEGREE], c[MAXDEGREE]; float xn; int i; b[n] = a[n]; c[n] = b[n]; for (i = n - 1; i > 0; i--) { b[i] = b[i+1] * x + a[i]; c[i] = c[i+1] * x + b[i]; } b[0] = b[1] * x + a[0]; xn = x - b[0] / c[1]; return xn; 122 E³ simli Fonksiyonlar • Bu program kullanarak p(x) = 13x7 − 9x6 + 12x4 − 4x3 + 3x + 5 polinomunun kökünü x0 = 1 de§erinden ba³layarak, 0.001 hatadan daha küçük olacak ³ekilde bulun. 6.8 E³ simli Fonksiyonlar C++ dilinde giri³ parametre listeleri farkl oldu§u sürece birden fazla fonksiyonun isimlerinin ayn olmas bir sorun yaratmaz. 4 Örne§in, iki giri³ parametresini takas eden fonksiyonlarda swap_int, iki kesirli sayy takas edecek fonksiyona swap_float, iki katar takas edecek fonksiyona swap_str isimlerin ayn olmasna izin verilmese iki tamsayy takas edecek fonksiyona gibi isimler vermek gerekir. Oysa giri³ parametreleri farkl tiplerden oldu§u için üç fonksiyona da swap ad verilebilir: void swap(int &x, int &y) { int tmp; } tmp = x; x = y; y = tmp; void swap(float &x, float &y) { float tmp; } tmp = x; x = y; y = tmp; void swap(char s1[], char s2[]) { char tmp[MAXSIZE]; } 4 strcpy(tmp, s1); strcpy(s1, s2); strcpy(s2, tmp); C dilinde ayn isimde birden fazla fonksiyon olamaz. 123 Fonksiyonlar 6.9 Varsaylan Parametreler Fonksiyonlar tanmlanrken istenirse baz giri³ parametrelerine varsaylan de§erler verilebilir. Varsaylan de§er giri³ parametresi listesinde ilgili de§i³kenden sonra atama komutunda oldu§u gibi yazlr. Bu durumda, ça§ran fonksiyon o parametre için bir de§er göndermezse varsaylan de§er kullanlr. Örne§in bir katar içinde bir simgenin kaçnc srada oldu§unu belirten bir fonksiyon yazalm. Normal durumda simge katarn ba³ndan ba³lanarak aranr ve simgeye ilk raslanlan konum belirlenir. Sözgelimi Dennis Ritchie katarnda 'e' simgesinin sra numaras 1'dir. Ancak bazen de bir noktadan ileriye do§ru arama yapmak istenebilir. Ayn örnek üzerinde ayn simge 4. konumdan ba³lanarak aranrsa sonuç 13 olacaktr. Bu durumda, yazlacak fonksiyonun ba³l§ ³öyle olur: int find_char(char s[], char c, int start); Üçüncü parametrenin ço§u zaman kullanlmayaca§ndan programclar gerek duymadklar bir parametreyi göndermek zorunda brakmak yerine varsaylan de§er kullanmak daha esnek bir çözümdür: int find_char(char s[], char c, int start = 0) { int index = -1, i; } Örnekte for (i = start; s[i] != '\0'; i++) { if (s[i] == c) { index = i; break; } } return index; start parametresine 0 varsaylan de§eri verilir. Böylelikle bu de§i³ken, fonksiyon ça§rlrken belirtilmezse 0 de§erini, belirtilirse verilen de§eri alr. lk iki parametrenin ça§rda belirtilmesi zorunludur; yani fonksiyon iki ya da üç parametreyle ça§rlabilir: find_char(Dennis Ritchie, 'e') find_char(Dennis Ritchie, 'e', 4) // 1 // 13 Sorular 1. Kendisine parametre olarak gönderilen bir katarda, yine kendisine parametre olarak gönderilen bir simgenin ilk ve son pozisyonlar arasnda kaç simge oldu§unu bularak sonucu döndüren bir fonksiyon yazn. Sözgelimi, giri³ katar 124 Varsaylan Parametreler the world is not enough ve giri³ simgesi 'o' ise, fonksiyon 13 de§erini döndürmelidir (rld is not en). 2. Bir katardaki bir simgenin yerine -o simgenin bulundu§u her noktada- ba³ka bir simge geçirilmek isteniyor. Örne§in 2002-04-10 katarnda '-' simgesi yerine '/' simgesi konacaksa 2002/04/10 katar elde edilecektir. (a) Bu i³lemi gerçekle³tiren bir fonksiyon yazn. (b) Verilen örnek tarih üzerinde bu i³lemi gerçekle³tirmek üzere (a) ³kknda yazd§nz fonksiyonu kullanan bir ana fonksiyon yazn. 3. ki tamsay dizisindeki ortak elemanlarn says bulunmak isteniyor. Örne§in birinci dizi 21 10 9 13 15, ikinci dizi 10 7 1 13 15 8 ise ortak elemanlarn says 3'tür (10, 13, 15). Örnekten de görülebilece§i gibi, dizilerin ayn sayda elemanlar bulunmas zorunlu de§ildir. Bunun için: (a) Bir saynn bir dizide bulunup bulunmad§n snayan bir fonksiyon yazn. Fonksiyonun giri³ parametreleri dizi, dizinin boyu ve aranan say olmaldr. Geriye say dizide varsa 1, yoksa 0 de§eri döndürülmelidir. (b) Yukarda yazd§nz fonksiyonu kullanarak, iki dizideki ortak elemanlarn saysn belirleyen bir fonksiyon yazn. Fonksiyonun giri³ parametreleri her iki dizinin kendileri ve boylar olmaldr. Fonksiyon geriye ortak elemanlarn saysn döndürmelidir. (c) Yukarda yazd§nz fonksiyonlar kullanarak, boyunu ve elemanlarn kullancdan ald§ iki dizinin ortak eleman saysn bularak ekrana çkartan bir ana fonksiyon (main) yazn. 4. Bir dizinin kipi, dizide en çok yinelenen elemandr. Sözgelimi 75 32 45 43 75 66 43 88 66 92 66 27 dizisinin kipi 66'dr. Buna göre, bir snavdaki ö§renci notlarnn kipi bulunmak isteniyor. (a) Bir dizinin en büyük elemannn dizideki srasn döndüren bir fonksiyon yazn. (b) Yukarda yazd§nz fonksiyonu kullanarak bir dizinin kipini döndüren bir fonksiyon yazn. (Yol gösterme: Elemanlar ilgili notun kaç kere geçti§ini gösteren 101 elemanl bir tamsay dizisi kullann. Örne§in counts[55], kaç ö§rencinin 55 ald§n göstersin.) (c) Yukarda yazd§nz fonksiyonlar kullanarak, ö§renci saysn ve notlarn kullancdan alarak notlarn kipini bulan ve ekrana çkartan bir ana fonksiyon (main) yazn. 5. Polar sistemde düzlemde bir nokta kutuptan olan uzakl§n belirten θ de§erleriyle belirtilir. Ayn noktann kartezyen x = r · cosθ ve y = r · sinθ e³itlikleri geçerlidir. yapt§ ise sistemdeki r ve kutup eksenine koordinatlar x ve y (a) Noktann polar ve kartezyen koordinatlarn temsil etmek üzere birer kayt tanm yazn. 125 Fonksiyonlar (b) Yukarda yazd§nz kayt tanmlarn kullanarak, parametre olarak bir noktann polar koordinatlarn alan ve geriye kartezyen koordinatlarn döndüren bir fonksiyon yazn. (c) Kayt yaplar kullanmadan polar koordinatlar kartezyen koordinatlara çevirecek bir fonksiyon yazn. (d) (b) ve (c) ³klarnda yazd§nz fonksiyonlarn kullanmlarna birer örnek verin. Varsaylan Parametreler 126 Bölüm 7 ³aretçiler u ana kadar yaplan örneklerde skalar, bile³ke ya da vektörel tipten olsun, bütün de§i³kenlerin bellekte kaplayacaklar alan ba³tan belliydi. Sözgelimi, 100 elemanl bir tamsay dizisi tanmlanrsa bu diziye bellekte 100 adet tamsayy tutacak kadar yer ayrlaca§ derleme a³amasnda biliniyordu. Bu tip de§i³kenlere statik de§i³ken ad verilir. Statik bir de§i³kenin saklanaca§ bellek alan program çal³maya ba³lad§nda ayrlr ve programn sonuna kadar braklmaz. Bu durumun baz sakncalar vardr: • Statik dizilerde görüldü§ü gibi (bkz. Bölüm 5), dizinin eleman says derleme a³amasnda belli de§ilse gerekebilecek en büyük miktarda yer ayrlmak zorunda kalnr. Örne§in, de§i³ik snardaki ö§rencilerin notlarn tutmak üzere bir tamsay dizisi tanmlanacak olsun. Bu durumda bir snftaki maksimum ö§renci says konusunda bir varsaym yapp (diyelim 100) dizi bu boyutta açlmaldr. Verilen bu boyut hem programn bir snrlamas olacak, hem de ö§renci says bunun altnda kald§ zamanlarda gereksiz bellek harcanmasna yol açacaktr. • Programnzda kullanmak istedi§iniz de§i³kenlerin kaplayaca§ toplam bellek alan çal³t§nz bilgisayarda bulunmayabilir. Di§er yandan, bu de§i³kenlerin hepsine birden ayn anda gereksinim duymuyor olabilirsiniz, yani bir de§i³ken için ayrlan yerin programn bütün i³leyi³i boyunca tutulmas gerekli olmayabilir. Sözgelimi bir dizi belli bir noktada kullanlmaya ba³lyor ve bir noktadan sonra da kullanlmyor olabilir. Böyle bir durumda diziye gerekli oldu§u zaman yer ayrmak, i³i bittikten sonra da ayrlan yeri geri vermek programn toplam bellek gereksinimlerini azaltr. ³aretçiler, bellekte kaplanacak yerin derleme srasnda de§il çal³ma srasnda belirlenmesini sa§larlar. Böylelikle gerekti§i zaman gerekti§i kadar yer almak ve gerek kalmad§ zaman da geri vermek olanakl hale gelir. Bir ³ekilde kullanlan de§i³kenlere dinamik de§i³ken ad verilir. Dinamik de§i³kenlerin zorlu§u, bellek alanlarnn yönetimi programcya brakld§ndan programlarn en sk hata yaplan bölümleri olmalardr. ³aretçi, bir bellek gözüne i³aret eden bir de§i³kendir. Bunun anlam, i³aretçi de§i³keninin o bellek gözünün adresini tutmasdr. Ba³ka bir deyi³le, i³aretçi de§i³keninin de§eri, bellek gözünün adresidir. Dolaysyla, bir i³aretçi için iki de§erden söz edilebilir: 127 128 • kendi de§eri: i³aret edilen bellek gözünün adresi • i³aret etti§i de§er: i³aret edilen bellek gözünün içeri§i ekil 7.1a'da i³aretçi de§i³keniyle i³aret edilen bellek gözü arasndaki ili³ki simgesel olarak p gösterilmi³tir. Burada de§i³keni, içinde 422 yazan bir bellek gözüne i³aret etmektedir. e- kil 7.1b, ayn durumun örnek adres de§erleriyle nasl sa§land§n gösterir. zl oldu§u bellek gözünün adresinin 8000 oldu§u varsaymyla, ta³d§ görülür. Adres de§erlerinin (bu örnekteki 8000 p 422 de§i³keninin de§erinin ya- 8000 de§erini says) ne olduklar programcy ilgi- lendirmez, bunlar i³letim sistemi belirler. Programc adres de§erlerinin ne olaca§ konusunda bir varsaymda bulunamaz. p p 422 422 8000 12000 8000 (a) (b) ekil 7.1: ³aretçi tipinden de§i³kenler. ³aretçinin i³aret etti§i bellek gözünün içeri§inin okunmas için örnekte p deyiminin de§eri 8000, *p deyiminin de§eriyse 422'dir. * i³leci kullanlr. ekildeki ³aretçilerle i³lem yaparken, i³aretçinin kendisiyle mi, yoksa i³aret etti§i alanla m i³lem yapld§na dikkat edilmelidir. p++ Örne§in komutu neden olur. Oysa 422 p i³aretçisinin bir sonraki (diyelim 8001) bellek gözüne i³aret etmesine (*p)++ komutu kullanlmaldr. de§erinin bir artrlmas isteniyorsa ³aretçilerle ilgili i³lemlerde kullanlan di§er bir i³leç de & i³lecidir. Adres i³leci ad verilen bu i³leç, bir de§i³kenin adresinin ö§renilmesini sa§lar. Örnekte oldu§undan • &p: • p: &p p de§i³keninin adresi 12000 deyiminin de§eri 12000'dir. Örnekteki de§erleri toparlarsak: 12000 8000 • *p: 422 ³aretçi de§i³kenleri için NULL adnda özel bir de§er tanmlanr. Bu de§erin anlam, o i³a- retçinin geçerli bir bellek gözüne i³aret etmiyor oldu§udur. Dolaysyla, de§eri i³aretçi de§i³keninin * NULL olan bir i³leciyle içeri§inin okunmaya çal³lmas derleyicinin farkedemeyece§i ama çal³ma annda bellek hatasna yol açacak bir programlama hatasdr. Örnek 27. Dinamik Diziler Bu bölümdeki program, Örnek 13'de yazlan istatistik programnn aynsdr. Dolaysyla ekran çkts ekil 5.1'de verilenle ayndr. Programn i³leyi³indeki tek fark, statik diziler yerine di- 129 ³aretçiler score NULL ekil 7.2: ³aretçi tipinden de§i³ken tanmlama. namik diziler kullanlmasdr. Böylece snftaki ö§renci says kullancdan ö§renildikten sonra, tam gerekti§i kadar eleman tutacak bir dizi tanmlanabilmi³tir. 7.1 ³aretçi Tipinden De§i³kenler ³aretçiler, de§erleri birer adres (bir tür tamsay) olan de§i³kenlerdir, di§er de§i³ken tiplerinden bir farklar yoktur. Dolaysyla, di§er de§i³kenlerde oldu§u gibi, i³aretçi tipinden bir de§i³ken tanmland§nda bellekte bir adres tutmaya yetecek kadar yer ayrlr. ³aretçinin kendi de§eri her zaman bir adrestir ama i³aret etti§i bellek gözünün nasl yorumlayaca§nn belirtilmesi gerekir. Bu nedenle, i³aretçi tanm ³u ³ekilde yazlr: veri_tipi * de§i³ken_ad ; Bu tanmn anlam, ad verilen de§i³kenin bir i³aretçi oldu§u ve gösterdi§i bellek gözünde belirtilen tipten bir de§er bulunaca§dr. Buradaki içeri§i anlamna gelen * * i³areti, i³aretçinin gösterdi§i bellek gözünün i³leciyle kar³trlmamaldr. Örnekteki int *score = NULL; tanm, score de§i³keninin tamsay barndran bir bellek gözüne i³aretçi oldu§unu belirtir (ekil 7.2). ³aretçilere ba³langç de§eri olarak genellikle 7.2 NULL atanr. Bellek Yönetimi Programda kullanlacak her türlü bellek bölgesinin kullanlaca§ i³ için ayrlmas gerekti§i görülmü³tü. Yani i³aretçinin i³aret edece§i bellek alannn da ayrlmas gerekir. Ayrlacak bu alan tek bir eleman boyunda olabilece§i gibi, birden fazla elemandan olu³an bir dizi olarak da kullanlabilir. Dinamik dizi kullanrken i³aretçi tanmnda belirtilen veri tipi dizinin her bir elemannn tipi olarak dü³ünülebilir. Yer ayrma i³lemini gerçekle³tiren new i³leci istenen büyüklükte, birbirini izleyen gözlerden olu³an bir bellek alann ayrarak ba³langç adresini verir. Yer alma giri³imi ba³arszlkla sonuçlanrsa, örne§in bellekte yer kalmadysa, geriye NULL de§erini döndürür. Yazm ³u ³ekildedir: new veri_tipi [eleman_says ] 130 Bellek Yönetimi Örnek 27 Örnek 13'in dinamik dizilerle gerçeklenmesi. #include <iostream> #include <stdlib.h> #include <math.h> // cin,cout,endl // EXIT_SUCCESS // fabs,sqrt using namespace std; int main(void) { int *score = NULL; int no_students = 0; float mean, variance, std_dev, abs_dev; float total = 0.0, sqr_total = 0.0, abs_total = 0.0; int i = 0; } cout << "Kaç ö§renci var? "; cin >> no_students; score = new int[no_students]; for (i = 0; i < no_students; i++) { cout << i + 1 << ". ö§rencinin notu: "; cin >> score[i]; total = total + score[i]; } mean = total / no_students; for (i = 0; i < no_students; i++) { sqr_total = sqr_total + (score[i] - mean) * (score[i] - mean); abs_total = abs_total + fabs(score[i] - mean); } variance = sqr_total / (no_students - 1); std_dev = sqrt(variance); abs_dev = abs_total / no_students; cout << "Ortalama: " << mean << endl; cout << "Varyans: " << variance << endl; cout << "Standart sapma: " << std_dev << endl; cout << "Mutlak sapma: " << abs_dev << endl; delete score; return EXIT_SUCCESS; 131 ³aretçiler score no_students*sizeof(int) 6500 6500 ekil 7.3: Yer ayrlmasndan sonraki durum. Örnekte ö§renci notlarn tutacak dizi için score = new int[no_students]; komutuyla yer alnm³tr. Bu komut sonucunda bellekte lk bir alan ayrlr ve bu alann ba³langç adresi score no_students * sizeof(int) kadar- i³aretçisine atanr (ekil 7.3). Tek bir elemanlk bölge ayrlacaksa eleman saysnn belirtilmesine gerek yoktur. Örne§in, ekil 7.1'de çizilen durum ³u komutlarla yaratlabilir: int *p = NULL; p = new int; *p = 422; // 8000 oldu§u varsaylyor Ayrlan yerin geri verilmesi delete i³leciyle gerçeklenir. Bu i³leç, bir i³aretçi için alnan bütün bölgeyi geri verir; bölgenin bir ksmn geri vermek gibi bir seçenek yoktur. Bu nedenle, i³lece yalnzca i³aretçinin adn vermek yeterlidir, geri verilecek eleman says yeniden belirtilmez. Yukarda yazlan her iki (birden fazla eleman ya da bir eleman) yer ayrma i³leminin de geri vermesi benzer ³ekildedir: delete score; delete p; ³aretçi tipinden de§i³kenler için her zaman yer ayrlmas zorunlulu§u yoktur. Zorunlu olan DKKAT nokta, i³aretçilerin her zaman geçerli bellek gözlerine i³aret etmeleridir. Bu bellek gözleri örneklerde oldu§u gibi dinamik olarak ayrlm³ olabilecekleri gibi, ba³ka bir i³aretçi de§i³keni tarafndan ayrlm³ ve hatta statik olarak tanmlanm³ bile olabilirler. Örne§in ekil 7.1'de çizilen durum ³u komutlarla da yaratlabilirdi: int x = 422; int *p = &x; Bu durumda 422 de§erini tutan bellek gözüne programn ba³nda statik olarak yer ayrlr; i³aretçisi ise bu bellek gözünün adresini ta³r. Önemli olan x ile *p p de§i³kenlerinin ayn bellek gözünde bulunduklarnn ve birinin de§i³mesiyle öbürünün de de§i³ece§inin gözönünde bulundurulmasdr. Örnekte p de§i³keni için yer ayrlmad§ndan burann de sözkonusu de§ildir; böyle bir deneme hataya neden olacaktr. delete ile geri verilmesi 132 ³aretçi - Dizi li³kisi Bellek yönetimi için new ve delete i³leçleri C++ dilinde getirilmi³ yeniliklerdir. C dilinde ayn malloc ve free fonksiyonlarn kullanmak gerekir. Buna göre örnekteki i³lemleri yapmak için programn ilgili satrlar ³u ³ekilde de§i³tirilebilir score = (int *) malloc(no_students * sizeof(int)); ... free(score); malloc fonksiyonu new i³leciyle ayn ³ekilde yer ayrr. Aralarndaki yazm farklar ³u ³ekilde açklanabilir: 1. new i³lecinde eleman tipi ve says belirtilir, malloc fonksiyonunda ise ayrlacak alann boyunu sekizli cinsinden vermek gerekir. 2. malloc fonksiyonu geriye void * tipinden bir de§er döndürür (ham i³aretçi). Bu de§er de§i³kene atanrken uygun ³ekilde tip dönü³ümü yaplmas gerekir. 3. malloc ve free birer fonksiyon olduklarndan parametrelerinin ayraçlar içinde yazlmas gerekir. Ayn nedenle, kullanlabilmeleri için bir ba³lk dosyasnn (stdlib.h) alnmas gerekir. 7.3 ³aretçi - Dizi li³kisi Statik diziler ile dinamik diziler arasndaki tek fark olu³turulmalarndadr, elemanlara eri³im her ikisinde de ayndr. Yani ³u iki tanm arasnda, bellekte olu³an durum açsndan bir fark yoktur: int p[10]; ... for (i = 0; i < 10; i++) ...p[i]... ... int *p; p = new int[10]; ... for (i = 0; i < 10; i++) ...p[i]... ... delete p; Statik dizilerle dinamik dizilerin ayn ³ekilde kullanlabilmeleri iki özelli§e dayanr: 1. Statik bir dizinin ad, dizinin ilk elemanna bir i³aretçidir. 2. ³aretçinin de§eri bir sayyla toplanrsa, i³aretçinin gösterdi§i adresten i³aret edilen tipten o say kadar ilerlenerek gelinen bellek gözünün adresi elde edilir. Benzer ³ekilde, çkartma i³leminde bu miktar kadar geriye gidilir. Bu özellikler nedeniyle, i³aretçinin tipi ne olursa olsun, a³a§daki deyimler e³de§erlidir: p[0] p[1] p[n] *p *(p + 1) *(p + n) 133 ³aretçiler Katarlar da birer dizi olduklarndan katarlar arasndaki atama ve kar³la³trma gibi i³lemlerin neden beklendi§i gibi çal³mayacaklarna tekrar dönelim. ekil 7.4'deki yapda str2 de§i³kenleri kar³la³trlrsa (str1 == str2), str1 ile kar³la³trma sonucu yanl³ de§eri üretilir (32006=9450). str1 3200 "Dennis Ritchie" 3200 str2 9450 "Dennis Ritchie" 9450 ekil 7.4: Katarlarn kar³la³trlmas. Benzer ³ekilde, ayn örnekte str1 = str2 atamas str1 i³aretçisinin str2 i³aretçisiyle ayn de§eri almas sonucunu do§urur (ekil 7.5). Bu durum ayn katarn iki farkl kopyasnn olu³masn sa§lamad§ gibi str1 katarnn önceki i³aret etti§i bellek bölgesinin (Dennis Ritchie de§erinin bulundu§u bölge) de yitirilmesine yol açar. Örnek 28. Morse Kodlamas Kullancdan ald§ bir sözcü§ü Morse abecesinde kodlayan bir program yazlmas isteniyor. Programn örnek bir çal³masnn ekran çkts ekil 7.6'da verilmi³tir. 7.4 ³aretçi Tipinden Parametreler Dizilerin fonksiyonlara parametre olarak aktarlmalarnda statik ya da dinamik gösterilimler arasnda bir fark yoktur. Sözgelimi, Örnek 24'de yazlan asal çarpanlarna ayrma fonksiyonunun bildirimi için ³u ikisi e³de§erlidir: void factorize(int number, factor_t factors[], int &n); void factorize(int number, factor_t *factors, int &n); str1 9450 "Dennis Ritchie" 3200 str2 9450 "Ken Thompson" 9450 (b) ekil 7.5: Katarlarn atanmas. 134 ³aretçi Tipinden Parametreler Örnek 28 Morse kodlamas yapan program. #include #include #include #include <iostream> <stdlib.h> <stdio.h> <string.h> // // // // cin,cout,endl EXIT_SUCCESS gets strcat using namespace std; #define MAXLENGTH 80 char *encode(const char *s); int main(void) { char word[MAXLENGTH]; char *morse = NULL; } cout << "Sözcü§ü yaznz: "; cin >> word; morse = encode(word); cout << "Morse kar³l§: " << morse << endl; delete morse; return EXIT_SUCCESS; char *encode(const char *s) { static char encoding[][5] = { ".-", "-...", "-.-.", "-..", "....", "..", ".---", "-.-", "---", ".--.", "--.-", ".-.", "...-", ".--", "-..-", "-.--", char *morse = new char[MAXLENGTH]; int i; } ".", "..-.", "--.", ".-..", "--", "-.", "...", "-", "..-", "--.." }; morse[0] = '\0'; for (i = 0; s[i] != '\0'; i++) { strcat(morse, encoding[s[i] - 'a']); strcat(morse, " "); } return morse; 135 ³aretçiler Sözcü§ü yaznz: istanbul Morse kar³l§: .. ... - .- -. -... ..- .-.. ekil 7.6: Örnek 28 ekran çkts. Fonksiyonun ba³lk satrnda bu iki gösterilimden herhangi biri kullanlabilir, fonksiyonun gövdesinde bir de§i³iklik yapmak gerekmez. ³aretçiler, dizilerin çkt parametresi olarak döndürülememesi kstlamasn da çözerler. Statik bir dizi bir bütün halinde (bütün elemanlarnn kopyas olu³turularak) çkt parametresi olarak döndürülemez ancak dizinin ba³na bir i³aretçi döndürülebilir. Örnekte bu özellik kullanlarak encode fonksiyonu char *encode(const char *s); ³eklinde bildirilmi³tir. Bunun anlam, bu fonksiyonun de§i³tirilmeyecek bir katar ald§ ve üretti§i katar geri döndürdü§üdür. Fonksiyonun gövdesinde tanmlanan m³ sözcü§ü tutar ve fonksiyon sonunda morse de§i³keni, kodlan- ile geri döndürülür. encode fonksiyonunun, geri verme i³iniyse main fonksiyonunun yapmasdr. Geri verme i³lemi yine encode fonksiyonunca yaplamaz çünkü katarn i³i henüz sona ermemi³tir. Benzer ³ekilde morse de§i³keni encode fonksiyonunda statik olarak da (char morse[MAXLENGTH] ³eklinde) tanmlanamaz çünkü böyle Burada önemli olan bir nokta, morse return katar için yer ayrma i³ini tanmland§nda bu bir yerel de§i³ken olaca§ndan fonksiyonun sona ermesiyle onun için ayrlm³ olan bellek geri verilir ve sonuç ana fonksiyona aktarlamaz. 7.5 Statik De§i³kenler Örnekte encode fonksiyonunda tanmlanan encoding dizisi bu fonksiyonun bir yerel de§i³ke- nidir, yani fonksiyonun her yaratl³nda bu dizi yeniden yaratlr, elemanlarna de§erler verilir ve fonksiyonun sona ermesiyle yok edilir. Bu i³lemin her defasnda tekrar tekrar yaplmas istenmiyorsa, encoding de§i³keni genel bir de§i³ken olarak tanmlanabilir: char encoding[][5] = { ... }; int main(void) { ... } char *encode(char *word) { ... } 136 Adres Aktarm encoding de§i³keninin gereksiz main fonksiyonundan da eri³ilebilir hale gelmesine yol açar. Daha düzgün bir çözüm, encoding de§i³kenini encode fonksiyonunun içinde statik olarak tanmlanamaktr: Genel de§i³ken tanmlamak sözü edilen sakncay giderir ama yere static char encoding[][5] = { ... }; Böyle yapld§nda encoding dizisi genel bir de§i³ken gibi sürekli ya³ar ama encode fonksiyonu d³nda kullanlamaz. 7.6 Adres Aktarm Ba³vuru aktarm yöntemi C++ dilinde gelmi³ oldu§undan C dilinde bunun yerine adres aktarm yöntemi kullanlr, yani ça§rlan fonksiyona de§i³kenin adresi yollanr. Ça§rlan fonksiyon bu adresi i³aretçi tipinden bir de§i³kene alr ve bu i³aretçinin gösterdi§i yerde de§i³ikli§i yapar. Böylece de§i³iklik ça§ran fonksiyondaki de§i³keni do§rudan etkiler. Buna göre, Örnek 20'da anlatlan ve düzeltilen swap fonksiyonu yöntemi Örnek 29'de oldu§u gibi de gerçeklenebilirdi: Örnek 29 ki sayy adres aktarmyla takas eden fonksiyon ve kullanm. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; void swap(int *x, int *y) { int tmp; } tmp = *x; *x = *y; *y = tmp; int main(void) { int m = 32, n = 154; } cout << m << " " << n << endl; swap(&m, &n); cout << m << " " << n << endl; return EXIT_SUCCESS; Bu örnekte m x de§i³keni tamsayya i³aretçi (yani adres) tipinden bir de§i³ken olurdu ve de§eri de§i³keninin adresi olurdu. Yani yazlm³ olurdu (ekil 7.7). x i³aretçisinin gösterdi§i yere yazlan de§er m de§i³kenine 137 ³aretçiler x swap y 2000 m main tmp 2004 xxx n 32 2000 154 2004 (a) x swap y 2000 m main tmp 2004 xxx n 154 2000 32 2004 (b) ekil 7.7: Takas fonksiyonunda parametre aktarm. Günümüzde neredeyse bütün C geli³tirme ortamlarnda C++ yetenekleri bulundu§undan, giri³ parametrelerinde de§i³iklik yapmak istendi§inde adres aktarm yöntemini kullanmann artk bir gere§i yoktur. Adres aktarm programc hatalarna daha elveri³li oldu§undan ancak derleyiciniz C++ desteklemiyorsa ya da probleminiz açsndan daha uygunsa kullanmanz önerilir. Uygulama: ³aretçiler Örnek 30. Seçerek Sralama Kullancdan ald§ say kadar ö§rencisi olan bir snfta kullancnn girdi§i ö§renci notlarnn ortade§erini bulan bir program yazlmas isteniyor. Bir dizinin ortade§eri, dizi sraland§nda dizinin ortasnda yer alan de§erdir. Çift sayda eleman olan dizilerde dizinin ortasnda bir eleman olmad§ndan ortadaki iki elemann aritmetik ortalamas ortade§er kabul edilir. Dizinin ortade§erini bulmak için öncelikle diziyi sralamak gerekir. Örnekte kullanlan seçerek sralama yöntemi, en basit sralama algoritmalarndan biridir. Bu yöntemde, küçükten büyü§e do§ru sralama yaplaca§ varsaymyla, bu algoritmann her admnda dizinin en büyük eleman bulunur ve sondaki elemanla yeri kar³lkl de§i³tirilir. Böylece en büyük eleman en sona alnr ve dizinin boyu bir azaltlarak i³leme devam edilir. geçen i³lem n−1 n elemanl bir dizide sözü kere yinelenecektir. Örnek bir dizi üzerinde seçerek sralama algoritmasnn çal³mas ekil 7.8'de verilmi³tir. • Sralama i³lemini kabarck sralama algoritmas kullanacak ³ekilde düzenleyin. 138 Adres Aktarm Örnek 30 Ö§renci notlarnn ortade§erini bulan program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; void selsort(int *numbers, int count); int main(void) { int *score = NULL; float median; int no_students, i; cout << "Ö§renci says: "; cin >> no_students; score = new int[no_students]; for (i = 0; i < no_students; i++) { cout << i + 1 << ". ö§rencinin notu: "; cin >> score[i]; } selsort(score, no_students); median = (no_students % 2 == 1) ? score[no_students/2] : (score[no_students/2] + score[no_students/2-1]) / 2.0; cout << "Orta de§er: " << median << endl; } delete score; return EXIT_SUCCESS; void selsort(int *numbers, int count) { int round, max, i; int tmp; } for (round = 0; round < count - 1; round++) { max = 0; for (i = 1; i < count - round; i++) { if (numbers[max] < numbers[i]) max = i; } tmp = numbers[max]; numbers[max] = numbers[count - 1 - round]; numbers[count - 1 - round] = tmp; } 139 ³aretçiler 4 5 1 3 2 4 2 1 3 5 3 2 1 4 5 1 2 3 4 5 1 2 3 4 5 ekil 7.8: Seçerek sralama örne§i. Adres Aktarm 140 Sorular 1. Sezar ³ifrelemesi yönteminde ³ifrelenecek sözcükteki her harn yerine (ngilizce) abecede kendisinden 3 sonra gelen harf konur (A yerine D, B yerine E, ..., V yerine Y, W yerine Z, X yerine A, Y yerine B, Z yerine C). Buna göre HUNGRY sözcü§ünün kar³l§ KXQJUB olur. (a) Bildirimi a³a§da verildi§i ³ekliyle bir sözcük alan ve bunun ³ifrelenmesi sonucu olu³an yeni katar döndüren bir fonksiyon yazn: char *caesar(const char s[]); (b) Kullancdan ald§ bir sözcü§ü yukardaki fonksiyon yardmyla ³ifreleyen ve sonucu ekrana yazan bir ana fonksiyon yazn. (c) (a) ³kknda yazd§nz fonksiyonu öteleme miktar da bir parametre olacak ³ekilde genelle³tirin ve (b) ³kknda yazd§nz fonksiyonu da uygun biçimde düzenleyin. 2. ngilizce'de 'q' harnden sonra ço§u zaman 'u' har gelir. Buna göre kendisine parametre olarak gönderilen katarda 'q' harnden sonra 'u' har geliyorsa 'u' harni silen bir fonksiyon yazn. Sözgelimi, fonksiyona you must be quick katar parametre olarak gelirse bu fonksiyon katar you must be qick diye de§i³tirmelidir (yeni bir katar üretmiyor, geriye bir de§er döndürmüyor). Bu fonksiyonu denemek üzere bir ana fonksiyon yazn. Bölüm 8 Giri³-Çk³ Bu bölümde öncelikle giri³-çk³ kitapl§ndaki fonksiyonlar kullanarak giri³-çk³ i³lemlerinin nasl yapld§ gösterilecektir. Daha sonra dosyalar üzerinde okuma-yazma i³lemlerinin nasl yapld§ anlatlacaktr. 8.1 Çk³ C dilinde cout birimi yoktur. Bunun yerine printf fonksiyonu kullanlr. Bu fonksiyonun yaps ³u ³ekildedir: printf(biçim katar, deyim1, deyim2, deyim3, ...); Biçim katarnn temel i³levi yazdrlmas istenen iletileri belirtmektir. Sözgelimi: cout < < Merhaba dünya! < < endl; komutunun C'deki kar³l§ ³öyledir: printf(Merhaba dünya!\n); Bu örnekte ekrana herhangi bir de§i³ken ya da deyim de§eri yazdrlmamakta, yalnzca bir ileti görüntülenmektedir. Katarn sonundaki sa§lar (C++'daki endl '\n' simgesi katar sona erdi§inde alt satra geçilmesini kar³l§). Bir deyim de§erinin ekranda gösterilmesi isteniyorsa bu de§erin tipi de biçim katarnda belirtilmelidir. Her veri tipinin kendine özgü bir belirteci vardr. (bkz. Tablo 8.1). Buna göre Örnek 1'de geçen cout < < Alan: < < area < < endl; komutunun kar³l§ ³u ³ekilde olur: 141 142 Çk³ Veri Tipi Belirteç Onlu düzende tamsay Onlu düzende uzun tamsay Onaltl düzende tamsay Noktal gösterilimde kesirli say Bilimsel gösterilimde kesirli say Simge Katar %d %ld %x %f %e %c %s Tablo 8.1: Biçim belirteçleri. printf(Alan: %f\n, area); Çktnn nasl olu³turulaca§n biçim katar belirler. Belirteçler d³nda kalan bölümler oldu§u gibi çk³a aktarlr; bir belirteç ile kar³la³ld§nda deyim listesinde sradaki deyim hesaplanarak elde edilen de§er çk³a aktarlr. Dolaysyla, biçim katarnda geçen belirteçler ile deyim listesindeki deyimlerin say ve tiplerinin birbirini tutmas gerekir. Örnek. radius de§i³keninin kesirli say tipinden oldu§u ve kullancnn giri³ srasnda 2.4 de§erini yazd§ varsaymyla printf(Yarçap %f olan dairenin alan: %f\n, radius, 3.14 * radius * radius); fonksiyonunun i³leyi³i ³u ³ekilde olur: • Biçim katarnda ilk % i³aretine kadar görülen her simge ekrana çkartlr (belirteçten Yarçap önceki bo³luk dahil): • Biçim katarndan sonraki ilk deyimin de§eri kesirli say biçiminde ekrana çkartlr (önce ve sonraki bo³luklar hariç): • 2.4 Bir sonraki belirtece kadar görülen her simge ekrana çkartlr: alan: • olan dairenin Biçim katarndan sonraki ikinci deyimin de§eri kesirli say biçiminde ekrana çkartlr: • \n 18.07 simgesi nedeniyle sonraki satra geçilir. Yüzde ve ters bölü i³aretleri biçim katarnda özel anlam ta³dklarndan bunlarn çk³a gönderilmesi istendi§inde özel bir yazm gerekir. Yüzde i³aretini çkarmak için '%%', ters bölü i³aretini çkarmak içinse '\\' simgeleri kullanlmaldr. Biçim katar de§i³ken de§erlerinin çk³a gönderilmesinde ayrntl denetim olana§ da sa§lar. Örne§in say de§erlerinin belli bir uzunlukta olmas sa§lanabilir. %5d ³eklinde belirtilen bir tamsay de§eri be³ haneliyse bo³luksuz, dört haneliyse bir bo³luk ve say, üç haneliyse iki bo³luk ve say v.b. ³eklinde de§erlendirilerek çk³a gönderilir. Bu yöntem düzgün ³ekilde altalta gelmi³ çktlar olu³turmak için yararldr. Kesirli saylarda da noktadan önce ve sonra 143 Giri³-Çk³ kaç hane bulundu§u belirtilebilir. Sözgelimi %20.12f belirteci saynn toplam 20 hane (nokta dahil) yer tutaca§n ve bunun 12 hanesinin noktadan sonra olaca§n gösterir. DÜZELT: daha fazla ayrnt 8.2 Giri³ Çk³ biriminde oldu§u gibi, C dilinde giri³ için kullanlabilecek yerine scanf cin birimi de yoktur. Bunun fonksiyonu kullanlr. Bu fonksiyonun yaps ³u ³ekildedir: scanf(biçim katar, &de§i³ken1, &de§i³ken2, &de§i³ken3, ...); Biçim katar, printf fonksiyonundakine benzer bir i³lev görür ve okunacak de§erlerin tipinin ne olaca§n belirler. Kullanlan veri tipi belirteçleri de ayndr. Giri³ yaplrken kullancnn yazd§ de§erin alnaca§ de§i³ken scanf fonksiyonunda de§er de§i³tirece§inden fonksiyona bu de§i³kenin adresi gönderilir (bkz. Bölüm 7.6). Bu nedenle, scanf fonksiyonuna gönderilen de§i³kenlerin adlarnn ba³na adres i³leci olan & simgesi konur. Örne§in cin > > radius; komutunun C dilindeki kar³l§ ³u ³ekildedir: scanf(%d, &radius); Katar tipinden olan de§i³kenlerde katarlar bir dizi olduklarndan ve adlar zaten dizinin ilk elemanna bir i³aretçi oldu§undan katar tipinden bir word & simgesi kullanlmaz. Sözgelimi, kullancnn yazd§ sözcü§ü de§i³kenine almak için a³a§daki komut kullanlr: scanf(%s, word); Örnek 31. statistik Hesaplar Bu örnekte, Örnek 13'de yaplan ö§renci notlar üzerindeki istatistik hesaplar dosyalar yardmyla gerçeklenecektir. Ö§renci notlar bir dosyadan okunacak, i³lem sonuçlar da yine bir dosyaya yazlacaktr. Notlarn hangi dosyadan okunaca§ ve sonuçlarn hangi dosyaya yazlaca§ program çal³trlrken komut satrndan belirtilecek, böylelikle program çal³mas srasnda kullancya hiçbir ³ey sormayacak, üretti§i hiçbir sonucu da ekranda göstermeyecektir. Bu programn yazl oldu§u dosya dosyann ad stat3 stat3.cpp ve derleme ile ba§lama sonucu olu³an çal³trlabilir olursa program stat3 notlar.txt sonuclar.txt gibi bir komutla ça§rlmaldr. Burada ilk belirtilen isim (örnekte dosyay, ikinci isim (örnekte notlar.txt) okunacak sonuclar.txt) sonuçlarn yazlaca§ dosyay gösterir ve herhangi birinin eksik olmas durumunda program nasl çal³trlmas gerekti§ine ili³kin bir kullanm iletisi görüntüler. 144 Giri³ Örnek 31 Dosyalar ile giri³/çk³ i³lemleri yaparak ö§renci notlar üzerinde istatistik hesaplar yapan program (okuma bölümü). #include #include #include #include <iostream> <stdio.h> <stdlib.h> <math.h> // // // // cin,cout,cerr,endl fopen,fclose,fprintf,fscanf,feof exit,EXIT_SUCCESS,EXIT_FAILURE fabs,sqrt using namespace std; #define MAXSTUDENTS 100 int main(int argc, char *argv[]) { int score[MAXSTUDENTS]; int no_students = 0; float mean, variance, std_dev, abs_dev; float total = 0.0, sqr_total = 0.0, abs_total = 0.0; int i = 0; FILE *infile, *outfile; if (argc != 3) { cout << "Kullanm: " << argv[0] << " giri³_dosyas çk³_dosyas" << endl; return EXIT_FAILURE; } infile = fopen(argv[1], "r"); if (infile == NULL) { cerr << "Giri³ dosyas açlamad." << endl; exit(EXIT_FAILURE); } no_students = 0; while (true) { fscanf(infile, "%d", &score[no_students]); if (feof(infile)) break; total = total + score[no_students]; no_students++; } fclose(infile); ... } return EXIT_SUCCESS; 145 Giri³-Çk³ Örnek 32 Dosyalar ile giri³/çk³ i³lemleri yaparak ö§renci notlar üzerinde istatistik hesaplar yapan program (yazma bölümü). #include #include #include #include <iostream> <stdio.h> <stdlib.h> <math.h> // // // // cin,cout,cerr,endl fopen,fclose,fprintf,fscanf,feof exit,EXIT_SUCCESS,EXIT_FAILURE fabs,sqrt using namespace std; #define MAXSTUDENTS 100 int main(int argc, char *argv[]) { int score[MAXSTUDENTS]; int no_students = 0; float mean, variance, std_dev, abs_dev; float total = 0.0, sqr_total = 0.0, abs_total = 0.0; int i = 0; FILE *infile, *outfile; ... mean = total / no_students; for (i = 0; i < no_students; i++) { sqr_total = sqr_total + (score[i] - mean) * (score[i] - mean); abs_total = abs_total + fabs(score[i] - mean); } variance = sqr_total / (no_students - 1); std_dev = sqrt(variance); abs_dev = abs_total / no_students; outfile = fopen(argv[2], "w"); if (outfile == NULL) { cerr << "Çk³ dosyas açlamad." << endl; exit(EXIT_FAILURE); } fprintf(outfile, fprintf(outfile, fprintf(outfile, fprintf(outfile, fprintf(outfile, "Ö§renci says: %d\n", no_students); "Ortalama: %f\n", mean); "Varyans: %f\n", variance); "Standart sapma: %f\n", std_dev); "Mutlak sapma: %f\n", abs_dev); fclose(outfile); } return EXIT_SUCCESS; 146 Ana Fonksiyona Parametre Aktarma 8.3 Ana Fonksiyona Parametre Aktarma Ana fonksiyon da di§er fonksiyonlar gibi bir fonksiyon olmakla birlikte giri³ ve çk³ parametrelerinin aktarm bakmndan farkllk gösterir. Bir fonksiyonun giri³ parametreleri almas ve çk³ parametresi döndürmesi, o fonksiyonun ça§rlabilmesi anlamna gelir. Oysa ana fonksiyon çal³mann ba³lad§ fonksiyon oldu§undan di§er fonksiyonlarca ça§rlmaz. Ana fonksiyonu ça§ran i³letim sistemidir, yani ana fonksiyonun ça§rlmas programn i³letim sistemince yürütülmeye ba³lanmasna kar³ dü³er. Bu durumda ana fonksiyon giri³ parametrelerini i³letim sisteminden alr, çk³ parametresini de i³letim sistemine döndürür. Ana fonksiyonun çk³ parametresinin nasl belirtildi§i ³u ana kadarki bütün örneklerde görülmü³tü. Bu parametre programn çal³mas sonucu olu³an durumun i³letim sistemine bildirilmesi anlamn ta³r ve ba³ar durumunda return EXIT_SUCCESS; ba³arszlk durumunda return EXIT_FAILURE; komutlaryla belirtilir. Ana fonksiyonun giri³ parametreleriyse kullancnn program çal³trrken belirtti§i parametrelerdir. Giri³ parametrelerinin okunabilmesi için ana fonksiyonun giri³ parametresi listesi int argc, char *argv[] ³eklinde verilir. Burada argc parametre saysn, argv ise parametre dizisini gösterir. Para- metre dizisinin her bir eleman, ba³lktan da görülebilece§i gibi, bir katardr. Programn ad da parametreler arasnda sayld§ndan parametre says en az 1 olabilir. Yani argc de§i³keni program yalnzca stat3 komutuyla ça§rlrsa 1, yukarda verilen ³ekilde ça§- rlrsa 3 de§erini alr. Parametre de§erleri de argv dizisinin elemanlarn olu³tururlar. Yine örnek üzerinden gidersek: argv[0] = stat3 argv[1] = notlar.txt argv[2] = sonuclar.txt Örnekteki if (argc != 3) komutu programn do§ru sayda parametreyle çal³trlp çal³trlmad§n snamak için konmu³tur. Parametre saysnn hatal oldu§u durumda programn ekrana bir kullanm iletisi basp sonlanmasn sa§lar. Bütün giri³ parametrelerinin birer katar oldu§una dikkat edilmelidir. Komut satrndan verilen de§erlerin say olarak kullanlabilmesi için uygun kitaplk fonksiyonlaryla (tamsaylar için atoi, kesirli saylar için atof) sayya çevrilmeleri gerekir. 147 Giri³-Çk³ 8.4 Dosyalar Dosyalar üzerinde i³lem yapmak için öncelikle dosyay programda temsil edecek bir de§i³ken tanmlanmaldr. C dilinde bu de§i³ken dosya i³aretçisi olarak adlandrlr ve FILE * tipinden tanmlanr. Örnekte biri giri³ dosyasn (infile) di§eri de çk³ dosyasn (outfile) temsil etmek üzere iki dosya i³aretçisi tanmlanm³tr. Dosya i³aretçisi sradaki okuma ya da yazma i³leminin dosya üzerinde hangi noktada yaplaca§n belirler ve yaplan her i³lemle ileri ya da geri do§ru hareket eder. 8.4.1 Dosya Açma - Kapama Bir dosya üzerinde i³lem yapmadan önce ilk yaplmas gereken dosyann açlmasdr. Açma i³lemi bildirimi a³a§da verilmi³ olan fopen fonksiyonu yardmyla yaplr: FILE *fopen(const char *path, const char *mode ); Fonksiyon ba³l§nda görülen path parametresi, açlacak dosyann sistemdeki tam adnn be- lirtilmesini sa§lar. kinci parametre olan mode ise dosya üzerinde ne i³lem yaplmas istendi§ini belirtmeye yarar. Bu parametre için verilebilecek örnek de§erler ³öyledir: • r : dosya yalnzca okunacak (dosya varsa sfrlanmaz, yoksa yaratlmaz) • w : dosyaya yalnzca yazlacak (dosya varsa sfrlanr, yoksa yaratlr) • r+ : dosyada hem okuma hem yazma yaplacak (dosya varsa sfrlanmaz, yoksa yaratl- maz) • w+ : • a : dosyada hem okuma hem yazma yaplacak (dosya sfrlanr, yoksa yaratlr) dosyann sonuna ekleme yaplacak (dosya varsa sfrlanmaz, yoksa yaratlr) Fonksiyon ba³l§ndan da görülebilece§i gibi bu fonksiyon geriye açt§ dosya için bir i³aretçi döndürür, dosya üzerinde sonraki i³lemlerde bu i³aretçi kullanlacaktr. Ekleme kipinde açma d³ndaki kiplerde dosya açma i³lemi dosya i³aretçisini dosyann ba³na konumlandrr; yani ilk okuma ya da yazma dosyann ba³ndan yaplr. Dosya üzerindeki i³lemler bittikten sonra da dosyann kapatlmas gerekir. Bu amaçla bildirimi a³a§da verilmi³ olan fclose fonksiyonu kullanlr: int fclose(FILE *stream ); Bu fonksiyon parametre olarak verilen dosya i³aretçisinin gösterdi§i dosyay kapatr. Ba³arl olursa 0, ba³arsz olursa EOF de§erini döndürür. 148 Standart Giri³ / Çk³ Birimleri 8.4.2 Dosyada Okuma-Yazma Her okuma ya da yazma i³lemi i³aretçiyi okunulan ya da yazlan miktar kadar ilerletir; böylelikle pe³pe³e okuma i³lemleri dosyann srayla okunmasn sa§lar (yazma için de benzer ³e- fscanf ve fprintf fonksiyonlar kullanlabilir. Bu fonksiprintf fonksiyonlar ile ayndr; tek farklar ek olarak en ba³a kilde). Okuma-yazma i³lemleri için yonlarn kullanmlar scanf ve bir dosya i³aretçisi parametresi almalardr. Dosyadan ba³ka birimlerde okuma yapmak da istenebilir. Örne§in bir satrn bütün halinde okunmas amacyla gets fonksiyonuna benzer fgets fonksiyonu kullanlabilir. Bu fonksiyonun bildirimi ³u ³ekildedir: char *fgets(char *s, int size, FILE *stream ); Bu fonksiyon duklarn stream parametresi ile belirtilen dosyadan en fazla size - 1 simge okur ve oku- s parametresi ile belirtilen katara yazar. Satr sonu ya da dosya sonuna raslarsa daha NULL, ba³arl olursa s de§erini döndürür. Güvenlik açsndan fazla okumaz. Ba³arsz olursa gets fonksiyonu yerine bu fonksiyonun kullanlmas önerilir. Dosyadan tek bir simge okumak için fgetc fonksiyonu kullanlabilir. Bu fonksiyonun bildirimi ³u ³ekildedir: int fgetc(FILE *stream ); Bu fonksiyon stream parametresi ile belirlenen dosyadan okudu§u sradaki simgeyi bir tamsay olarak geri döndürür. Dosya sonuna gelinip gelinmedi§ini ö§renmek amacyla feof fonksiyonundan yararlanlr. Bu fonksiyon kendisine parametre olarak gönderilen dosya i³aretçisinin ilgili dosyann sonu olup olmad§n snar ve sona gelindiyse do§ru de§erini döndürür. 8.5 Standart Giri³ / Çk³ Birimleri Standart giri³, çk³ ve hata birimleri de birer dosya gibi davranrlar. Standart giri³ birimi stdin adnda önceden tanmlanm³ özel bir de§i³kende tutulur. Benzer ³ekilde standart çk³ için stdout, standart hata için de stderr de§i³kenleri tanmlanm³tr. Basit bir örnek verecek olursak printf(biçim katar, deyimler); komutu fprintf(stdout, biçim katar, deyimler); komutuyla ayn anlama gelir. Benzer ³ekilde a³a§daki ikisi de giri³ i³lemleri için e³de§erlidir: scanf(biçim katar, de§i³kenler); fscanf(stdin, biçim katar, de§i³kenler); 149 Giri³-Çk³ 8.6 Hata letileri Hata iletilerinin standart çk³ iletilerinden ayrlmasnn yararl bir al³kanlk oldu§u Bölüm 1.5'de söylenmi³ti. Bir C++ programnda bu i³lem iletinin cout de§il, cerr birimine yönlendirilmesiyle sa§lanabilir. Örnekte dosyalarn açlamamas durumunda görüntülenen iletilerde bu i³lem görülebilir: cerr < < Giri³ dosyas açlamad. < < endl; C dilinde ise cerr birimi olmad§ndan ayn i³lem a³a§daki komutla gerçekle³tirilmelidir: fprintf(stderr, .Giri³ dosyas açlamad.\n); Hata olu³tu§unda programn ne yapaca§ durumdan duruma de§i³ebilir. Düzeltilemeyecek bir hata olu³tuysa programlar exit fonksiyonuyla sonlandrlrlar. Bu fonksiyona EXIT_FAILURE de§eri gönderilirse programn ba³arsz sonland§ i³letim sistemine bildirilmi³ olur. Bu i³lemin return ile dönmeden fark hangi fonksiyondan ça§rlrsa ça§rlsn programn derhal sonlan- masdr; return ise yalnzca ça§ran fonksiyona dönü³ü sa§lar. Hata iletilerini standartla³trmak amacyla perror fonksiyonu tanmlanm³tr. Bu fonksiyon son olu³an hataya göre uygun bir mesaj standart hata birimine gönderir. Kullanmnda gelenek olarak hatann hangi fonksiyonda ortaya çkt§ belirtilir. Örnekte giri³ dosyas açlamad§nda cerr birimine yönlendirme yerine perror(main: giri³ dosyas açlamad); komutu kullanlsayd ve programn çal³trlmas srasnda belirtilen giri³ dosyas sistemde bulunamasayd çal³ma annda ³öyle bir ileti görünürdü: main: giri³ dosyas açlamad: No such file or directory 8.7 Katarlar ile Giri³-Çk³ Standart giri³-çk³ kitapl§ndaki sprintf ve sscanf fonksiyonlar ayn i³lemlerin katarlar printf ve scanf fonksiyonlarndan farklar, ilk pa- ile yaplmasn sa§lar. Bu fonksiyonlarn rametrelerinin okuma ya da yazma yaplacak katarlar belirtmeleridir. Örne§in dosyadan bir satr bütün olarak okuyup, üzerinde belki baz denetlemeler yaptktan sonra de§erlerin de§i³kenlere aktarlmas isteniyorsa fscanf ile do§rudan de§i³kenlere aktarmak yerine a³a§daki teknik kullanlabilir: // fp dosyasndan bir satr line katarna oku // ilk de§eri x tamsay de§i³kenine, // ikinci de§eri y kesirli de§i³kenine aktar fgets(line, fp); ... sscanf(line, %d %f, &x, &y); kili Dosyalar 150 sprintf fonksiyonu da çktnn ekrana baslmadan bir katarda olu³turulmas i³leminde yararl olur. Sözgelimi, x saysn strx katarna çevirmek için a³a§daki basit komut kullanlabilir: sprintf(strx, %d, x); 8.8 kili Dosyalar 'b' bayra§ fread, fwrite, fseek Uygulama: Dosyalar Örnek 33. Graarn Enlemesine Taranmas DÜZELT: YAZILACAK graf tip tanm: struct graph_s { int nodes; int adjacency[MAXNODES][MAXNODES]; }; typedef struct graph_s graph_t; okuma fonksiyonu bildirimi: void read_matrix(FILE *fp, graph_t &g); Sorular 1. Biti³iklik matrisini komut satrnda belirtilen bir dosyadan okudu§u grafn ba§lant matrisini Warshall algoritmas yardmyla hesaplayan bir program yazn. 151 Giri³-Çk³ Örnek 33 Bir graf enlemesine tarayan program (ana fonksiyon). int main(int argc, char *argv[]) { FILE *fp; graph_t graph; int vertices[MAXNODES]; bool visited[MAXNODES]; int start_vertex, next_vertex; int count, index, i; if (argc != 3) { cerr << "Kullanm: " << argv[0] << " matris_dosyas ba³langç_dü§ümü" << endl; return EXIT_FAILURE; } fp = fopen(argv[1], "r"); if (fp == NULL) { cerr << "Matris dosyas açlamad." << endl; exit(EXIT_FAILURE); } sscanf(argv[2], "%d", &start_vertex); read_matrix(fp, graph); for (i = 0; i < graph.nodes; i++) visited[i] = false; vertices[0] = start_vertex; visited[start_vertex] = true; count = 1; index = 0; while ((index < graph.nodes) && (count < graph.nodes)) { next_vertex = vertices[index]; for (i = 0; i < graph.nodes; i++) { if ((graph.adjacency[next_vertex][i] == 1) && (!visited[i])) { vertices[count] = i; visited[i] = true; count++; } } index++; } for (i = 0; i < graph.nodes; i++) cout << vertices[i] << endl; fclose(fp); return EXIT_SUCCESS; kili Dosyalar Örnek 34 Bir graf enlemesine tarayan program (matris okuma fonksiyonu). void read_matrix(FILE *fp, graph_t &g) { int c; int i = 0, j = 0; } fscanf(fp, "%d\n", &g.nodes); while (true) { c = fgetc(fp); if (c == EOF) break; if (c == '\n') { i++; j = 0; continue; } g.adjacency[i][j] = c - '0'; j++; } 152 Bölüm 9 Öni³lemci Bir C kaynak dosyasndan çal³trlabilir dosya olu³turulmas için geçilen a³amalar derleme ve ba§lama olarak belirtilmi³ti. Aslnda kaynak dosyas, derleyiciye verilmeden önce bir de öni³lemciden geçirilir. Öni³lemcinin yaptklar ³öyle özetlenebilir: • Açklamalar ayklar: /* ile */ arasnda kalan ya da // i³aretinden satr sonuna kadar olan bölümleri koddan siler; yani bu bölümler derleyiciye hiç gitmez. • Öni³lemci komutlarn i³ler: # simgesiyle ba³layan komutlar öni³lemci komutlardr ve öni³lemci tarafndan i³lenirler. En sk kullanlan öni³lemci komutlarn yeniden görelim: #dene De§i³mez ya da makro tanmlamakta kullanlr. Kodun içinde de§i³mezin adnn geçti§i her yere de§erini yazar. Sözgelimi yazan her yere 3.14 yazarak derleyiciye #define PI 3.14 öni³lemci komutu, kodda PI o haliyle gönderir; yani derleyici PI sözcü§ünü görmez. #include Belirtilen dosyay o noktada kodun içine ekler. Sözgelimi öni³lemci komutu, stdlib.h #include <stdlib.h> isimli dosyay bularak kaynak kodun içine yerle³tirir. Kod derleyiciye geldi§inde bu dosyann içeri§ini de barndrr. 9.1 Makrolar Programn içinde skça yinelenmesi gerekebilecek, ancak bir fonksiyon haline getirmeye de de§meyecek küçük kod parçalar makrolar yardmyla gerçeklenir. Makrolar da de§i³mez tanmlarna benzer ³ekilde #define sözcü§üyle yaplrlar. ³leyi³leri de yine de§i³mez tanmlarna benzer ³ekilde olur, yani makronun adnn geçti§i yere açlm konur. Örnek 13'de geçen sqr_total = sqr_total + (score[i] - mean) * (score[i] - mean); 153 154 Projeler komutunu basitle³tirmek üzere bir deyimin karesini alan #define sqr(x) (x) * (x) makrosunu kullanarak komutu ³u ³ekle getirebiliriz: sqr_total = sqr_total + sqr(score[i] - mean); Bunun sonucunda makro tanmndaki score[i] - mean x simgesinin yerine makronun kullandld§ yerdeki deyimi konur (programc kendisi bu ³ekilde yazm³ gibi). Bu i³lem bir sözcük ya da sözcük grubunun yerine ba³ka bir sözcük ya da sözcük grubunun yerle³tirilmesi ³eklinde yürüdü§ünden kullanmna dikkat etmek gerekir. Örnekteki makro #define sqr(x) x * x ³eklinde tanmlansayd makro açlmyla olu³acak (hatal) kod ³u ³ekilde olurdu: sqr_total = sqr_total + score[i] - mean * score[i] - mean; Örnek 35. Projeler Bir saynn asal çarpanlarnn ekrana dökülmesini ve iki saynn en büyük ortak bölen ve en küçük ortak katlarnn hesaplanmas i³lemlerini yapan bir program yazlmas isteniyor. Programn örnek bir çal³mas ekil 9.1'de verilmi³tir. Bu örnekte kaynak kodu birden fazla dosyaya bölünecek, kullancyla etkile³im ksmn yürüten fonksiyon (ayn zamanda siyonu) project.cpp dosyasna (Örnek 35), i³lemleri yapan fonksiyonlar (Örnek 36) konacaklardr. 9.2 1 ops.cpp main fonkdosyasna Projeler Yazlan programn kapsam büyüdükçe bütün kaynak kodunun tek bir dosyada toplanmas zorla³maya ba³lar. Binlerce satrlk bir kaynak kodunun tek bir dosyada tutularak program geli³tirilmesi son derece zordur. Böyle projelerde kaynak kodu farkl dosyalara bölünür. Birden fazla kaynak dosyasna bölünmü³ bir proje derlenirken önce her kaynak dosyas ayr ayr derlenerek ara kodlar olu³turulur, sonra ba§layc bu ara kodlar ve varsa kullanlan kitaplklar arasndaki ba§lantlar kurarak çal³trlabilir kodu üretir (ekil 9.3). Derleme süresi ba§lama süresinden çok daha uzun oldu§undan kaynak kodun bu ³ekilde bölünmesi çal³trlabilir dosyann üretilmesi için gereken zaman da azaltr. Tek bir büyük dosyadan olu³an projelerde herhangi bir yordamdaki herhangi bir de§i³iklikte bütün yordamlarn yeniden derlenmeleri ve ba§lanmalar gerekir. Oysa kaynak dosyalar bölünürse yalnzca de§i³tirilen 1 Bu örne§in nasl derlenece§ini Ek B.2'de görebilirsiniz. 155 Öni³lemci Say 1: 0 Say 2: 0 1. 2. 3. 4. 5. 6. Say 1'i de§i³tir Say 2'yi de§i³tir Say 1'in çarpanlarn göster En büyük ortak bölen bul En küçük ortak kat bul Çk Seçiminiz: 1 Sayy yaznz: 9702 Say 1: 9702 Say 2: 0 1. 2. 3. 4. 5. 6. Say 1'i de§i³tir Say 2'yi de§i³tir Say 1'in çarpanlarn göster En büyük ortak bölen bul En küçük ortak kat bul Çk Seçiminiz: 2 Sayy yaznz: 945 ekil 9.1: Proje örne§i ekran çkts. 156 Projeler Say 1: 9702 Say 2: 945 1. 2. 3. 4. 5. 6. Say 1'i de§i³tir Say 2'yi de§i³tir Say 1'in çarpanlarn göster En büyük ortak bölen bul En küçük ortak kat bul Çk Seçiminiz: 3 2^1 3^2 7^2 11^1 Say 1: 9702 Say 2: 945 1. 2. 3. 4. 5. 6. Say 1'i de§i³tir Say 2'yi de§i³tir Say 1'in çarpanlarn göster En büyük ortak bölen bul En küçük ortak kat bul Çk Seçiminiz: 4 En büyük ortak bölen: 1323 Say 1: 9702 Say 2: 945 1. 2. 3. 4. 5. 6. Say 1'i de§i³tir Say 2'yi de§i³tir Say 1'in çarpanlarn göster En büyük ortak bölen bul En küçük ortak kat bul Çk Seçiminiz: 5 En küçük ortak kat: 145530 Say 1: 9702 Say 2: 945 1. 2. 3. 4. 5. 6. Say 1'i de§i³tir Say 2'yi de§i³tir Say 1'in çarpanlarn göster En büyük ortak bölen bul En küçük ortak kat bul Çk Seçiminiz: 6 157 Öni³lemci Örnek 35 Giri³/çk³ fonksiyonlarn içeren kaynak dosyas. #include <iostream> #include <stdlib.h> #include "ops.h" // std::xxx // EXIT_SUCCESS // gcd,lcm,... int main(void) { int num1 = 0, num2 = 0; factor_t factors[MAXFACTOR]; int n, i; int choice; while (true) { std::cout << "Say 1: " << num1 << std::endl; std::cout << "Say 2: " << num2 << std::endl << std::endl; std::cout << "1. Say 1'i de§i³tir" << std::endl; std::cout << "2. Say 2'yi de§i³tir" << std::endl; std::cout << "3. Say 1'in çarpanlarn göster" << std::endl; std::cout << "4. En büyük ortak bölen bul" << std::endl; std::cout << "5. En küçük ortak kat bul" << std::endl; std::cout << "6. Çk" << std::endl << std::endl; std::cout << "Seçiminiz: "; std::cin >> choice; if (choice == 6) exit(EXIT_SUCCESS); switch (choice) { case 1: case 2: std::cout << "Sayy yaznz: "; if (choice == 1) std::cin >> num1; else std::cin >> num2; break; case 3: factorize(num1, factors, n); for (i = 0; i < n; i++) std::cout << factors[i].base << "^" << factors[i].power << " "; std::cout << std::endl; break; case 4: std::cout << "En büyük ortak bölen: " << gcd(num1, num2) << std::endl; break; case 5: std::cout << "En küçük ortak kat: " << lcm(num1, num2) << std::endl; break; } std::cout << std::endl; } return EXIT_SUCCESS; 158 Projeler Örnek 36 Hesap fonksiyonlarn içeren kaynak dosyas. #include <math.h> #include "ops.h" // sqrt,pow // struct factor_s #define max(x, y) (x) > (y) ? (x) : (y) #define min(x, y) (x) > (y) ? (x) : (y) void gcd_factors(const factor_t factors1[], int const factor_t factors2[], int factor_t factors[], int &n); void lcm_factors(const factor_t factors1[], int const factor_t factors2[], int factor_t factors[], int &n); n1, n2, n1, n2, int gcd(int number1, int number2) { ... } int lcm(int number1, int number2) { ... } bool is_prime(int cand) { ... } int next_prime(int prime) { ... } void factorize(int x, factor_t factors[], int &n) { ... } void gcd_factors(const factor_t factors1[], int n1, const factor_t factors2[], int n2, factor_t factors[], int &n) { ... } void lcm_factors(const factor_t factors1[], int n1, const factor_t factors2[], int n2, factor_t factors[], int &n) { 159 Öni³lemci derleme baglama kaynak kodu 1 ara kod 1 kaynak kodu 2 ara kod 2 kaynak kodu n ara kod n çalistirilabilir kod kitapliklar ekil 9.3: Birden fazla kaynak kodlu projelerin derleme a³amalar. yordamn bulundu§u kaynak dosyas yeniden derlenir ve ba§lama i³lemi yaplr; de§i³meyen kaynak kodlarnn yeniden derlenmelerine gerek kalmaz. Böyle bir çal³mada, dosyalardan yalnzca birinde main fonksiyonu bulunabilece§i açktr; aksi durumda ba§lama i³lemi belirsizlik nedeniyle ba³arsz olur. Ayrca farkl dosyalardaki fonksiyonlarn birbirlerini ça§rabilmeleri, dosyalar arasnda de§i³ken payla³abilmeleri gibi konular için baz düzenlemeler yapmak gerekir. Da§tmann yararl olabilmesi için fonksiyonlar, amaçlarna göre gruplanarak dosyalara bölünmelidir. Örnekte oldu§u gibi, kullancyla etkile³imi sa§layan (giri³/çk³ i³lemlerini yapan) fonksiyonlarn hesaplamalar yapan fonksiyonlarla ayr dosyalara toplanmas sk kullanlan bir bölümleme tekni§idir. Hesap i³lemlerini yapan factorize, gcd, lcm fonksiyonlar project.cpp dosyasnda bulunma- dklarndan bu dosyann derlenmesi srasnda sorun çkar. Derlenebilmesi için bu üç fonksiyonun bildirimleri dosya ba³na eklenmelidir. Bildirimler elle yazlabilir ancak daha do§ru olan yöntem, ops.cpp dosyasn bir kitaplk gibi dü³ünüp tanmlad§ fonksiyonlarn bildirimlerini içeren bir ba³lk dosyas hazrlamak ve bu ba³lk dosyasn di§er dosyann içine almaktr. Böy- ops.cpp ve ops.h dosyalar ba³ka projelerde de kullanlabilirler. Örnek projede ops.cpp dosyas için ops.h ba³lk dosyas hazrlanm³ (Örnek 37) ve bu dosya lelikle #include ops.h öni³lemci komutuyla her iki kaynak dosyasnn da içine alnm³tr. Burada <> simgeleri yerine simgeleri kullanlmas, öni³lemcinin ba³lk dosyasn sistem klasörlerinden önce bulunulan klasörde aramasn sa§lar. Ba³lk dosyas, ilgili kitapl§n arayüzüdür; ba³ka dosyalardaki fonksiyonlarn gerek duyabilecekleri bilgileri barndrr. Bir fonksiyon yalnzca o dosya içinde kullanlyorsa ve d³ardan 160 Projeler Örnek 37 Hesap fonksiyonlar için ba³lk dosyas. #ifndef OPS_H #define OPS_H #define MAXFACTOR 50 struct factor_s { int base, power; }; typedef struct factor_s factor_t; void factorize(int x, factor_t factors[], int &n); int gcd(int number1, int number2); int lcm(int number1, int number2); #endif fonksiyonlar tarafndan ça§rlmayacaksa (örnekteki next_prime ve is_prime fonksiyonlar gibi) bildirimi ba³lk dosyasna yazlmaz. Ba³lk dosyalar, fonksiyon bildirimlerinin d³nda, tip tanmlar da içerebilirler. Örnekte çarpanlar göstermek için kullanlan factor_t tipi project.cpp dosyasnda da gerek duyulan bir tip oldu§undan ba³lk dosyasna alnm³tr. Program bir saynn asal çarpanlarn listeleme i³ini yapmayacak olsayd, bu veri tipi ve factorize fonksiyonunun bildirimine project.cpp ops.cpp dosyasnda gerek kalmayaca§ için ba³lk dosyasna yazlmayabilirlerdi. Bu veri tipi dosyasnda da kullanld§ndan bu dosyann da ayn ba³lk dosyasn içermesi gerekir. Benzer ³ekilde, de§i³mez ve makro tanmlar da ba³lk dosyalarnda yer alabilir. Örnekte ana fonksiyon bir saynn asal çarpanlarn temsil etmek üzere statik bir dizi tanmlamaktadr. Bu dizinin eleman saysna kendisi karar verebilece§i gibi, di§er fonksiyonlarla uyum açsndan bu bilgiyi ba³lk dosyasndan almas daha uygundur. Ba³lk dosyalarnda yaplmamas gereken iki önemli i³lem vardr: • Fonksiyon tanmlamak: Ba³lk dosyalarna fonksiyonlarn yalnzca bildirimleri yazlr, gövdeleri yazlmaz. Bir ba³lk dosyas birden fazla C dosyas tarafndan alnabilece§inden ayn fonksiyonun birden fazla kere tanmlanmas ba§lama a³amasnda hataya neden olur. • De§i³ken tanmlamak: Benzer ³ekilde, ba³lk dosyasnda tanmlanan de§i³kenler birden fazla dosya tarafndan alnma durumunda ayn isimli genel de§i³kenler olarak de§erlendirilir ve ba§lama hatasna neden olurlar. Farkl dosyalar arasnda payla³lacak genel de§i³ken tanmlanmak isteniyorsa bu de§i³ken extern sakl sözcü§üyle bildirilmeli ve C kaynak dosyalarndan birinde normal biçimde tanmlanmaldr. Örne§in, ba³lk dosyasnda extern int counter; ³eklinde bildirilebilir ve dosyalardan biri int counter; komutuyla tanmlayabilir. ba³lk dosyasnda 161 Öni³lemci Sorular 1. x ← |y − z| (a) bir if i³lemini gerçekle³tirmek üzere komutu yazn. (b) bir makro tanm yazn. 2. Üç saynn harmonik ortalamas ³öyle tanmlanr: 3 1 x1 + 1 x2 + 1 x3 (a) Üç saynn harmonik ortalamasn hesaplamak üzere kullanlabilecek harmonic(x, y, z) makrosunun tanmn yaznz. (b) Yazd§nz makro b = harmonic(m - 1, n + 3, p); ³eklinde ça§rlrsa bu makronun açlm nasl olur? Projeler 162 Bölüm 10 Ba§lantl Listeler Örnek 38. En Büyük Ortak Bölen Bulma Örnek 23'de gerçeklendi§i ³ekliyle, en büyük ortak bölen bulma programnda bir saynn çarpanlar statik bir diziyle temsil ediliyordu. Bu örnekte statik dizi yerine dinamik dizi kullanmak bellek kullanmn etkinle³tirmek adna bir i³e yaramaz; çünkü dinamik dizilerde yaplan, eleman says belli olduktan sonra gerekti§i kadar yer ayrmaktr, oysa bu örnekte eleman says ancak çarpanlarna ayrma algoritmasnn sona ermesiyle sonra belli olur. Ba§lantl listeler, bu tip algoritmalarda dizilere göre daha uygun bir veri yapsdr. Bir ba§lantl liste, birbirinin e³i dü§ümlerden olu³ur; her dü§üm tutulmak istenen bilgileri ta³masnn yansra listede kendisinden sonra gelen dü§üme de bir i³aretçi içerir. Böylece listenin ba³ biliniyorsa sonraki dü§ümü gösteren alanlar üzerinden ilerlenerek bütün dü§ümlere eri³ilebilir. Listenin sonunu belirtmek üzere son dü§ümün sonraki alanna özel bir de§er (NULL) yazlr. Bu yapda, dizilerin aksine, eleman saysn tutmann gere§i yoktur. Örnek 38 ayn algoritmalar statik diziler yerine ba§lantl listeler üzerinde gerçekleyen bir programdr. Örnekteki ba§lantl liste yapsnn olu³turulmas için kullanlan yap tanm ³öyledir: struct factor_s { int base, power; struct factor_s *next; }; typedef struct factor_s factor_t; Görüldü§ü gibi, bir dü§ümde asal çarpann de§eri ve üssüne ek olarak dü§ümün kendi tipine i³aret eden bir i³aretçi alan vardr. Böyle bir yap üzerinde i³lem yapmak için tek gerekli de§i³ken dizinin ilk elemanna i³aret eden bir de§i³ken tutmaktr, örnekteki head de§i³ken- leri bu amaçla tanmlanm³tr. Listeye ekleme algoritmalarnda kolaylk sa§lamas için bir de listenin son dü§ümünü (next alannda NULL yazan dü§üm) gösteren bir de tail de§i³keni kullanlm³tr. Bu tanma göre olu³turulan ba§lantl listelerde 9702 saysnn çarpanlarnn nasl gösterildi§i ekil 10.1'de verilmi³tir. 163 164 Örnek 38 Ba§lantl listeler kullanarak en büyük ortak bölen hesaplayan program (ana fonksiyon). int main(void) { int number1, number2; factor_t *factors1 = NULL, *factors2 = NULL, *factors3 = NULL; long int gcd = 1L; factor_t *f = NULL; } cout << "Saylar yaznz: "; cin >> number1 >> number2; factors1 = factorize(number1); factors2 = factorize(number2); factors3 = gcd_factors(factors1, factors2); for (f = factors3; f != NULL; f = f->next) gcd = gcd * (long int) pow((double) f->base, (double) f->power); delete_factors(factors1); delete_factors(factors2); delete_factors(factors3); cout << "En büyük ortak bölen: " << gcd << endl; return EXIT_SUCCESS; tail head 2 3 7 11 1 2 2 1 ekil 10.1: Ba§lantl liste örne§i. 165 Ba§lantl Listeler Bu veri yaps kullanld§nda bir sayy asal çarpanlarna ayran fonksiyonun giri³ parametresi olarak yalnzca asal çarpanlarna ayrlacak sayy almas ve çk³ parametresi olarak olu³turdu§u çarpanlar listesinin ba³langç elemann döndürmesi yeterlidir: factor_t *factorize(int x); Benzer ³ekilde, ortak çarpanlar bulma algoritmas da iki çarpan listesini alarak ortak çarpanlar listesini döndürür: factor_t *gcd_factors(factor_t *factors1, factor_t *factors2); Ba§lantl listeler dinamik olarak olu³turulduklarndan i³leri bitti§inde sisteme geri verilmeleri gerekir. Bu amaçla tanmlanan delete_factors fonksiyonu ilk dü§ümüne i³aretçi ald§ bir listenin bütün dü§ümlerini sisteme geri verir. Burada head i³aretçisi o anda geri veri- lecek dü§ümün adresini tutarken p i³aretçisi bir sonraki dü§ümün unutulmamasn sa§lar. Bu fonksiyon ³öyle yazlabilir: void delete_factors(factor_t *head) { factor_t *p = NULL; } while (head != NULL) { p = head->next; delete head; head = p; } Örnek programda kullanlan di§er fonksiyonlar olan factorize ve gcd_factors fonksiyonlar srasyla Örnek 39 ve Örnek 40'de verilmi³tir. 10.1 Yaplara ³aretçiler Bir yapya i³aret eden bir de§i³ken tanmland§nda bu yapnn alanlarna eri³mek için -> i³leci kullanlr. Örnekte ortak çarpanlardan en büyük ortak bölenin hesapland§ döngüdeki f->base yazm buna bir örnektir. Bunun yerine önce * ile i³aretçinin ba³vurdu§u yere eri³ilip daha sonra noktal gösterilimle istenen alann de§eri de alnabilir: (*f).base gibi. Ancak bu ikinci gösterilim pek ye§lenmez. Uygulama: Ba§lantl Listeler Bu örnekte, Örnek 30'de yaplan ortade§er bulma program seçerek sralama algoritmas yerine araya sokarak sralama algoritmasyla gerçeklenecektir. Yaplara ³aretçiler 166 Örnek 39 Ba§lantl listeler kullanarak en büyük ortak bölen hesaplayan program (asal çarpanlara ayrma fonksiyonu). factor_t *factorize(int x) { factor_t *head = NULL, *tail = NULL, *f = NULL; int factor = 2; } while (x > 1) { if (x % factor == 0) { f = new factor_t; f->base = factor; f->power = 0; while (x % factor == 0) { f->power++; x = x / factor; } f->next = NULL; if (head == NULL) head = f; if (tail != NULL) tail->next = f; tail = f; } factor = next_prime(factor); } return head; 167 Ba§lantl Listeler Örnek 40 Ba§lantl listeler kullanarak en büyük ortak bölen hesaplayan program (ortak çarpanlar bulma fonksiyonu). factor_t *gcd_factors(factor_t *factors1, factor_t *factors2) { factor_t *factors = NULL, *head = NULL, *tail = NULL, *p = NULL; } while ((factors1 != NULL) && (factors2 != NULL)) { if (factors1->base < factors2->base) factors1 = factors1->next; else if (factors1->base > factors2->base) factors2 = factors2->next; else { factors = new factor_t; factors->base = factors1->base; factors->power = min(factors1->power, factors2->power); factors->next = NULL; if (head == NULL) head = factors; if (tail != NULL) tail->next = factors; tail = factors; factors1 = factors1->next; factors2 = factors2->next; } } return head; Yaplara ³aretçiler 168 Örnek 41. Araya Sokarak Sralama Araya sokarak sralama algoritmas, temel sralama yöntemlerinden biridir. Bu yöntemde, her yeni gelen eleman o ana kadar gelen elemanlara göre sral olacak ³ekilde yerine yerle³tirilir. Örne§in 45, 22, 91, 18, 62 saylar sralanacaksa ³u ³ekilde ilerlenir: 45 22 22 18 18 45 45 91 22 45 91 22 45 62 91 Bu yöntem statik diziler üzerinde gerçeklenmeye uygun de§ildir çünkü her yeni gelen eleman eklendi§inde ondan büyük olan bütün elemanlarn bir konum sa§a kaydrlmalar gerekir. Örnekte 18 says dizinin en ba³na eklenece§inden üç elemann birden sa§a kaydrlmasna neden olur. Oysa bu algoritma ba§lantl listeler üzerinde gerçeklenmeye gayet uygundur. Örnek 41'de bir diziyi sral bir ba§lantl listeye çeviren program verilmi³tir. • Ekleme i³lemini yapan fonksiyonu ³u durumlar için inceleyin: liste bo³ eleman en ba³a ekleniyor eleman en sona ekleniyor eleman arada bir yere ekleniyor • assert • core dump 169 Ba§lantl Listeler Örnek 41 Ba§lantl liste üzerinde araya sokarak sralama program (ana fonksiyon). #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; struct node_s { int value; struct node_s *next; }; typedef struct node_s node_t; node_t *insertsort(int *numbers, int count); void delete_nodes(node_t *head); int main(void) { int *score = NULL; node_t *head = NULL, *f = NULL; float median; int no_students, i; cout << "Ö§renci says: "; cin >> no_students; score = new int[no_students]; for (i = 0; i < no_students; i++) { cout << i + 1 << ". ö§rencinin notu: "; cin >> score[i]; } head = insertsort(score, no_students); f = head; for (i = 0; i < no_students / 2 - 1; i++) f = f->next; median = (no_students % 2 == 1) ? f->next->value : (f->value + f->next->value) / 2.0; cout << "Orta de§er: " << median << endl; delete_nodes(head); } delete score; return EXIT_SUCCESS; Yaplara ³aretçiler Örnek 42 Ba§lantl liste üzerinde araya sokarak sralama program (liste fonksiyonlar). node_t *insert(node_t *head, int v) { node_t *p = head, *newnode = NULL, *last = NULL; } newnode = new node_t; newnode->value = v; while ((p != NULL) && (p->value < v)) { last = p; p = p->next; } newnode->next = p; if (last == NULL) return newnode; last->next = newnode; return head; node_t *insertsort(int *numbers, int count) { node_t *head = NULL; int i; } for (i = 0; i < count; i++) head = insert(head, numbers[i]); return head; void delete_nodes(node_t *head) { node_t *p = NULL; } while (head != NULL) { p = head->next; delete head; head = p; } 170 Bölüm 11 Rekürsiyon ki saynn en büyük ortak bölenini bulmak üzere kulland§mz Euclides algoritmas, a ile b saylarnn en büyük ortak böleni b ile a % b saylarnn en büyük ortak bölenine e³ittir ilkesine dayanyordu. Problemin çözümünün, bu örnekte oldu§u gibi, kendisi cinsinden ifade edilmesine rekürsif tanm ad verilir. Çözülmesi istenen problem, kendisi cinsinden daha küçük bir probleme indirgenir. Sürekli indirgemeler yoluyla çözümü bilinen bir duruma (taban durum) ula³lmaya çal³lr. Euclides algoritmasnda taban durum küçük olan saynn 0'a gelmesi durumuydu; bu durumda di§er say en büyük ortak bölen oluyordu. Aksi halde daha küçük saylar üzerinde en büyük ortak bölen aranmaya devam ediliyordu. Bu ilkeyi gerçekleyen bir fonksiyon ³u ³ekilde yazlabilir: int gcd(int a, int b) { if (b == 0) return a; else return gcd(b, a % b); } Rekürsiyona en çok verilen örneklerden biri de faktöryel hesaplanmasdr. Rekürsif olarak faktöryel hesaplayan bir fonksiyon ³öyle yazlabilir: int factorial(int x) { if (x == 0) return 1; else return x * factorial(x - 1); } Bu iki örnek, C gibi blok yapl dillerde rekürsif gerçeklenmeye uygun örnekler de§ildir; çünkü yinelemeli olarak gerçeklendiklerinde daha etkin çal³rlar. Rekürsif yazm bazen daha güzel görünse ve matematikteki tanma daha yakn olsa da, ba³arm açsndan dezavantajl olabilir. 171 172 Örnek 43. Hanoi Kuleleri Hanoi kuleleri probleminde 3 adet direk ve 64 adet ortas delik disk vardr. Diskler ba³langçta birinci dire§e geçirilmi³ durumdadr. Çap en geni³ olan disk en altta, en dar olan en üstte yer alr ve her disk kendisinden daha geni³ çapl bir diskin üzerinde durur. Amaç, diskleri teker teker direkler arasnda ta³yarak ayn düzeni üçüncü direkte olu³turmaktr. Burada kural, hiçbir diskin hiçbir a³amada kendisinden dar bir diskin üzerine konamamasdr. ekil 11.1'de üç direk ve üç diskli örnek verilmi³tir. Bu örne§in çözümünü yapan programn çkts ekil 11.2'de verilmi³tir. A B C ekil 11.1: Hanoi kuleleri problemi ba³langç durumu. Hanoi kuleleri probleminin genel çözümünü olu³turmaya en geni³ çapl diskin nasl ta³naca§n dü³ünmekle ba³layalm. Bu disk ba³ka hiçbir diskin üstüne konamayaca§ için üçüncü diske ba³ka bir direk üzerinden aktarlarak geçemez, bir kerede götürülmelidir. Bunun yaplabilmesi için birinci diskte kendisinden ba³ka disk bulunmamal, üçüncü disk de bo³ olmaldr (ekil 11.3). Bu durumda çözüm üç a³amal olarak görülebilir: 1. Dar 63 diski birinci diskten ikinci diske ta³. 2. En geni³ diski birinci diskten üçüncü diske ta³. 3. Dar 63 diski ikinci diskten üçüncü diske ta³. Birinci ve üçüncü admlardaki ta³ma i³lemi aslnda 63 disk için ayn problemin çözülmesinden ba³ka bir ³ey de§ildir. O halde problemimizi n diskin a dire§inden b dire§ine c dire§i üzerinden ta³nmas ³eklinde ifade ederek çözümü ³u ³ekilde yazabiliriz: Bir Bir Bir Bir Bir Bir Bir diski diski diski diski diski diski diski 1 1 3 1 2 2 1 dire§inden dire§inden dire§inden dire§inden dire§inden dire§inden dire§inden 3 2 2 3 1 3 3 dire§ine dire§ine dire§ine dire§ine dire§ine dire§ine dire§ine ta³. ta³. ta³. ta³. ta³. ta³. ta³. ekil 11.2: Hanoi kuleleri problemini çözen programn ekran çkts. 173 Rekürsiyon A C B ekil 11.3: Hanoi kuleleri problemi (en geni³ diskin ta³nmas). 1. n - 1 2. a 3. n - 1 diski a dire§inden dire§inde kalan diski diski c b dire§inden c dire§ine b dire§i üzerinden ta³. dire§ine ta³. b dire§ine a dire§i üzerinden ta³. Her seferinde direk says azald§ndan bu algoritma sonlanma ko³ulunu sa§lar. Taban durum, ta³nacak disk saysnn 0 oldu§u durumdur, bu durumda hiçbir ³ey yaplmayacaktr. O halde bu problemi çözen program Örnek 43'de görüldü§ü gibi yazlabilir. Bu algoritmann en güzel yanlarndan biri, deneme-yanlma yöntemiyle de§il, herhangi bir diski gereksiz yere bir direkten bir dire§e aktartmadan bir kerede çözümü bulmasdr. Uygulama: Rekürsiyon Örnek 44. Çabuk Sralama DÜZELT: YAZILACAK Sorular 174 Örnek 43 Hanoi kuleleri problemini çözen program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; #define DISKS 3 void move(int n, int a, int b, int c); int main(void) { move(DISKS, 1, 3, 2); return EXIT_SUCCESS; } void move(int n, int a, int b, int c) { if (n > 0) { move(n - 1, a, c, b); cout << "Bir diski " << a << " dire§inden " << b << " dire§ine ta³." << endl; move(n - 1, c, b, a); } } 175 Rekürsiyon Örnek 44 Çabuk sralama algoritmasn gerçekleyen program. #include <iostream> #include <stdlib.h> // cin,cout,endl // EXIT_SUCCESS using namespace std; void quicksort(int arr[], int first, int last); int main(void) { int numbers[] = { 26, 33, 35, 29, 19, 12, 22 }; int i; } quicksort(numbers, 0, 6); for (i = 0; i < 7; i++) cout << numbers[i] << endl; return EXIT_SUCCESS; void swap(int &x, int &y) { int tmp; } tmp = x; x = y; y = tmp; int partition(int arr[], int first, int last) { int pivotloc = first; int pivot = arr[first]; int i; } for (i = first + 1; i <= last; i++) { if (arr[i] < pivot) { pivotloc++; swap(arr[pivotloc], arr[i]); } } swap(arr[first], arr[pivotloc]); return pivotloc; void quicksort(int arr[], int first, int last) { int pivotloc; if (first < last) { pivotloc = partition(arr, first, last); quicksort(arr, first, pivotloc - 1); quicksort(arr, pivotloc + 1, last); 176 Ek A Simgelerin Kodlanmas Bilgisayarlarda di§er her ³ey gibi simgeler de saylarla gösterilirler. Bunun için hangi simgenin hangi sayyla gösterilece§i (ya da tersine, hangi saynn hangi simgeye kar³ dü³ece§i) konusunda bir uzla³ma olmas gerekir. Bu amaçla tanmlanan kodlamalar, simgelere birer numara verirler. Yaygn kullanlan ilk kodlamalardan biri ASCII kodlamasyd (ekil A.1). ASCII, 7 bitlik bir kodlama oldu§undan 128 farkl simgenin kodlanmasna olanak verir. lk kodun numaras 0, son kodun numaras 127'dir. Bunlardan ilk 32 simge (0-31) ve son simge (127) baslamaz simgelerdir (satr sonu, bip sesi v.b.). Aradaki 95 simgeyse (32-126) ngilizce'nin bütün küçük ve büyük hareri, rakamlar, noktalama i³aretleri ve tu³takm üzerinde gördü§ünüz her türlü özel simgeyi içerir. ASCII kodlamas günümüzde kullanlan bütün kodlamalarn temelini olu³turur. 32 40 48 56 64 72 80 88 96 104 112 120 +0 +1 +2 +3 +4 +5 +6 +7 ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ Tablo A.1: ASCII kodlama çizelgesi. ASCII kodlamas, ngilizce d³nda kalan abecelerin harerini içermedi§inden, her dil için o dilde bulunan farkl simgeleri de içeren 8 bitlik kodlamalar olu³turulmu³tur; böylelikle 256 farkl simgenin kodlanmasna olanak sa§lanm³tr. Bütün bu kodlamalarda ilk 128 simge 177 178 ASCII çizelgesinde olann aynsdr, düzenlemeler ikinci 128 simge üzerinde yaplr. Bu kodlamalarn en bilineni ISO8859 standart ailesinde tanmlananlardr. ISO8859 kodlamalarnda da 128-159 aras saylar kullanlmaz. • ISO8859-1: Bat Avrupa dilleri (latin1 kodlamas adyla da bilinir) • ISO8859-2: Do§u Avrupa dilleri • ISO8859-9: Türkçe (latin5 kodlamas adyla da bilinir). ISO8859-1 kodlamasyla neredeyse ayndr, yalnzca ISO8859-1'deki zlandaca harerin yerine Türkçe harerin gelmesiyle olu³turulmu³tur. ki kodlama arasnda de§i³en 6 simge ³unlardr: § ³. Son yllarda, farkl diller konu³an, farkl ülkelerde ya³ayan insanlarn ortak kullandklar uygulamalarn says çok büyük bir hzla artt§ndan, bütün dillerin bütün simgelerini içeren bir kodlamaya geçmek bir zorunluluk halini alm³tr. Bu amaçla geli³tirilen Unicode kodlamas (resmi adyla ISO10646-1), 16 ve 32 bitlik sürümleri olan bir kodlamadr. Yeryüzünde bilinen bütün dillerin simgelerini içermenin yansra daha pek çok ek simgenin tanmlanabilmesine de olanak verir. Ancak bütünüyle bu kodlamaya geçmek için yaygn kullanlan bütün programlarda büyük miktarlarda de§i³iklik gerekecektir. Bu nedenle, yeni yazlan uygulamalarda bu kodlamann yaln hali olan UTF-16 ya da UTF-32 kodlamalarna uyulmas öngörülürken, kullanm süren eski uygulamalarla uyum sorununu azaltmak için bir geçi³ kodlamas olarak UTF-8 geli³tirilmi³tir. Bir de§erin bilgisayar belle§inde bir göze ham bir veri olarak yazld§ dü³ünülebilir. Sözgelimi, bir bellek gözünde 240 says yer alyor olsun. Program bu gözü bir tamsay olarak de§erlendirirse 240 de§erini elde eder ve diyelim bu sayy ba³ka bir say ile toplayabilir. ISO8859-9 kodlamasnda bir simge olarak de§erlendiriyorsa '§' harni elde eder ve Türkçe kurallarna göre sralama yapmada kullanabilir. ISO8859-1 kodlamasnda bir say olarak de§erlendiriyorsa harni elde eder ve zlandaca kurallarna göre sralamada kullanabilir. Ksacas, de§er bellekte ham haliyle bulunur; nasl anlam verilece§i, ne amaçla kullanlaca§ programn belirleyece§i konulardr. Ek B Unix'de Program Geli³tirme B.1 Yardmc Belgeler Unix i³letim sistemlerinde ço§u zaman man fonksiyon komutuyla o fonksiyonla ilgili bilgi alabilirsiniz. Bu komut fonksiyonun ne i³ yapt§n ve hangi ba³lk dosyasnda yer ald§n söyleyecektir. Örnek: man sqrt. info KDE: Konqueror ya da Alt-F2 #sqrt B.2 Derleme Unix ailesi i³letim sistemlerinde C/C++ dilinde geli³tirme yapmak için en çok GNU C Compiler (gcc) derleyicisi kullanlr. Temel kullanm ³öyledir: gcc kaynak_dosyas -o çal³trlabilir_dosya Kaynak dosyanz bir C++ koduysa g++ kaynak_dosyas -o çal³trlabilir_dosya komutuyla çal³trmanz gerekir. Bu komutun sonucunda kaynak dosya derlenir, ba§lanr ve ismi verilen çal³trlabilir dosya olu³turulur. Derleyici ba³lk dosyalarn /usr/include, kitaplk dosyalarnysa /usr/lib kataloglarnda arar. Derleyicinin çal³mas baz bayraklar yardmyla denetlenebilir. A³a§daki örneklerde kaynak dosyasnn adnn da main • main.cpp, hedef dosya adnn main.o, çal³trlabilir dosya adnn oldu§u varsaylrsa: Kaynak dosyay yalnz derlemek istiyorsanz, yani ba§lamak istemiyorsanz kullanabilirsiniz: 179 -c bayra§n 180 Derleme g++ main.cpp -c -o main.o • Derleyicinin bütün uyarlarlarn görmek istiyorsanz -Wall bayra§n kullanabilirsiniz: g++ main.cpp -Wall -o main • Ba³ka kataloglarda da ba³lk dosyas aramasn istiyorsanz -I bayra§yla bunu belirte- bilirsiniz: g++ main.cpp -I/usr/X11R6/include -o main • Ba³ka kataloglarda da kitaplk aramasn istiyorsanz -L bayra§yla bunu belirtebilirsiniz: g++ main.cpp -I/usr/X11R6/include -L/usr/X11R6/lib -o main • Optimizasyon: -O2 Birden fazla kaynak dosyasndan olu³an bir projenin derlenmesi birkaç a³amal olur. Örnek 35 üzerinde bir projenin nasl derlenece§ini görelim: • project.cpp dosyasn derle (ba§lamadan): g++ -c project.cpp -o project.o • ops.cpp dosyasn derle (ba§lamadan): g++ -c ops.cpp -o ops.o • ba§la g++ project.o ops.o -o project Kaynak dosyalarnn herhangi birinde bir de§i³iklik yaplrsa yalnzca o dosyann yeniden derlenmesi ve ba§lama yeterlidir. Her seferinde elle derleme komutlarn yazmak zahmetli bir i³ oldu§undan derleme i³lemlerini kolayla³trmak için make arac kullanlr. Bu araç, programcnn yazd§, derleme a³amalarn belirten Makefile isimli bir dosya denetiminde çal³r. Makefile dosyas hedeerden olu³ur. Her hedef için heden nelere ba§l oldu§u ve nasl olu³turulaca§ belirtilir. Örnek bir hedef ³öyle yazlabilir: project: project.o ops.o g++ project.o ops.o -o project Bu yazmn anlam, project hedenin project.o ve ops.o dosyalarna ba§l oldu§u ve olu³- turulmas için ikinci satrda yazlan komutun kullanlaca§dr. 1 Bir heden ba§l oldu§u dos- yalarda de§i³me olursa (dosyann tarih ve saati hedenkinden yeniyse) heden yeniden olu³turulmas gerekti§ine karar verilir. Örnek projedeki di§er hedeer de ³öyle yazlabilir: 1 Hede olu³turmakta kullanlacak komutlar satr ba³ndan bir sekme içeriden ba³lamaldr. Bir hede olu³- turmakta birden fazla komut kullanlabilir. 181 Unix'de Program Geli³tirme project.o: project.cpp g++ -c project.cpp -o project.o ops.o: ops.cpp g++ -c ops.cpp -o ops.o make komutu çal³trlrken hangi heden olu³turulmasnn istendi§i belirtilir. Hedef belirtil- mezse dosyada bulunan ilk hedef olu³turulmaya çal³lr. Ba³langçta project dosyalarnn hiçbirinin olmad§n varsayarsak, make project project.o, ops.o ve komutunun çal³mas ³öyle olur: 1. project hede olu³turulmaya çal³lr. Bu hedef project.o ve ops.o hedeerine ba§l oldu§u için ve bunlar henüz olu³turulmam³ oldu§u için srayla bunlar olu³turulmaya çal³lr. 2. project.o hede olu³turulmaya çal³lr. Bu hedef project.cpp dosyasna ba§l oldu§u için olu³turulmasna geçilebilir ve g++ -c project.cpp -o project.o komutu yürütülür. 3. ops.o hede olu³turulmaya çal³lr. Bu hedef ops.cpp dosyasna ba§l oldu§u için olu³turulmasna geçilebilir ve g++ -c ops.cpp -o ops.o komutu yürütülür. 4. Artk project hedenin ba§l oldu§u iki dosya da olu³mu³ oldu§undan bu heden olu³- turulmasna geçilebilir ve g++ project.o ops.o -o project komutu yürütülür. leride ops.cpp dosyasnda bir de§i³iklik yapld§n ve make project komutunun yürütüldü- project.o ops.o §ünü dü³ünelim: 1. project hede olu³turulmaya çal³lr. Bu hedef ve hedeerine ba§l oldu§u için önce onlara baklr. 2. project.o hede olu³turulmaya çal³lr. Bu hedef project.cpp dosyasna ba§ldr ancak project.cpp dosyasnn saati project.o dosyasndan eski oldu§u için bir i³lem yaplmaz. 3. ops.o hede olu³turulmaya çal³lr. Bu hedef dosyasnn saati ops.o ops.cpp dosyasna ba§ldr ve ops.cpp dosyasndan yeni oldu§u için heden yeniden olu³turulmas ge- rekti§ine karar verilir ve 182 Editörler g++ -c ops.cpp -o ops.o komutu yürütülür. 4. project hedene dönüldü§ünde ops.o dosyasnn saati artk project dosyasnn sa- atinden yeni oldu§u için bu heden de yeniden olu³turulmas gerekti§ine karar verilir ve g++ project.o ops.o -o project komutu yürütülür. Makefile dosyalarnda ayrca baz de§i³mezler tanmlanarak okunulurluk ve esneklik artrla- bilir. Örnek proje için yazlm³ bir Makefile Örnek 45'de verilmi³tir. Bu dosya skça kullan- lan, kaynak dosyalar d³nda kalan her ³eyi silen clean hedeni de içermektedir; make clean komutu sizin yazd§nz d³nda kalan bütün dosyalarn silinmesi için kullanlr. Örnek 45 Örnek bir Makefile dosyas. CXX=g++ CXXFLAGS=-O2 -Wall -g -pg LDFLAGS=-pg proje: proje.o ops.o $(CXX) $(LDFLAGS) proje.o ops.o -o proje proje.o: proje.cpp $(CXX) $(CXXFLAGS) -c proje.cpp -o proje.o ops.o: ops.cpp $(CXX) $(CXXFLAGS) -c ops.cpp -o ops.o clean: rm -f *.o proje Öni³lemci: cpp B.3 Editörler nedit kate mcedit: yazm renklendirme, ayraç e³le³tirme, makrolar, tab emülasyonu, kendili§inden girintileme B.4 Hata Ayklayclar Çal³trlabilir dosya üzerinde hata ayklama yapacaksanz -g bayra§n kullanmalsnz: 183 Unix'de Program Geli³tirme g++ main.cpp -g -o main Hata ayklama bilgilerini silmek için -s strip gdb ddd: adm adm çal³trma, de§i³ken de§erlerini izleme ³aretçilerle çal³rken yaplan hatalar sklkla programn çökmesine ve o anki bellek görüntüsünün bir dosyaya yazlmasna neden olurlar (core dump). Bu bellek görüntüsü programnzn neden çöktü§üne ili³kin önemli bilgiler içerir ve hatann nedenini bulmanza yardmc olabilir. Örnek 39'de if (x % factor == 0) { satrndan sonraki f = new factor_t; komutunu silerek program derleyin ve çal³trn. Program bellek hatas vererek çökecektir. ddd hata ayklaycsnda önce Open Program komutuyla çal³trlabilir dosyay, sonra da Open Core Dump... komutuyla yaratlan core dosyasn açn. Programn çöktü§ü anda f->base = factor; satrnda kald§n ve B.5 f i³aretçisinin de§erinin NULL oldu§unu göreceksiniz. Ba³arm nceleme Programnzdaki fonksiyonlarn kaçar kere ça§rldklarn ve hangi fonksiyonda ne kadar zaman harcand§n ölçmek için gprof aracn kullanabilirsiniz. gprof 'un kullanlabilmesi için gcc/g++ derleyicisine hem derleme hem ba§lama a³amasnda -pg bayra§ verilmelidir. Örnek 23'de hangi fonksiyonun kaç kere ça§rld§n görmek için: g++ -pg lcm.cpp -o lcm komutuyla program derlendikten sonra çal³trlr ve en küçük ortak kat hesaplanmak istenen de§erler girilir. Bu çal³ma sonucunda gmon.out isimli bir dosya olu³ur ve gprof lcm gmon.out komutu programn çal³masyla ilgili bir rapor üretir. 32424 ve 563324 de§erlerinin girilmesiyle olu³an örnek bir raporun baz bölümleri a³a§da verilmi³tir: % cumulative self self total time seconds seconds calls us/call us/call 95.24 0.20 0.20 70516 2.84 2.84 4.76 0.21 0.01 2 5000.00 105000.00 0.00 0.21 0.00 13127 0.00 15.24 0.00 0.21 0.00 1 0.00 0.00 name is_prime factorize next_prime merge_factors