1. Skip to Menu
  2. Skip to Content
  3. Skip to Footer>

Nöbetçi Kontrollü Döngü

PDF Yazdır e-Posta

Written by Admin

Posted on 07 Eylül 2010

Son Güncelleme 07 Eylül 2010

DURUM 2 (NÖBETÇİ KONTROLLÜ DÖNGÜLER)

Ortalama problemimizi genelleştirelim.Aşağıdaki problemi inceleyiniz:
Program çalıştırıldığında, kaç kişinin ortalamasının hesaplanacağını önceden bilmeden, sınıf ortalamasını bulacak bir program geliştirin.
İlk sınıf ortalaması örneğinde, notların sayısını (10) başlangıçta biliyorduk. Bu örneğimizde ise kaç not girileceğini başlangıçta bilmiyoruz. Program, herhangi bir sayıda veriyi işlemek zorundadır. Bu durumda, programımız notların girişinin sonlandığına nasıl karar verecektir? Sınıf ortalamasını ne zaman hesaplayacağını ve yazdıracağını nasıl bilecektir?

Bu problemi çözmenin yolu, veri girişinin sonlandığını belirten bir özel değer, nöbetçi değer, ( sinyal değer ve ya işaretçi değer de denir) kullanmaktır. Kullanıcı, girmesi gereken tüm verileri girdikten sonra son değeri girdiğini belirten bir nöbetçi değer girer. Nöbetçi kontrollü döngüler, genelde belirsiz döngüler olarak adlandırılır çünkü döngü çalışmaya başlamadan önce döngünün kaç kez tekrarlanacağı bilinmemektedir.

Nöbetçi değer, kabul edilebilir herhangi bir giriş değeriyle karıştırılmayacak biçimde seçilmelidir. Not değerleri genellikle pozitif tamsayılar olduğundan, -1 bu örnek için uygun bir nöbetçi değer olabilir. Böylece sınıf ortalama programı, 95,96,75,74,89 ve –1 gibi verileri işleyecektir. Program, sınıf ortalamasını 95,96,75,74 ve 89 notları için hesaplayacak ve ortalamayı yazdıracaktır.( -1 nöbetçi değerdir, bu sebepten ortalama hesabına katılmamalıdır.)

    Genel Programlama Hataları 3.6
    Veri olabilecek bir değeri nöbetçi değer seçmek.

Bu sınıf ortalama problemine, iyi yapısal programlar geliştirmek için ihtiyaç duyduğumuz ve yukarıdan-aşağıya adımsal iyileştirme adını verdiğimiz bir teknikle yaklaşacağız. Bunun için en yukarıya yapmak istediğimiz işin sahte kodunu yazalım.

Bu sınav için sınav ortalamasını belirle.

En yukarıya yazdığımız bu kod, tüm program için geçerli olacak ve tüm programın tanıtıcısı konumunda bulunacaktır. Ancak çok az durumda, en yukarıya yazdığımız bu sahte kod bir C programı yazmak için yeterli detaya sahiptir. Bu yüzden, süreci iyileştirmeye başlayacağız. Bunun için, yukarıdaki kodu daha küçük görevlere bölüp, bu görevlerin hangi sırada yapılacağını listeleyeceğiz. İlk iyileştirmemiz şu biçimde yapılabilir :

Değişkenleri belirle.
Notları gir,topla ve say.
Sınıf ortalamasını hesapla ve yazdır.

Burada yalnızca dizi yapısı kullanılmıştır ; adımlar çalıştırılacakları sırada birbiri ardına sıralanmıştır.

    Yazılım Mühendisliği Gözlemleri 3.3
    Her iyileştirme algoritmanın bütünleştirilmesidir; yalnızca detay seviyeleri değişmektedir.

Bir sonraki iyileştirme seviyesinde (ikinci iyileştirmemizde), bazı değişkenleri belirtmeliyiz. Sayıların toplamına, kaç sayının işlendiğini bilmemize, her notun değerini girdi olarak alacak bir değişkene ve hesaplanan ortalamayı tutacak bir değişkene ihtiyaç duyacağız.

Değişkenleri belirle

sahte kodunu

toplam değişkenini sıfır olarak belirle
sayıcı değişkenini sıfır olarak belirle

biçiminde iyileştirebiliriz.

Yalnızca toplam ve sayıcıya ilk değer atanması gerektiğine dikkat ediniz ; ortalama ve not değişkenleri için (sırasıyla hesaplanmış ortalama ve kullanıcı girişi için kullanılırlar) ilk değer atanmasına gerek yoktur. Çünkü bu değerler, destructive-read in işlemi sayesinde, hafızada önceden bulunabilecek verileri siler.

Notları gir,topla ve say

