Ünite 8: Fonksiyonlar

Giriş

C Programlama dilinde, fonksiyonlar önemli bir yapıya sahip alt program kodlarıdır. Fonksiyonlar, yazılan program kodlarının daha modüler bir şekilde yapılandırılmasını sağlarlar. Fonksiyonların kullanımı sayesinde program kodları daha küçük alt bölümlere ayrılabilmektedir.

Matematiksel ifadelerde kullanılan fonksiyonlara benzer şekilde, programlamadaki fonksiyonlar da bazı giriş değerlerini kullanarak belli bir işlemi gerçekleştirecek şekilde çıkış değeri oluşturacaklardır. İçerisine ana program kodlarının yazıldığı main() fonksiyonu da bir fonksiyondur. Ancak main() fonksiyonu mutlaka olması gerekli ana fonksiyondur.

Programın alt bölümler hâlinde çalıştırılması, yapılması gerekli işlemlerin farklı fonksiyonlar hâlinde gerçekleştirilmesini sağlayarak kodlamada bir hata oluştuğunda hata tespitini kolaylaştıracaktır.

Fonksiyon Tanımlama ve Çağırma

Fonksiyonlar C kütüphanesinin içerisinde yer alan hazır fonksiyonlar (printf, scanf, pow vb.) şeklinde olabileceği gibi, programcı tarafından ihtiyaca göre sonradan oluşturulmuş fonksiyonlar da olabilirler. Fonksiyonun kullanılabilmesi için tanımlanması, fonksiyon bloğunun olması ve fonksiyonun çağrılması gereklidir.

Bir fonksiyonu kullanmadan önce, değişken tanımlamada olduğu gibi fonksiyonu tanımlamak gerekmektedir. Tanımlama aşamasında fonksiyonun giriş ve çıkış değerlerinin sayısı ve türü belirtilir. Yapılacak işlemler ise fonksiyon bloğunun içindeki kod satırları ile sağlanır. Fonksiyon tanımlama satırı, main() öncesinde, “#include” ifadesini içeren önişlemci bölümünün hemen altında yapılabilir. Böylece, main() fonksiyonu içerisinde fonksiyonu kullanabilme yetkisi oluşturulmuş olur.

Fonksiyon tanımı, fonksiyon_tipi fonksiyon_adı(tip1 arguman1, tip2 arguman2) veya fonksiyon_tipi fonksiyon_adı(tip, tip2) şeklinde yapılır. Tanımlama satırında argüman değişkenlerinin adını(arguman1, arguman2) yazma zorunluluğu yoktur. İkinci ifadede olduğu gibi, yalnızca tiplerini (int, float, double, char vb.) yazmak yeterlidir. Ancak parantez içerisindeki toplam argüman sayısı önemlidir. Fonksiyonun giriş argümanları olarak dışarıdan, bir diğer ifade ile main() ortamından kaç değişken alması gerektiği belirlenmelidir. Argüman sayısı fonksiyon tanımı, fonksiyonun çağrılması ve fonksiyon bloğu bölümlerinde birbirleri ile tutarlı olmalıdır. Argüman bölümüne void ifadesi yazıldığı durumda ise fonksiyonun bir giriş değeri almadığı kabul edilir. Çıkış değerini ise fonksiyon_tipi b ölümü belirleyecektir. Fonksiyon tipi de int, float, double, char vb. değişken türlerinden herhangi bir tanesi olabilir. Fonksiyon yaptığı işlemin ardından, main() ortamına herhangi bir değer geri döndürmüyor ise fonksiyon_tipi bölümüne void ifadesi yazılır. Fonksiyon tanımlamasından sonra “;” (noktalı virgül) işaretinin unutulması derleme hatası verecektir.

Fonksiyon bloğunda, işlem sonucunda, hangi değişken, fonksiyonun çağrıldığı yere geri döndürülecek ise, o değişken fonksiyon bloğunun sonundaki return ifadesinin yanına yazılacaktır. fonksiyon_tipi ise dönüş değerinin tipini belirler. Fonksiyon bloğu,

fonksiyon_tipi fonksiyon_adı(tip1 arguman1, tip2 arguman2){

yerel değişkenler;

fonksiyon kod satırları;

return(geri_dönüş_değeri);

}

şeklinde oluşturulur. Fonksiyon tanımında herhangi bir tip türü yazılmaz ise geri dönüş değeri varsayılan değer olarak, int (tam sayı) kabul edilir. Fonksiyonun çağrılması aşaması ise main() içerisinde,

