Amiga C

3. Bölüm

Erdem Taylan

Hatırlarsanız geçen sayıdaki yazımda son olarak fahrenheit sıcaklık değerlerini celcius sıcaklık değerlerine çeviren ve daha önce kaynak kitap olarak belirttiğim "The C Programming Language" adlı kitaptan alınan bir program yapmış ve programın incelenmesine bu sayıda devam edeceğimi söylemiştim. Kaldığım yerden başlamadan önce, biraz önce sözünü ettiğim kitaptan bazı örneklerin Amiga'ya uyarlanmış versiyonlarının yazı dizimde bulunacağını ve verilen programın o kitaptan yararlanılarak yazıldığını belirtmek amacıyla programın başına "K&R'nin kitabından alınarak Amiga'ya uyarlanmıştır" şeklinde bir comment (Tk. açıklama) ekleyeceğimi belirteyim. Buradaki "K&R" deyimi kitabın yazarlarının soyadlarının baş harflerinden oluşan (Kernighan & Ritche) ve tüm dünyada kullanılan bir kısaltmadır.

Şimdi kaldığımız yere dönelim:

Önce geçen sayıdaki yazıyı açın ve üçüncü kutudaki programın gözünüzün önünde olmasını sağlayın.

En son while döngüsünü incelemiştik. Şimdi programın nasıl çalıştığı konusundaki incelememize devam edelim. Programın yaptığı için oldukça büyük birkısmı while döngüsü içinde yapılmaktadır. Celcius sıcaklıkları aşağıdaki satırda hesaplanmakta ve celcius adlı değişkene eşlenmektedir:

celcius = (5.0/9.0) * (fahr-32.0);

Burada 5/9 terimi yerine 5.0/9.0 teriminin kullanılmasının sebebi, C'de iki tam sayının bölünmesi sırasında virgülden sonraki kısmın atılmasıdır. Eğer 5/9 terimini kullansaydık, bu sıfıra eşit olduğu için tüm değerler sıfıra eşit olacaktı. Bir sabitteki nokta işareti o sabitin floating point (Tk. virgüllü sayı) sayı olduğunu belirtir. Buradan 5.0/9.0 = 0.555...'dır ki bizim de istediğimiz budur.

Yine 32 yerine 32.0 yazdığım dikkati çekecektir. Aslında bu durumda ikisi de kullanılabilirdi. Çünkü fahr değişkeni bir floating point sayı olduğu için, eğer 32 yazsaydık bu değer C tarafından 32.0'a otomatik olarak çevrilecekti. Floating Point sayıları gereksiz olsa bile virgüllü şekilde (sayı 0) yazmamız programın daha anlaşılabilir olmasını sağlamaktadır.

Bu örnek, C dilinde oldukça kullanılan bir fonksiyon olan printf'in nasıl kullanıldığına da iyi bir örnektir. Printf, ilk argümanı karakterlerden oluşan bir string'dir (karakter dizisi). Bu dizideki her % işareti buraya diğer argümanların konulacağını belirtir. Örneğin:

printf ("% 4.0f %6.1f/n", fahr, celcius);
satırında %4.0f ekrana 4 basamaklı ve virgülden sonra hiç basamağı olmayan bir floating point sayı basılacağını, %6.1f ise yine bir floating point sayının ekrana basılacağını fakat sayının basamak uzunluğunun virgülden sonraki bir basamakla beraber altı olacağını belirtmektedir. Bu tanımlamaların bazı kısımları atlanabilir. Örneğin %4f, 4 basamaklı bir floating point sayının basılacağını; % 3f, virgülden sonra 3 basamağı bulunan bir sayı basılacağını; sadece %f ise floating point bir sayının basılacağını belirtir. Printf %f'den başka decimal (ondalık düzen) tamsayılar için %d, octal (sekizlik düzen) sayılar için %o, heksadesimal (onaltılık düzen) sayılar %x, karakterler için %c, string'ler (karakter dizileri) için %s ve % işaretinin kendisi içinde %% simgelerini de tanımaktadır.

printf'in argümanları, ilk argümanda belirtildikleri düzene uygun olarak verilmelidir. Yani eğer ilk argümanda ilk basılacak değer tamsayı, ikincisi floating point sayı olarak verilmişse ikinci argümanın integer (Tk. tamsayı), üçüncü argümanın floating point sayı olması gerekir. Aksi halde anlaşılmaz cevaplar alırsınız.