sahte kodumuzun tüm notları alabilmesi için bir döngü yapısına ihtiyacı vardır. Kaç notun girileceğini ve işleneceğini bilmediğimiz için nöbetçi kontrollü döngü kullanacağız. Kullanıcı notları girdikten sonra nöbetçi değeri girecektir. Program her seferinde girilen sayının nöbetçi değere eşit olup olmadığını kontrol etmeli, nöbetçi değer girildiği anda da döngüyü sonlandırmalıdır. Öyleyse sahte kodumuzda yapacağımız iyileştirme

İlk notu gir


Kullanıcı nöbetçi değeri girmediği sürece(while)

Bu notu o andaki toplam değere ekle
Sayıcıyı bir arttır
Sıradaki notu al ( bu değer nöbetçi değer olabilir )

biçiminde yapılmalıdır. Sahte kodda, while yapısının gövdesindeki ifadeleri küme parantezleri içine almadığımıza dikkat ediniz. Bunun yerine, while yapısı içindeki tüm ifadeleri içeriden başlattık. Bir kez daha sahte kodların yalnızca bir program geliştirme aracı olduğuna dikkat ediniz.

Ortalamayı hesapla ve yazdır

sahte kodunu ise

Eğer ( if ) sayıcı sıfıra eşit değilse
Ortalamayı, notların toplamını sayıcıya bölerek hesapla
Ortalamayı yazdır
Aksi takdirde ( else )
"Not girilmemiştir" yazdır

biçiminde düzeltebiliriz.

Burada, toplamın sıfıra bölünme ihtimalini ortadan kaldırdığımıza dikkat edin. Bir sayıyı sıfıra bölmek engellenmezse ölümcül hata oluşturur.Şimdi de ikinci iyileştirmemizi topluca şekil 3.7'de görelim.

    Genel Programlama Hataları 3.7
    Sıfıra bölmeye çalışmak ölümcül bir hata oluşturur.

    İyi Programlama Alıştırmaları 3.7
    Değeri sıfır olabilecek bir deyimi bölme işlemlerinde bölen olarak kullanacaksak bunu programda ölümcül bir hata oluşturmayacak biçimde kullanmak gerekir.(Örneğin bir hata mesajı yazdırarak)

Şekil 3.5 ve 3.7'de sahte kod içinde boş satırlar bırakarak okunurluğu arttırmaya çalıştık.Aslında bu boş satırlar programları çeşitli kısımlara ayırmaktadır.

Toplam değişkenini sıfır olarak belirle
Sayıcı değişkenini sıfır olarak belirle

İ

lk notu gir
Kullanıcı nöbetçi değeri girmediği sürece (while)
bu notu o andaki değere ekle
Sayıcıyı bir arttır
Sıradaki notu al(bu değer nöbetçi değer olabilir)

Eğer ( if ) sayıcı sıfıra eşit değilse

Ortalamayı, notların toplamını sayıcıya bölerek hesapla

Ortalamayı yazdır

 Aksi takdirde ( else )
"Not girilmemiştir" yazdır


Şekil 3.7 Sınıf ortalaması problemini nöbetçi kontrollü döngülerle çözen sahte kod algoritması.

    Yazılım Mühendisliği Gözlemleri 3.4
    Programların çoğu mantıksal olarak 3 kısma bölünebilir:Program değişkenlerinin bildirildiği ve değişkenlere ilk değer atandığı bildirim safhası, girilen verilerin değerlerinin işlendiği ve program değişkenlerinin ayarlandığı işleme safhası ve son olarak da sonuçların hesaplandığı ve yazdırıldığı sonlandırma safhası.

Şekil 3.7'deki sahte kod algoritması, daha genel sınıf ortalaması problemlerini çözmektedir. Algoritma iki iyileştirme seviyesinden sonra geliştirilmiştir. Çoğu zaman daha fazla seviyeye ihtiyaç duyulur.

    Yazılım Mühendisliği Gözlemleri 3.5
    Programcı, yukarıdan-aşağıya adımsal iyileştirme sürecini, sahte kod algoritması programcı tarafından C kodlarına çevrilebilecek kadar detaya sahip olduğunda sonlandırır. Daha sonra C programının yazılması oldukça kolay olacaktır.

C programı ve örnek bir çıktısı Şekil 3.8'de gösterilmiştir. Notlar için yalnızca tamsayılar girilmiş olsa da ortalama hesabı sonucunun, ondalıklı bir sayı olma ihtimali bulunmaktadır. int tipi böyle bir sayıyı temsil edemez. Bu sebepten, programda yeni bir veri tipi olan float, ondalıklı sayıları temsil edebilmek için kullanılmıştır. Ayrıca, ortalama hesabında iki tür arasındaki dönüşümü sağlamak için dönüşüm operatörü (cast operatörü) kullanılmıştır.Bu yeni özellikler programın yazılmasından sonra detaylı bir şekilde açıklanmıştır.