fonksiyon_tipi fonksiyon_adı(tip1 arguman1, tip2 arguman2);

şeklinde gerçekleştirilir. Fonksiyonların tanımlanması, çağırılması ve fonksiyon bloğu oluşturulması ile ilgili Sayfa 145’teki Örnek 8.1 incelenebilir.

Fonksiyonlara Argüman Geçirme

İçerisine argüman alan fonksiyonlarda, bu argümanların gönderilmesi için iki farklı yöntem bulunmaktadır. Bunlar değer yöntemi(call by value) ve referans yöntemi(call by reference) ile çağırmadır.

Değer yöntemi ile çağırma işleminde, fonksiyona iletilen değişkenlerin(argümanların) yalnızca sayısı kadar tip bildirimi iletilmekte olup, fonksiyon bloğu aktif olduğu anda, fonksiyonun kendi içerisinde, gönderilen argümanların birer kopyası oluşturulmaktadır. Bir diğer ifade ile fonksiyon içerisindeki işlemlerde, main() fonksiyonunda ilk anda oluşturulan orijinal veri yerine kopyası ile işlem yapılmaktadır. Böylece fonksiyon içerisinde orijinal değerler değiştirilememektedir.

Değer yöntemi ile fonksiyonlara argüman geçirildiğinde fonksiyondaki değişiklikler orijinal değeri değiştirmemesine rağmen, fonksiyona referans yöntemi ile argüman geçirildiğinde orijinal değer değişebilmektedir. Çünkü referans yöntemi, orijinal değişkenin adres değerini kullanmaktadır. Bellekteki adreslerle işlem yapılabilmesi için gösterici (pointer) yapıları kullanılmaktadır. Fonksiyona geçirilen argüman bir gösterici-değişken olarak kullanılmaktadır.

Fonksiyonlara argüman geçirirken gönderilen değişkenin main () deki mevcut değeri değiştirilmek istenmez ise değer yolu ile fonksiyon çağırma işlemi, orijinal değerin de değişmesi isteniyorsa referans yolu ile fonksiyon çağırma işlemi gerçekleştirilir.

Bir dizinin elemanları fonksiyona argüman olarak geçirilmek istendiğinde her bir elemanın ayrı ayrı gönderilmesi gerekir. Ancak bu şekildeki kullanım çok pratik değildir. Bu nedenle dizinin tüm elemanlarını geçirebilmek için dizinin ilk elemanının adresi yani başlangıç adresini geçirmek daha uygun olacaktır. Dizinin başlangıç adresinin geçirilmesi aslında diziyi gösterici olarak kullanmak anlamına da gelir.

C Standart Hazır Kütüphane Fonksiyonlarının Kullanımı

C programlama dilinde, ihtiyaca göre programcı tarafından yazılan fonksiyonların yanı sıra hazır olarak bulunan kütüphane fonksiyonları da bulunmaktadır. Ekrana yazdırma veya klavyeden girişler için kullanılan printf ve scanf bunların en çok bilinenleri arasındadır. C programlama dilinde birçok hazır kütüphane bulunmaktadır. Bu kütüphane fonksiyonlarını kullanıp, gereksiz yere zaman harcayarak, yeniden fonksiyon oluşturmaya gerek kalmamaktadır. Yalnızca önişlemci bölümüne ilgili fonksiyonun içerildiği “*.h” uzantılı kütüphane dosyalarını dâhil etmek yeterlidir. Bu kütüphanelere en çok kullanılan math.h, string.h, ctype.h, stdlib.h kütüphaneleri örnek gösterilebilir.

Matematiksel Kütüphane Fonksiyonları (math.h): Hazır matematiksel fonksiyonları kullanabilmek için önişlemci tanımları bölümüne #include adlı başlık dosyası eklenmelidir. Matematiksel fonksiyonların kullandığı sayılar double tipindedir. Başlıca matematiksel fonksiyonlar acos(), asin(), atan(), ceil(), cos(), cosh(), exp(), floor(), log(), log10(), pow(), sin(), sqrt(), tan(), tanh(), ceil() olarak sıralanabilir.

Dizgi ve Karakter Fonksiyonları (string.h, ctype.h): Karakterleri veya dizgileri kullanarak işlem yapan hazır kütüphane fonksiyonları string.h ve ctype.h başlık dosyaları tarafından içerilirler.