Bütün bunlara rağmen printf, C'nin bir parçası değildir, O sadece standart C kütüphanesinde bulunan bir fonksiyondur. Dolayısıyla BASIC'teki Print komutuyla hemen hemen aynı işi yapmasına karşın BASIC'teki durumun aksine, C bu fonksiyonu içermemektedir. Aslında C'de I/O (Ing. Input/Output, Tk. giriş/çıkış) ile ilgili hiçbir komut bulunmamakladır. Fakat printf hiçbir zaman bir farklılık oluşturmaz. O, sadece yararlı bir fonksiyondur o kadar. İşte bu sebepten dolayı (Soru: Hangi sebepten? Cevap: C'nin komut sayısının oldukça az olması sebebinden) C bellekte fazla yer kaplamaz ve bu da programı işleten bilgisayarın daha iyi çalışmasına destek olur (işte C'nin bir avantajı daha).

Bu arada Aztec C'deki printf'in bazı değişiklikleri var. Bu da şu:

Aztec C kütüphanelerinde 2 tane printf var. Bunlardan ilki C kütüphanesinde, ikincisi ise M kütüphanesinde. İlk printf sadece tamsayıları ve karakterleri basabiliyor. İkincisi ise bunlara ek olarak floating point sayıları da basabiliyor. Eğer dikkatinizi çekmişse fahrenheit-celcius programını link ederken "ln programismi.C -lc" yerine, "1n programismi.C -lm -lc" ile link ettik. Bu uygulamanın sebebi, printf'in iki değişik versiyonunun olması. Eğer programı "ln proramismi.c -lc' ile link etseydik c kütüphanesindeki printf kullanılacak ve bu da floating point sayıları basamadığından, biz sonuçları doğru olarak alamayacaktık (gerçekte %f görülen yer karakter olarak algılanacak ve %f şeklinde basılacaktı). Bundan dolayı programı ikinci metodu kullanarak ilk önce m kütüphanesi ile link ettik ve floating point sayıları basabilen printf'i kullanmış olduk.

Artık size biraz problem vermenin zamanı geldi. Bunun için ilk kutudaki problemleri lütfen yapın. Sizin de kabul edeceğiniz gibi ne kadar çok alıştırma yaparsanız o kadar iyi olur.

FOR KOMUTU

Tahmin edebileceğiniz gibi bir programı yazmanın genellikle birden fazla yolu vardır. Doğal olarak bizim sıcaklık programımız da bir istisna değil. Programın başka bir versiyonunu ikinci kutuda bulabilirsiniz (haydi ikinci kutuya).

Gördüğünüz gibi bu program da aynı cevapları çıkartmakta. Önemli değişikliklerden biri, çoğu değişkenin kaldırılması. Sadece fahr değişkeni printf'de %d'nin işlevini göstermek için kalmış durumda. Üst altsınırlar ve adım sayısı for döngüsü içinde sabitler olarak görülmektedirler. Ayrıca Celsius sıcaklığını hesaplayan satır da, printf'in bir argümanı olarak programda yer almaktadır.

Son değişiklik C'deki önemli ve genel kurallardan birini bize göstermektedir. Herhangi bir programda eğer programın içinde bir yerde herhangi bir çeşit data tipini kullanmak olasıysa, o data tipini veren herhangi bir komut dizini orada kullanılabilir. Printf'in son argümanı, bir floating point sayı olduğundan ve (5.0/0.0) * (fahr-32) ifadesi de floating point birsayı verdiğinden bu kullanım C kurallarına uygundur.

For'un kendisi aslında bir döngü çeşitidir. Eğer onu while döngüsü ile karşılaştırırsanız, işleyiş mantığını kolayca anlayabilirsiniz. For üç kısım içerir. Birinci kısım:

fahr = 0
sadece birkez çalıştırılır, ikinci kısım döngünün test bölümüdür:
fahr = 300
Bu koşul çalıştırılır. Eğer doğruysa döngü işletilir. Bundan sonra üçüncü kısım olan:
fahr = fahr + 20
bölümü çalıştırılır. Koşul yeniden test edilir. Koşul yanlış olduğu anda döngüden çıkılır. Aynen while'da olduğu gibi for'un döngüsü de tek bir komuttan oluşabileceği gibi, süslü parantezler içindeki birçok satırdan oluşabilir. For döngüsünün birinci ve üçüncü kısımlarıysa herhangi birtek satır işlem olabilir.

While ile for arasındaki seçim genellikle hangisinin daha rahat anlaşıldığına göre yapılır. For döngüsü genellikle başlangıç ve yeniden başlama adımlarının (birinci ve üçüncü kısımların) kısa ve birbiri ile ilişkili olduğu yerlerde kullanılır.