1 /* Şekil 3.8: fig03_08.c
2 Sayıcı kontrollü döngülerle
3 sınıf ortalaması bulan program */
4 #include <stdio.h>
5
6 int main( )
7 {
8 float ortalama ; /* yeni veri tipi */
9 int sayici, not, toplam ;
10
11 /* ilk değer atama */
12 toplam = 0;
13 sayici = 0;
14
15 /* işlem */
16 printf( "Notu giriniz (Çıkış için –1) : " );
17 scanf( "%d", &not );
18
19 while ( not != -1 ) {
20 toplam = toplam + not;
21 sayici = sayici + 1;
22 printf( "Notu giriniz (Çıkış için –1) : " );
23 scanf("%d", &not);
24 }
25
26 /* sonlandırma */
27 if ( sayici != 0 ) {
28 ortalama = ( float ) toplam / sayici;
29 printf ( "Sınıf ortalaması %.2f", ortalama);
30 }
31 else
32 printf ( "Hiç not girilmemiştir\n" );
33
34 return 0; /* Program başarılı bir şekilde sonlanmıştır */
35 }


Notu giriniz (Çıkış için –1) : 75
Notu giriniz (Çıkış için –1) : 94
Notu giriniz (Çıkış için –1) : 97
Notu giriniz (Çıkış için –1) : 88
Notu giriniz (Çıkış için –1) : 70
Notu giriniz (Çıkış için –1) : 64
Notu giriniz (Çıkış için –1) : 83
Notu giriniz (Çıkış için –1) : 89
Notu giriniz (Çıkış için –1) : -1
Sınıf ortalaması 82.50

Şekil 3.8 Sınıf ortalaması problemini nöbetçi kontrollü döngülerle çözen C programı ve örnek bir çıktısı.

Şekil 3.8'de, while döngüsü (19.satır) içindeki birleşik ifadeye dikkat ediniz. Döngü ile dört ifadenin de tekrarlanabilmesi için bu ifadelerin küme parantezi içine alınması gerektiğine dikkat ediniz. Küme parantezleri olmadığında, son üç ifade döngü dışında kalır ve bilgisayarın kodu aşağıdaki biçimde algılamasına sebep olur.

while( not != -1 )
toplam = toplam + not;
sayici = sayici + 1;
printf( "Notu giriniz (Çıkış için –1) :" );
scanf( "%d", &not);

Bu, kullanıcı ilk not olarak –1 girmediğinde sonsuz döngü oluşmasına sebep olur.

    İyi Programlama Alıştırmaları 3.8
    Nöbetçi kontrollü döngülerde kullanıcıdan veri istenirken nöbetçi değerin her seferinde hatırlatılması gerekir.

Ortalamaların hesabında her zaman tamsayı değerleri hesaplayamayız. Sıklıkla ortalama, 7.2 ya da –93.5 gibi ondalıklı bir kısım içeren bir değerdir. Bu değerler ondalıklı sayılar (floating point numbers) ya da gerçek sayılar olarak adlandırılır ve float veri tipi ile temsil edilirler. Hesaplamadaki ondalık kısmı tutabilmek için, ortalama değişkeni float tipinde bildirilmiştir.Buna rağmen toplam/sayici işleminin sonucu bir tamsayıdır. Çünkü toplam ve sayici değişkenleri tamsayı değişkenleridir. İki tamsayıyı bölmek bize ondalık kısmı kaybolmuş bir tamsayı değeri verecektir. Hesaplama işlemi ilk önce yapıldığından, ondalık kısım, sonuç ortalama değişkenine atanmadan önce kaybolur. Tamsayı değerleriyle ondalık kısma sahip bir hesaplama yapabilmek için, işlemde kullanılacak değerleri geçici olarak ondalıklı sayılara çevirmeliyiz. C, bu işlemi gerçekleştirmek için dönüşüm (cast) operatörünü kullanır.Programın 28.satırındaki

ortalama = (float) toplam / sayici;