Dizgi işlemleri yapan ve string.h kütüphanesinde bulunan fonksiyonlardan en çok kullanılanlar şu şekildedir: strlen, argüman olarak bir dizgi alır ve dönüş değeri olarak karakter sayısını döndürür. strcpy(birinci, ikinci) fonksiyonu, parantezler arasında iki parametre (verideğişken) alır. Bunlardan ikincisini birinciye kopyalar. strcmp() ile karakter dizilerinin sayısal olarak karşılaştırılması sağlanmaktadır. Karakterlerin her birinin ASCII olarak sayısal bir karşılığı bulunmaktadır. strcmp() ile bu harflerin sayısal karşılıkları kullanılarak dizilim sırası karşılaştırılmaktadır. strcat(birinci, ikinci) fonksiyonu, aldığı iki adet giriş dizgilerinden ikincisini birincisinin sonuna boşluk bırakmadan ekler.

Karakterlerden oluşan dizgilerle ilgili fonksiyonları string.h başlık dosyası içerirken, yalnızca karakterlerle ilgili işlemleri içeren fonksiyonları ise ctype.h başlık dosyası tarafından içerilmektedir. Bu fonksiyonlardan en çok kullanılanları şu şekildedir: toascii(int c) c sayısı ile verilen ASCII koda sahip karakteri verir. isdigit(int c) c bir rakam ise 0’dan farklı, diğer durumda 0 gönderir. isalpha(int c) c bir harf ise 0’dan farklı, diğer durumda 0 gönderir. islower(int c) c küçük harf ise 0’dan farklı, diğer durumda 0 gönderir. isupper(int c) c büyük harf ise 0’dan farklı, diğer durumda 0 gönderir. tolower(int c) giriş argümanını küçük harfe çevirir. toupper(int c) giriş argümanını büyük harfe çevirir.

Dinamik Bellek Ayırma Fonksiyonları

C programlama dilinde, değişkenlerle veya herhangi bir dosyadan okunan verileri kullanarak işlemler gerçekleştirirken, bellekte verilerin büyüklüğüne göre sürekli yeni yerler ayrılır. Ancak bu verilerin büyüklüğü veya aynı anda birden çok programın çalıştırılması gereken durumlarda, programın çalıştırıldığı bilgisayarın belleğinin kapasitesine göre yetersizlik gösterebilir. Bu nedenle verilere sürekli yeni bellek alanları tahsis eden statik değişken atama yöntemi yerine, gerektiğinde bellekte yer açıp işlem bittiğinde o bellek alanını boşa çıkaran dinamik bellek atamaişlemi gerekebilir. Böylece bellek daha verimli bir şekilde kullanılabilir. Bahsedilen dinamik bellek ayırma işlemleri için C’de bulunan hazır kütüphane fonksiyonlarından malloc, calloc, realloc ve free fonksiyonları kullanılabilir. Bu fonksiyonlar stdlib.h başlık dosyasını kullanırlar. Bellek ayırma için;

void *malloc(n);

void *calloc(n, tip_uzunluğu);

fonksiyonları kullanılabilir. malloc ve calloc fonksiyonlarının kullanımları farklı olsa da yaptıkları işlem aynıdır. malloc argüman olarak doğrudan verinin byte türünden büyüklüğünü alırken, calloc fonksiyonu iki argüman alır. Bunlardan ilki kaç adet veri olduğu, ikincisi ise bu verinin veri tipinin byte olarak değerini gösterir.

Bellek ayırma işlemlerinde bir diğer fonksiyon ise realloc fonksiyonudur. Bu fonksiyon ise malloc veya calloc ile ayrılan bellek alanı programın ilerleyen satırlarında, yetersiz kalma veya azaltılması gereken durumlarda mevcut ayrılan alana ilave bellek alanı ekleme veya çıkarma amacıyla kullanılır. realloc f onksiyonunun kullanılabilmesi için daha önceden malloc veya calloc fonksiyonu ile bellek tahsis edilmiş olmalıdır.

malloc, calloc yada realloc fonksiyonları ile tahsis edilen bellek alanının kullanımı bittikten sonra free fonksiyonu ile bu tahsis edilen bellek alanlarının serbest bırakılması gerekir. Kod içerisinde free (dizgi) satırından sonra dizgi göstericisinin içeriği kaybedilir, kullanılamaz. Bu nedenle, tamamıyla değişken ile ilgili işlem bittikten sonra free fonksiyonunu kullanmak gerekir.