Şimdi biraz daha alıştırma vereyim (neredeler mi? Tabii ki üçüncü kutuda).

SEMBOLİK SABİTLER

Fahrenheit-celsius programı ile ilgili olarak son yapacağımız programın içindeki 300, 20 gibi sayıların C diline ve doğal olarak size getirdiği zararları incelemek. C'de bu şekilde sayılar kullanmak hiçbir zaman iyi değildir. Çünkü eğer bu sayıları değiştirmek istersek, programda sayıları içeren tüm yerleri değiştirmeliyiz. Eğer programımız buradakinin aksine oldukça büyük kapasiteli bir programsa, bu iş oldukça can sıkıcı ve uzun süren bir iş olabilir. İşte bunu engellemek için C bize H define tanımlamasını sunmakta. H define tanımlaması ile, programın başlangıcında sembolik karakterler tanımlayabilirsiniz. Bu işlemden sonra compiler, o sembolün programdaki tırnak içine alınmamış bütün yeralışlarını sembolün karşılığı ile değiştirir.

Sembolik sabitlere örnek vermek amacıyla dördüncü kutuda olan programı yazın ve çalıştırın.

Gördüğünüz gibi ALT, ÜST, ADIM sembollerinin karşısındaki değerler sabitlerdir. Dolayısıyla programın ilerisinde bir yerde:

ALT = 100;
diye bir satır yazamazsınız. Bu terimler aslında birer sabit olduğu için değişken gibi kullanılamazlar. Doğal olarak,
fahr = ALT;
programın herhangi bir yerinde yeralabilir. Son olarak sembolik sabitlerin genellikle değişkenlerden ayırmak amacıyla büyük harflerle yazıldığını ve tanımlama satırından sonra noktalı virgül konmadığını ekleyeyim. Tabii ki ilerde üst ve alt sınırlarda bir değişiklik yapmak isterseniz değiştirmeniz gereken tek satır, tanımlamanın yapıldığı satır olacaktır.

Bu aşamadan sonra birbiri ile ilişkili ve oldukça yararlı birkaç programı size vereceğim. Programlar karakterler üzerinde basit operasyonlar yapmaya yarıyorlar.

KARAKTER GİRİŞ VE ÇIKIŞ

Daha önce de belirttiğim gibi C kendi başına giriş/çıkış'la ilgili hiçbir komut içermemektedir. Peki o zaman karakterleri nasıl okuyup yazacağız? Burada da standart c kütüphanesi yardımımıza koşmakta. Evet standart o kütüphanesi karakter okuma ve yazma işlemleri için iki fonksiyon barındırmakta. Fonksiyonlar getchar () ve putchar ().

getchar () (dikkat ederseniz bazı satır başlarına küçük harfle başlıyorum. Bunun sebebi C'deki standart fonksiyon ve komutların küçük harflerle yazılması zorunluluğu. Ben de eğer büyük harfle başlarsam bu sizin kafanızı karıştırır diyerek, ilk kelimeleri C'nin içerdiği kelimeler olan cümlelere küçük harfle başlamaya karar verdim) fonksiyonu her çağrılışında, bir sonraki giriş karakterini alır ve onun değerini bir sayı olarak (ki bu sayı o karakterin ASCII tablosundaki karşılığıdır) programa verir. Yani,

c = getchar ()
atamasından sonra c değişkeni girişin fonksiyonun çağrılışından sonraki ilk karakterini içerir. Karakterler genelde klavyeden alınır fakat bu bir sınırlama değildir.

putchar (c) fonksiyonu ise getchar () fonksiyonunun tamamlayıcısıdır ve

putchar (c)
demek, c değişkeninin içerdiği karakteri çıkışa bas demektir. Çıkış, genellikle ekrana olur fakat bu da bir sınırlama değildir.

Aynen printf'de olduğu gibi getchar ve putchar C'de istisna oluşturmamaktadır. Bunlar yine standart c kütüphanesinde yeralan yararlı fonksiyonlardır.

TEXT DOSYALARINI KOPYALAMA

getchar ve putchar ile şaşılacak derecede yararlı programlar yapılabilir. Yapacağımız ilk program text dosyalarını birbirine kopyalamaya yarayan çok küçük bir program. Programı önce beşinci kutuda yazıldığı gibi compile edin ve daha sonra dördüncü adımda yazıldığı gibi çalıştırın ve bir dahaki aya kadar sabredin.