ifadesi bir dönüşüm operatörü , ( float ), içermektedir.Bu operatör sayesinde, bu operatörün operandı olan toplam değişkeninin geçici olarak, ondalıklı sayı biçiminde bir kopyası oluşturulur. toplam değişkeninde depolanan değer hala bir tamsayıdır. İşlem artık, ondalıklı bir sayının (toplam değişkeninin geçici olarak float tipine çevrilmiş kopyası), sayici değişkeni içinde tutulan tamsayı değerine bölünmesi haline gelmiştir. C derleyicisi, operandlarının tipi aynı olan deyimleri hesaplayabilir. Operandların aynı tipte olmaları için, derleyici seçilen operandlara terfi ( promotion ) adı verilen bir işlem uygular. Örneğin, int ve float veri tipini içeren bir deyimde, ANSI standardı int operandlarının kopyalarının oluşturulmasını ve float tipine terfi ettirilmesini söylemektedir. Örneğimizde, sayici değişkenin kopyası oluşturulup, float tipine terfi edildikten sonra işlem yapılmakta ve ondalıklı biçimdeki sonuç ortalama değişkenine atanmaktadır. ANSI standardı, değişik tipteki operandlar arasındaki terfi işlemleri için bir takım kurallara sahiptir. 5.ünitede tüm standart veri tipleri ve terfi sıraları anlatılacaktır.

Dönüşüm operatörleri, her veri tipi için geçerlidir. Dönüşüm operatörleri, veri tipi isminin parantez içine alınmasıyla oluşturulur. Dönüşüm operatörü tekli bir operatördür. Yani tek bir operand kullanılır. İkinci ünitede, ikili aritmetik operatörleri çalışmıştık. C, ayrıca artı ( + ) ve eksi ( - ) operatörlerinin tekli biçimlerini de içermektedir. Böylece programcı –7 ya da +5 gibi deyimler yazabilmektedir. Dönüşüm operatörleri, sağdan sola doğru işler ve diğer tekli operatörlerle, örneğin, tekli artı ( + ) ve tekli eksi ( - ) operatörleriyle aynı seviyede önceliğe sahiptir. Bu öncelik, *, / ve % operatörlerinden bir seviye üstte ve parantez operatöründen bir seviye alttadır.
Şekil 3.8'de, 29.satırdaki printf ifadesindeki dönüşüm belirteci ortalama değişkeninin değerini yazdırmak için %.2f biçiminde kullanılmıştır. f, ondalıklı bir değerin yazdırılacağını belirtmektedir. .2 ise, değerin hangi duyarlık ile gösterileceğini belirtir ve gösterilecek değerin, noktadan sonra iki basamak içerebileceği anlamına gelir. Eğer %f dönüşüm belirteci tek başına kullanılırsa, değerleri 6 duyarlığında yazdırır. Yani noktadan sonra 6 basamak yazdırır. Bu, %.6f yazmak ile aynıdır. Ondalıklı sayılar duyarlık ile yazdırıldıklarında, yazdırılan değerin belirtilen sayıda ondalıklı kısım içerebilmesi için değer yuvarlanır. Hafızadaki değer değiştirilmez. Aşağıdaki ifadeler çalıştırıldığında, 3.45 ve 3.4 değerleri yazdırılır.

printf("%.2f\n",3.446); /*3.45 yazdırılır*/
printf("%.1f\n",3.446); /*3.4 yazdırılır*/

    Genel Programlama Hataları 3.8
    scanf ifadesi içindeki biçim kontrol dizesi içinde dönüşüm belirtecini, duyarlık ile birlikte kullanmak hatadır. Duyarlık yalnızca printf dönüşüm belirteçleriyle kullanılır.

    Genel Programlama Hataları 3.9
    Ondalıklı sayıların mükemmel bir biçimde gösterilebileceklerini düşünerek bu sayıları kullanmak hatalı sonuçlar üretilmesine sebep olur. Ondalıklı sayılar çoğu bilgisayarda yaklaşık olarak temsil edilirler.

    İyi Programlama Alıştırmaları 3.9
    Eşitlik söz konusu olduğunda ondalıklı sayıları karşılaştırmayınız.

Ondalıklı sayılar, her zaman %100 kesin olmasalar da bir çok uygulamada kullanılırlar. Örneğin, 37.6 sıcaklığının normal vücut sıcaklığı olduğunu söylediğimizde çok fazla ondalıklı basamak belirtmemize gerek yoktur. Sıcaklığı termometreden 37.6 olarak okuduğumuzda, vücut sıcaklığının gerçek değeri 37.5999473210643 olabilir. Burada anlatılan, bu değer yerine 37.6 kullanılmasının çoğu uygulamada yeterli olacağıdır. Bu konu hakkında daha fazla bilgiyi ileride yeniden vereceğiz. Ondalıklı sayıların oluşmasındaki bir diğer sebep de bölme işlemidir. Onu üçe böldüğümüzde sonuç 3.3333333... dır ve üçlerin dizisi sonsuza kadar devam etmektedir. Bilgisayar, böyle bir değeri tutmak için yalnızca belli sayıda boşluk ayıracağından ondalıklı sayıların yalnızca bir tahmin olduğu açıktır.