Bu sayfadaki yazılar
Sayfanın metni
Sayfa 39
"Amiga"
şeklinde bir string (Tk. karakter dizisi) görürse, otomatik olarak string'in elemanlarından oluşan bir karakter dizisi tanımlar ve sonuna \0 karakterini ekler. Yani compiler'ın bellekte oluşturduğu dizi aşağıdaki gibidir.
|A|m|i|g|a|\n|\D|
Compiler'ın böyle bir uygulama yapmasının nedeni; printf gibi fonksiyonların ekrana (genellikle ekrana, printer gibi diğer çevresel birimlere de olabilir) yazacakları string'lerin sonunu bulabilmesini sağlamaktır, printf tanımlamalarından biri olan %s, basacağı karakter dizisinin sonunda 0 karakterinin yani sıfır değerinin bulunmasını ister. Başka bir örnek olarak; eğer copy fonksiyonunu incelerseniz, s1 dizisine s2'den kopyalanan elemanın \0 yani null karakter olmasıyla fonksiyonun kopyalama işlemini durdurduğunu görürsünüz. Bütün bu işlemlerde string'lerin sonunda 0 karakteri bulunduğu ilkesinin kullanıldığı anlaşılabilir.
Bu ayki yazımı bitirmeden, bir kaç alıştırma için ikinci kutuya bir göz atmanızı öneriyorum.
Bir sonraki ay, dışsal (İng. external) değişkenleri inceleyerek yazı dizimizin ilk bölümü olan C diline giriş'i bitireceğimizi belirteyim. İyi çalışmalar.
KUTU 2
1> Girişindeki satırların 80 karakterden fazla olanlarını ekrana basan bir program yazın.
2> Kendisine verilen string'i ters çeviren ters(s) adlı bir fonksiyon yazın ve çalışırlığını kontrol için kısa bir programda fonksiyonu deneyin.
KUTU 1
1> Aşağıdaki programı yazıp Ram Disk'e kaydedin.
/* K&R'ın kitabından alınarak Amiga'ya uyarlanmıştır. */
#define EOF -1 #define MAXLINE 1000
main() {
int len; /*O anki satır uzunluğu*/ int max; /*O ana kadarki en büyük uzunluk*/ char line[MAXLINE]; /*O anki satır*/ char save[MAXLINE]; /*O ana kadar en uzun satır*/
max=(); while((Ien=getline(line,MAXLINE))>0) if (len>max) {
max=len; copy(line,save); } if(max>0) printf("%s",save); }
getline(s,lim) char s[]: int lim; {
int c; int i;
for(i=0;i<lim-1&&(c=getchar())!=EOF&&c!='\n';++i)
s[i]=c; if(c==") {
s[i]=c;
++i; } s[i]='\0'; return(i); }
copy(sl,s2) char s1[]; char s2[]; {
int i;
i=0; « while((s2[i]=sl[i])!=,\0')
++i; }
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ırmak için ram:program-ismi yazın. Bu durumda program sizin klavyeden girdiğiniz karakterler üzerinde işlem yapacaktır. Bu moddan çıkmak için Ctrl-\ (Control ve ters bölü tuşlarına birlikte) tuşlarına basmalısınız. Eğer programa bir text dosyasından redirection (Tk. yeniden yönlendirme) verirseniz program text dosyasının bitimiyle beraber size yaptığı işlemlerin sonuçlarını yazacaktır.
Klavyeyle gezinmek için ← ve → tuşları.
Sayfa 38
DİLLER
Nerede kalmıştık? Aaaa, Evet! Fonksiyonları inceliyorduk. (Unutmadan dergi artık Amiga ile baskıya hazırlandığından "\" karakteri sorunu da kapanmış oldu.)
Son olarak, bir fonksiyonun kendisini çağıran fonksiyona bilgiyi geri gönderme metodlarını incelemiştik. Bu sayıda ise, fonksiyonların argümanlarıyla ilgili biraz teknik ve açıklayıcı bilgiden sonra karakter dizilerini inceleyeceğimizi belirteyim.
ARGÜMANLAR VE DEĞER OLARAK ÇAĞRILMALARI C dilindeki fonksiyonların en önemli parçası olarak gösterebileceğimiz argümanların, diğer dillere yabancı bir özellikleri var. Bu özellik diğer birçok dilin aksine, C'de argümanların değer olarak fonksiyona çağrılmaları. Değer olarak çağrılmayla anlatılmak istenen olgu şu: Bir fonksiyona bir argüman geçirildiğinde, o argümanın geçici bir kopyası alınır ve işlemler bu kopya üzerinde yapılır. Böylece argümanın kendisi değil, değeri işlemlere girer. Diğer birçok dilde ise argümanların adresleri fonksiyonlara geçirildiğinden, onlar üzerinde yapılan her işlem argümanın kendi değerini de etkiler. Diğer dillerin uyguladığı yönteme, adresle çağrılma denmekte.
Bu iki metod arasındaki en önemli fark, C dilinde hiçbir fonksiyonun argümanları üzerinde bir değişiklik yapamaması. Fonksiyonlar sadece o argümanın kopyası üzerinde değişiklik yapabildiklerinden, bir argüman fonksiyona hangi değerle yollandıysa (Yollayan kim mi? Tabii ki fonksiyonu çağıran diğer fonksiyon -hatırlarsanız C dilinde bütün programlar fonksiyonlardan oluşmaktaydı ve main bile aslında özel adlı bir fonksiyondu-), o değerle geri döner.
Değerle çağırma ilk bakışta anlamsız gibi görünse de genellikle programların daha kısa, daha az değişken kullanılarak yapılabilmesine olanak tanır. Çünkü fonksiyonlardaki argümanlar, değerlerinde bir değişme olacağı korkusu olmadan aynı isim altında kullanılabilirler. Örneğin aşağıdaki satırlarda power fonksiyonunun değer ile çağrılma yöntemini kullanan bir versiyonu bulabilirsiniz.
power(x,n) int x,n;
{
intp;
for(p=l;n>0;--n)
p=p*x; return(p);
}
Burada n adlı argümanın bir kopyası işlemlerde kullanılmıştır. İşlem sırasında, n sıfır olana kadar devamlı bir eksiltilmiştir. Dolayısıyla fonksiyonun içinde sayaç görevini üstlenmek için yeni bir değişken tanımlamaya gerek kalmamıştır. Çünkü fonksiyon n değişkeninin asıl değerini etkileyemeyeceğinden, n kullanılması değerin yitirilmesi gibi bir sonuca yol açmayacaktır.
Doğal olarak, gerektiğinde argümanlarının değerini değiştirebilecek fonksiyonlar yazmak da olasıdır. Değişkeni çağıran fonksiyona geçiren program parçası eğer değişken yerine, değişkenin adresini verirse (teknik olarak bir değişkenin adresine verilen isim pointer'dır (İng. gösterici)), program bu adres üzerinden giderek o değişken üzerinde değişiklik yapabilir. Doğal olarak eğer değişken yerine adresi yollanıyorsa fonksiyonda tanımlamalar sırasında o argüman bir değişkene pointer olarak tanımlanmalıdır. Herhangi bir fonksiyon, bir değişkenin adresini bilirse bu adres yardımıyla onun değeriyle dolaylı yoldan oynayabilir.
Eğer fonksiyon argümanlarından biri bir dizinin adıysa, fonksiyona girilen değer aslında o dizinin adresidir. Dolayısıyla fonksiyonlara geçirilen bir dizi için değer olarak çağrılma değil, adres ile çağrılma durumu geçerlidir. O zaman eğer fonksiyon dizinin elemanları üzerinde bir değişiklik yaparsa, değişiklikler dizinin elemanlarını etkileyerek değerlerini değiştirebilirler.
KARAKTER DİZİLERİ C dilinde en çok kullanılan dizi türü, belki de karakter dizileridir. Bu tür dizileri ve fonksiyonların onlar üzerindeki etkilerini görmek için, okuduğu satırlar içinden en uzun olanını seçen bir program hazırlayalım. Programın temel hatları oldukça kolay tasarlanabilir:
while(her satır daha varken)
if(o anki satır o ana kadarki en uzun satırdan daha uzunsa)
o satırı ve uzunluğunu sakla en uzun satırı ekrana yaz
Bu temel adımlardan da anlaşılabileceği gibi program parçalara kolaylıkla ayrılabilir. Bir parça yeni satırı okumakla, diğer bir parça onu test etmekle, bir sonraki onu bir yerde saklamakla ve kalan parçada işleyişi kontrol etmekle görevlendirilebilir.
Parçalar oldukça güzel bir biçimde birbirinden ayrılabildiğinden, programı parçalara ayırarak yazmak da oldukça iyi olacaktır. Bunun için önce girişteki bir sonraki satırı okuyan getline adlı bir fonksiyon -ki bu fonksiyon getchar fonksiyonunun genelleştirilmiş halidir- yazalım. Fonksiyonu başka programlarda da kullanabilmek için yazım sırasında fonksiyonun birkaç amaca uygulanabilir şekilde yazılmasına dikkat etmek gerekir. Bu fonksiyon en azından dosya bitimini sezebilmeli, daha genel olarak da okuduğu satırın uzunluğunu çağrıldığı yere geri gönderebilmelidir. Eğer yeni bir satır okuma sırasında dosya bitimi mesajı (EOF) alınırsa, program satır uzunluğu olarak sıfır'ı çağırana gönderecektir. Sıfır hiçbir zaman olası bir satır uzunluğu olamaz, çünkü bir satır en azından yeni satır karakterini ("\n") içermek zorundadır. Sadece "\n" karakterinden oluşan bir satırın uzunluğu bile bir olacaktır. Buradan da anlaşıldığı gibi karakterler arasında görülemeyen olanlar da sayılmaktadır ("\n"-yeni satır, "\t"-tab karakterleri gibi).
O ana kadarki en uzun satırdan daha uzun bir satır bulduğumuzda, o satırı mutlaka bir yerlere kaydetmeliyiz (burada kaydetmeyle diskete kaydetmek değil, bellekte bir bölgeye yerleştirme işlemini anlatmak istiyorum.). Bu gereklilik, copy isimli, görevi o anki en uzun satırı güvenilir bir yerde saklamak olan bir fonksiyon yardımıyla çözülebilir.
Son olarak tüm bu parçaların toplanacağı ve programın çalışmasının kontrol edileceği ana bir programa gerek duyulmaktadır.
Bu gerekliliklere göre yazılan programı birinci kutuda bulabilirsiniz.
Programdaki main ve getline fonksiyonları birbirleriyle bir çift argüman ve return komutuyla yollanan bir değer yardımıyla haberleşmektedir, getline fonksiyonunda, argümanlar
char s[]; int lim;
deklarasyonları ile tanımlanmaktadır. Burada birinci argüman bir dizi, ikinci argüman ise bir integer (Tk. tamsayı) olarak tanımlanmıştır, s dizisinin uzunluğu deklarasyonda yer almamıştır. Çünkü bu dizinin uzunluğu main fonksiyonunda belirlenmektedir, getline return komutunu main'e bir değer yollamak için kullanmaktadır. Görüldüğü gibi bazı fonksiyonlar bazı yararlı değerleri çağırıcılarına yollarken, copy fonksiyonu örneğinde olduğu gibi sadece yaptığı iş için kullanılan ve kullanışlı hiçbir değeri çağırana göndermeyen fonksiyonlar da vardır.
getline fonksiyonu 0 karakterini (null karakteri ki bu karakterin değeri sıfırdır), yarattığı dizinin sonuna; dizinin bittiğini belirtmek için koymaktadır. Bu metodu C compiler'ının kendisi de kullanmaktadır. Öyle ki, eğer compiler programın içinde;