Eveet! Bu aylık da bu kadar. Yeni programımızın incelmesine bir dahaki ay devam edeceğiz. Bu arada siz de verdiğim alıştırmaları yapmayı unutmayın. Hoşçakalın.


KUTU 1

1> Fahrenheit-Celcius programını modiflye ederek 
sıcaklık listesinin başına 
aşağıdaki gibi bir başlık konmasını sağlayın:
 
Fahrenheit   Celcius
----------   -------
     0        -17.8
    20         -6.7
    40          4.4
   ...          ...
   280        137.8
   300        148.9

2> 0'dan 300'e kadar olan sıcaklıklar için 
Celsius-Fahrenheit tablosu çıkaran bir program yazın.
3> 1'den 170'e kadar olan sayıları toplayan 
ve her on adımda bir ara toplamı yazan 
bir program yazın. Programın çıktısı aşağıdaki gibi olmalıdır.

1'den 170'kadar sayıların toplamı
---------------------------------

adım no:     Ara toplam
--------     ----------
adım 1           55
adım 2          210
 ...            ...
adım 16        12880
adım 17        14535

genel toplam:
-------------
14535

KUTU 2

1> Aşağıdaki programı yazıp RamDisk'e kaydedin:

/* K&R'nin kitabından alınarak Amiga'ya uyarlanmıştır */

main()
{
int fahr;

for(fahr=0;fahr<=300;fahr=fahr+20) 
printf("%4d %6.1f",fahr,(5.0/9.0)*(fahr-32));
}

2> Şimdi programınızı "cc ram:program-ismi.c" ile compile edin.
3> Şimdi de "ln ram:program-ismi.o -lm -lc" ile link edin. 
4> Programı çalıştırırsanız size aşağıdakine benzer bir liste verir:

 0   -17.8 
20    -6.7
40     4.4
..     ..
280   137.8 
300   148.9

KUTU 3

1> Fahrenheit-Celsius programını değiştirerek 
programın sayıları tersten basmasını 
yani 300'den 0'a doğru hesap yapmasını sağlayın.
2> Birinci kutudakl üçüncü alıştırmayı 
while ve for döngülerini beraber kullanarak yapın.
3> Birinci kutudaki üçüncü alıştırmayı 
sadece for döngüsünü kullanarak yapın.
4> İkinin ondördüncü üssünü bir for döngüsü yardımıyla hesaplayın.

KUTU 4

1> Aşağıdaki programı yazın ve Ram Disk'e kaydedin.

/* K&R'nin kitabından alınarak Amiga'ya uyarlanmıştır*/

#define ALT 0    /*tablonun alt sınırı*/ 
#define UST 300  /*üst sınır*/ 
#define ADIM 20  /*adım büyüklüğü*/

main() /*fahrenheit-celsius tablosu*/
{
int fahr;

for(fahr=ALT;fahr<=UST;fahr=fahr+ADIM)
printf("%4d %6.1f",fahr,(5.0/9.0)*(fahr-32));
}

2> Şimdi programı "cc ram: program-ismi.c" ile compile edin.
3> Şimdi de "ln ram:program-ismi.o -lm -lc" ile link edin.
4> Programın çıktısı daha önceki programlarla aynıdır.

KUTU 5

1> Aşağıdaki programı yazıp Ram Disk'e kaydedin.

/* K&R'nin kitabından alınarak Amiga'ya uyarlanmıştır*/

#define EOF -1

main() /*giriş'i çıkış'a kopyala birinci versiyon*/ 
{
  int c;

  c=getchar(); 
  while(c!=EOF) {
     putchar(c);
     c=getchar(); 
  }
}

2> Şimdi programı "cc ram:program-ismi.c" ile compile edin.
3> Şimdi de "ln ram:program-ismi.o -lc" ile link edin.
4> Programı çalıştırırken dikkat etmeniz gereken bir durum var. 
Eğer programı sadece adını yazarak çatıştırırsanız 
normal giriş, klavye ve normal çıkış ekran olduğu için 
siz ne yazarsanız program onu ekrana yazacaktır. 
Programı bu şekilde çalıştırırsanız çıkmak için Ctrl-\ tuşlarına basın. 
Text dosyaları kopyalamak için ise programa giriş ve çıkış yönlerini 
AmigaDOS yardımıyla ok işaretleri yardımıyla (İng, redirection) vermelisiniz. 
Bunun için, 

program-ismi < kopyalanacak_dosyanın_adı > dosyanın_kopyalanacağı_dosyanın_adı

şeklinde yazıp programı çalıştırmalısınız.