• Sonuç bulunamadı

Genel Programlama I Ders 6

N/A
N/A
Protected

Academic year: 2022

Share "Genel Programlama I Ders 6"

Copied!
37
0
0

Yükleniyor.... (view fulltext now)

Tam metin

(1)

Genel Programlama I

04.11.2010

Ders 6

(2)

Fonksiyonlar

C'de alt programlara fonksiyon denir. Fonksiyon sözcüğü burada matematiksel

anlamıyla değil diğer programlama dillerinde kullanılan, "alt program", "prosedür",

"subroutine" sözcüklerinin karşılığı olarak kullanılmaktadır.

Fonksiyonlar C dilinin temel yapı taşlarıdır. Çalıştırılabilen bir C programı en az bir C fonksiyonundan oluşur. Bir C programının oluşturulmasında fonksiyon sayısında bir kısıtlama yoktur.

Fonksiyonların onları çağıran fonksiyonlardan aldıkları girdileri ve yine onları çağıran fonksiyonlara gönderdikleri çıktıları vardır. Fonksiyonların girdilerine aktüel

parametreler (actual parameters) ya da argumanlar (arguments) diyoruz.

Fonksiyonların çıktılarına geri dönüş değeri (return value) diyoruz.

(3)

Bir fonksiyon iki farklı amaçla kullanılabilir :

•Fonksiyon, icrası süresince belli amaçları gerçekleştirir. (Belli işlemleri yapar)

•Fonksiyon icrası sonunda üreteceği bir değeri kendisini çağıran fonksiyona gönderebilir.

Fonksiyonların Tanımlanması ve Çağırılması

Bir fonksiyonun ne iş yapacağının ve bu işi nasıl yapacağının C dilinin sentaks kurallarına uygun olarak anlatılmasına o fonksiyonun tanımlanması (definition) denir. Fonksiyon tanımlamaları aşağıda inceleneceği gibi birtakım kurallara tabidir.

Bir fonksiyonun çağırılması ise o fonksiyonun yapacağı işi icraya davet edilmesi anlamına gelir. Fonksiyon çağırma ifadesi karşılığında derleyici, programın akışını ilgili fonksiyonun kodunun bulunduğu bölgeye aktaracak şekilde bir kod üretir.

Programın akışı fonksiyonun kodu içinde akıp bu kodu bitirdiğinde, yani fonksiyon icra edildiğinde, programın akışı yine fonksiyonun çağırıldığı noktaya geri

dönecektir.

(4)

Fonksiyonların Geri Dönüş Değerleri (return values)

Bir fonksiyonun yürütülmesi sonunda onu çağıran fonksiyona dönüşünde

gönderdiği değere, fonksiyonun geri dönüş değeri (return value) denmektedir.

Her fonksiyon bir geri dönüş değeri üretmek zorunda değildir. Fonksiyonların geri dönüş değerleri farklı amaçlar için kullanılabilir;

Bazı fonksiyonlar tek bir değer elde etmek amacıyla tasarlanmışlardır. Elde ettikleri değeri de kendilerini çağıran fonksiyonlara geri dönüş değeri olarak iletirler. Örneğin:

y = pow(2, 3);

pow fonksiyonu standart bir C fonksiyonudur. Birinci parametresiyle belirtilen sayının ikinci parametresiyle belirtilen kuvvetini hesaplayarak, hesapladığı sayıyı geri dönüş değeri olarak kendisini çağıran fonksiyona iletir. Yukarıdaki örnekte 2 sayısının 3. kuvveti bu fonksiyon yardımıyla hesaplanarak bulunan değer y

değişkenine atanmıştır.

(5)

Bazı fonksiyonların geri dönüş değerleri fonksiyonun yürütülmesi sırasında yapılan işlemlerin başarısı hakkında bilgi verir. Yani bu tür fonksiyonların geri dönüş değerleri test amacıyla kullanılmaktadır. Geri dönüş değerleri yapılması istenen işlemin başarılı olup olmaması durumunu açıklar. Örneğin :

p = malloc(200);

ifadesiyle bellekte 200 byte uzunluğunda bir blok tahsis etmek isteyen programcı bu işlemin başarılı bir biçimde yerine getirilip getirilmediğini de test etmek zorundadır.

Hemen arkasından p değişkeninin aldığı değeri kontrol edecek ve işlemin başarısı hakkında bir karara varacaktır. Dolayısıyla malloc fonksiyonunun geri dönüş değeri, fonksiyonun yapması gereken işin başarılı bir şekilde sonuçlanıp sonuçlanmadığını göstermektedir.

(6)

Bazı fonksiyonlar kendilerine gönderilen argumanları belirli bir kritere göre test ederler. Ürettikleri geri dönüş değerleri ise test sonucunu belirtir. Örneğin:

if (isalpha(ch)) { ...

}

Burada isalpha fonksiyonu arguman olarak gönderilen karakterin bir harf karakteri olup olmadığını test eder. Eğer harf karakteriyse, isalpha fonksiyonu 0 dışı bir değere geri dönecek, eğer harf karakteri değilse 0 değerine geri dönecektir. Çağıran fonksiyonda da geri dönüş değerine göre farklı işlemler yapılabilecektir.

(7)

Bazı fonksiyonlar hem belli bir amacı gerçekleştirirler hem de buna ek olarak amaçlarını tamamlayan bir geri dönüş değeri üretirler. Örneğin :

x = printf("Merhaba Dünya\n");

Burada printf fonksiyonu ekrana Merhaba Dünya yazısını yazmak için kullanılmıştır.

Ancak ekrana yazdığı karakter sayısını da geri dönüş değeri olarak vermektedir.

Bir yazı içersinde bulunan belirli bir karakteri silecek bir fonksiyon tasarladığımızı düşünelim. Fonksiyon işini bitirdikten sonra yazıdan kaç karakter silmiş olduğunu geri dönüş değeri ile çağırıldığı yere bildirilebilir.

(8)

Bazen geri dönüş değerlerine ihtiyaç duyulmaz. Örneğin yalnızca ekranı silme amacıyla tasarlanmış olan bir fonksiyonun geri dönüş değerine sahip olması gereksizdir.

clrscr();

clrscr fonksiyonu yalnızca ekranı siler, böyle bir fonksiyonun geri dönüş değerine ihtiyacı yoktur.

Fonksiyonların geri dönüş değerlerinin de türleri söz konusudur.

Fonksiyonların geri dönüş değerleri herhangi bir türden olabilir. Geri dönüş değerlerinin türleri fonksiyonların tanımlanması sırasında belirtilir.

(9)

Fonksiyonların Tanımlanması

Kendi yazdığımız fonksiyonlar için tanımlama (definition) terimini kullanıyoruz. C'de fonksiyon tanımlama işleminin genel biçimi şöyledir:

[Geri dönüş değerinin türü] <fonksiyon ismi> ([parametreler]) {

...

...

}

Yukarıdaki gösterimde açısal parantez içinde belirtilen ifadeler zorunlu olarak bulunması gerekenleri köşeli parantez içinde belirtilen ifadeler ise bulunması zorunlu olmayan, isteğe bağlı (optional) ifadeleri göstermektedir. Tanımlanan fonksiyonlar en az bir blok içerirler. Bu bloğa fonksiyonun ana bloğu denir. Ana blok içinde istenildiği kadar içiçe blok yaratılabilir. Aşağıdaki fonksiyon tanımlamasından fonk1 fonksiyonunun parametre almadığını ve geri dönüş değerinin de double türden olduğunu anlıyoruz.

double fonk1() {

...

... Fonksiyonun ana bloğu

...

(10)

void Anahtar Sözcüğü

Bir fonksiyonun parametre değişkeni ya da geri dönüş değeri olmak zorunda değildir. Bir fonksiyonun parametre değişkeni olmadığı iki şekilde belirtilebilir:

•Fonksiyon parametre parantezinin içi boş bırakılır, yani buraya hiçbirşey yazılmaz.

•Fonksiyon parametre parantezinin içine void anahtar sözcüğü yazılır.

fonk() fonk(void)

{ {

... ...

} }

Yukarıdaki tanımlamalar C'de aynı anlama gelmiyor. Fonksiyon prototipleri konusunu öğrenirken bu iki tanımlama arasındaki farkı da öğrenmiş olacağız. Şimdilik bu iki tanımlamanın aynı anlama geldiğini ve fonksiyonun parametre almadığını belirttiklerini varsayacağız.

(11)

Geri dönüş değerine ihtiyaç duyulmadığı durumlarda da geri dönüş değerinin türü yerine void anahtar sözcüğü yerleştirilir. Örneğin:

void sample(void) {

...

}

Yukarıda tanımlanan sample fonksiyonu parametre almamakta ve bir geri dönüş değeri de üretmemektedir.

Fonksiyon tanımlarken geri dönüş değeri yazılmayabilir. Bu durum geri dönüş türünün olmadığı anlamına gelmez. Eğer geri dönüş değeri yazılmazsa, C derleyicileri tanımlanan fonksiyonun int türden bir geri dönüş değerine sahip olduğunu varsayarlar. Örneğin :

sample2() {

...

}

Tanımlanan sample2 fonksiyonunun parametresi yoktur ama int türden bir geri dönüş değeri vardır.

(12)

C dilinde fonksiyon içinde fonksiyon tanımlanamaz!

Örneğin aşağıdaki durum error oluşturur, çünkü sample2 fonksiyonu sample1 fonksiyonunun içinde tanımlanmıştır:

double sample1() {

...

int sample2() /* error */

{

...

} ...

}

tanımlamanın aşağıdaki şekilde yapılması gerekirdi : double sample1()

{

...

}

int sample2() {

...

}

(13)

Fonksiyonların Çağırılması (function calls)

C dilinde fonksiyon çağırma operatörü olarak () kullanılmaktadır. Bir fonksiyon çağırıldığı zaman programın akışı fonksiyonu icra etmek üzere bellekte fonksiyonun kodunun bulunduğu bölgeye atlar, fonksiyonun icra edilme işlemi bittikten sonra da akış tekrar çağıran fonksiyonun kalınan yerinden devam eder.

Bir fonksiyonun geri dönüş değeri varsa, fonksiyon çağırma ifadesi geri dönüş değerini üretir.

Geri dönüş değeri bir değişkene atanabileceği gibi doğrudan aritmetik işlemlerde de kullanılabilir. Örneğin:

sonuc = hesapla();

Burada hesapla fonksiyonunun çağırılma ifadesiyle üretilen geri dönüş değeri sonuc değişkenine atanmaktadır. Bir başka deyişle bir fonksiyon çağırma ifadesinin ürettiği değer, ilgili fonksiyonun ürettiği (eğer üretiyorsa) geri dönüş değeridir. Yukarıdaki örnekte önce hesapla() fonksiyonu çağırılacak daha sonra fonksiyonun icra

(14)

Fonksiyonlar ancak tanımlanmış fonksiyonların içerisinden çağırılabilirler. Blokların dışından fonksiyon çağırılamaz. Çağıran fonksiyon ile çağırılan fonksiyonun her ikisi de aynı amaç kod içerisinde bulunmak zorunda değildir. Çağıran fonksiyon ile çağırılan fonksiyon farklı amaç kodlar içerisinde de bulunabilir. Çünkü derleme işlemi sırasında bir fonksiyonun çağırıldığını gören derleyici, amaç kod içerisine (yani .obj içine) çağırılan fonksiyonun adını ve çağırılış biçimini yazmaktadır. Çağıran fonksiyon ile çağırılan fonksiyon arasında bağlantı kurma işlemi, bağlama aşamasında, bağlayıcı program (linker) tarafından yapılır.

Bu nedenle tanımlanan bir fonksiyon içerisinde, var olmayan bir fonksiyon çağırılsa bile derleme aşamasında bir hata oluşmaz. Hata bağlama aşamasında oluşur. Çünkü

bağlayıcı çağırılan fonksiyonu bulamayacaktır.

Bütün C programları çalışmaya main fonksiyonundan başlar. Programın başladığı nokta olma dışında main fonksiyonunun diğer fonksiyonlardan başka hiçbir farkı yoktur. main fonksiyonun icrası bitince program da sonlanır. Bir C programının

(15)

Değer döndürmeyen bir fonksiyonun tanımlanması ve çağırılması:

(16)

Değer döndüren bir fonksiyona örnek:

(17)

return İfadesi

Bir fonksiyonun geriye değer döndürüp döndürmemesi, o fonksiyonu genel yapı içersinde nasıl kullanacağınıza bağlıdır. Eğer hazırlayacağınız fonksiyonun, çalışıp, üreteceği sonuçları başka yerlerde kullanmayacaksanız, fonksiyondan geriye değer dönmesi gerekmez. Ancak fonksiyonun ürettiği sonuçları, bir değişkene atayıp

kullanacaksanız, o zaman fonksiyonun geriye değer döndürmesi gerekir. Bunun için 'return' ifadesini kullanırız.

Geriye değer döndürmeyen fonksiyonları tanımlarken, başına void koyuyorduk. Geriye değer döndüren fonksiyonlar içinse, hangi tipte değer dönecekse, onu fonksiyon

adının başına koyuyoruz. Diyelim ki fonksiyonumuz bir tamsayı döndürecekse, int; bir karakter döndürecekse char diye belirtiyoruz. Fonksiyon içersinden neyin döneceğine gelince, burada da return ifadesi devreye giriyor.

Fonksiyonun neresinde olduğu farketmez, return sonuç döndürmek üzere kullanılır.

Döndüreceği sonuç, elle girilmiş veya değişkene ait bir değer olabilir. Önemli olan döndürülecek değişken tipiyle, döndürülmesi vaad edilen değişken tipinin

birbirinden farklı olmamasıdır. Yani int kup_hesapla( ) şeklinde bir tanımlama yaptıysanız, double tipinde bir sonucu döndüremezsiniz. Daha doğrusu

döndürebilirsiniz ama program yanlış çalışır. Tip uyuşmazlığı genel hatalardan biri olduğu için, titiz davranmanız gerekir.

(18)

Dikkat edilmesi gereken bir diğer konu; return koyduğunuz yerde, fonksiyonun derhâl sonlanmasıdır. Fonksiyonun kalan kısmı çalışmaz.

Geriye değer döndürmeyen fonksiyonlar için de aynı durum geçerlidir, onlarda da return ifadesini kullanabilirsiniz. Değer döndürsün, döndürmesin yazdığınız fonksiyonda herhangi bir yere 'return;' yazın. Fonksiyonun bu noktadan

itibaren çalışmayı kestiğini fark edeceksiniz.

Bu fonksiyonu çalıştırmanın uygun olmadığı şartlarda, kullanabileceğiniz bir yöntemdir. Bir kontrol ekranında, kullanıcı adı ve/veya şifresini yanlış

girildiğinde, programın çalışmasını anında kesmek isteyebilirsiniz. Böyle bir durumda 'return;' kullanılabilir.

(19)

Fonksiyon Prototipleri

Bildiğiniz gibi fonksiyonlarımızı, main( ) üzerine yazıyoruz. Tek kısa bir fonksiyon için bu durum rahatsız etmez; ama uzun uzun 20 adet fonksiyon olduğunu düşünün. main( ) fonksiyonu sayfalar dolusu kodun altında kalacak ve okunması güçleşecektir. Fonksiyon prototipleri burada devreye girer.

Daha önce yazdığımız programı tekrar yazalım. Ama bu sefer, fonksiyon prototipi yapısına uygun olarak bunu yapalım.

(20)

Yukarıdaki programda

alan( ) fonksiyonunu, main( ) fonksiyonundan önce yazmadık. Sadece böyle bir fonksiyon olduğunu ve alacağı parametre tiplerini bildirdik.

( İsteseydik parametre adlarını da yazabilirdik ama buna gerek yok. ) Daha sonra main( ) fonksiyonu altına inip, fonksiyonu yazdık.

(21)

Elektrik Alan hesaplayan fonksiyon

(22)

Bu fonksiyonun prototip ile yazılması

(23)

Rekürsif Fonksiyonlar

Bir fonksiyon içersinden, bir diğerini çağırabiliriz. Rekürsif fonksiyonlar,

fonksiyon içersinden fonksiyon çağırmanın özel bir hâlidir. Rekürsif fonksiyon bir başka fonksiyon yerine kendisini çağırır ve şartlar uygun olduğu sürece bu tekrarlanır. Rekürsif, Recursive kelimesinden geliyor ve tekrarlamalı,

yinelemeli anlamını taşıyor. Kelimenin anlamıyla, yaptığı iş örtüşmekte.

Rekürsif fonksiyonları bir kenara bırakığ, bildiğimiz yöntemle 1, 5, 9, 13 serisini oluşturan bir fonksiyon yazalım:

(24)

Bu fonksiyonu yazmak oldukça basitti. Şimdi aynı işi yapan rekürsif bir fonksiyon yazalım:

Son yazdığımız programla, bir önce yazdığımız program aynı çıktıları üretir.

Ama birbirlerinden farklı çalışırlar.

(25)

İkinci programın farkını akış diyagramına bakarak sizler de görebilirsiniz.

Rekürsif kullanım, fonksiyonun tekrar tekrar çağrılmasını sağlamıştır.

(26)

Faktöriyel hesaplayan fonksiyonu, rekürsif olarak yazalım:

(27)

faktöriyel hesaplaması yapılırken, adımları görmenizi istiyorum. Adım olarak geçen her kutu, fonksiyonun bir kez çağrılmasını temsil ediyor. Başlangıç kısmını geçerseniz fonksiyon toplamda 5 kere çağrılıyor.

(28)

Rekürsif yapılar, oldukça karmaşık olabilir. Fakat kullanışlı oldukları kesin.

Örneğin silme komutları rekürsif yapılardan yararlanır. Bir klasörü altında bulunan her şeyle birlikte silmeniz gerekiyorsa, rekürsif fonksiyon

kaçınılmazdır. Ya da bazı matematiksel işlemlerde veya arama ( search ) yöntemlerinde yine rekürsif fonksiyonlara başvururuz. Bunların dışında rekürsif fonksiyonlar, normal fonksiyonlara göre daha az kod kullanılarak yazılır. Bunlar rekürsif fonksiyonların olumlu yönleri... Ancak hiçbir şey mükemmel değildir.

Rekürsif fonksiyon kullanmanın bilgisayarınıza bindereceği yük daha fazladır.

Faktoriyel örneğine bakın; tam 5 kez aynı fonksiyonu çağırıyoruz ve bu sırada bütün değerler bellekte tutuluyor. Eğer çok sayıda iterasyondan söz ediyorsak, belleğiniz hızla tükenecektir. Rekürsif yapılar, bellekte ekstra yer kapladığı gibi, normal fonksiyonlara göre daha yavaştır. Üstelik kısa kod yazımına karşın,

rekürsif fonksiyonların daha karmaşık olduklarını söyleyebiliriz. Anlamak zaman zaman sorun olabiliyor. Kısacası bir programda gerçekten rekürsif yapıya

ihtiyacınız olmadığı sürece, ondan kaçınmanız daha iyi!

(29)

Matematiksel İşlemler

Matemetik kütüphanesi math.h kullanılarak kütüphane içerisindeki hazır matematiksel işlemler yapılabilir.

Sıkça kullanılan matematiksel fonksiyonlar.

• double ceil( double n ) : Virgüllü n sayısını, kendisinden büyük olan ilk tam sayıya tamamlar. Örneğin ceil(51.4) işlemi, 52 sonucunu verir.

• double floor( double n ) : Virgüllü n sayısının, virgülden sonrasını atarak, bir tam sayıya çevirir. floor(51.4) işlemi, 51 sayısını döndürür.

• double fabs( double n ) : Verilen n sayısının mutlak değerini döndürür. fabs(- 23.5), 23.5 değerini verir.

• double fmod( double a, double b ) : a sayısının b sayısına bölümünden kalanı verir. (Daha önce gördüğümüz modül (%) operatörü, sadece tam sayılarda

kullanılırken, fmod fonksiyonu virgüllü sayılarda da çalışır.)

(30)

• double pow( double a, double b ) : Üstel değer hesaplamak için kullanılır;

ab değerini verir.

• double sqrt( double a ) : a'nın karekökünü hesaplar.

Bu fonksiyonlardan herhangi birini kullacağınız zaman, program kodununun başına #include<math.h> yazmalısınız.

Ayrıca derleyici olarak gcc'yle çalışıyorsanız, derlemek için -lm parametresini eklemeniz gerekir. (Örneğin: "gcc –o –lm test test.c " gibi...)

(31)

Üslü sayılarla işlem yapmak

Programlarınızda kullandığınız değişkenler veya sabitler her zaman tam sayı veya ondalık şeklinde yazabileceğiniz sayılar olmayabilir. Bazen pozitif veya negatif üslü sayılarla işlem yapmanız gerekebilir.

Örneğin elektrik alan hesabında kullanmanız gereken k=8,99x 109 sabitini programınızda nasıl yazarsınız bunu göreceğiz.

k=8,99e+9

Program içerisinde üslü sayı yazarken üslü kısım yerine “e” yanına da üssün kaç olduğu yazılır.

Örneğin elektronun yükünü yazmak için e=1,6x 10-19 e=1,6e-19 yazarsınız

(32)

Elektrik alan hesaplayan programı inceleyelim

(33)

Programın sonucunu dosyaya yazdırma.

Programda yaptığımız işlemlerin sonucunu çok büyük olduğunda veya sonuçları saklamak istediğimizde bunları bir dosyaya yazdırabiliriz.

Bunun için program içerisinde sonuçların kaydedileceği bir dosya tanımlamamız gerekir.

FILE *output;

Bu şekilde dosyayı tanımladıktan sonra program içerisinde programın

sonuçları kaydedeceği yere bir isim verip bunu açmasını programa iletmemiz gerekiyor.

Dosyayı açtıktan sonra yapacağımız işlem sonuçları bu dosyaya yazdırmak olacaktır.

Son olarak ta açtığımız bu dosyayı kapatmamız gerekiyor. Bunun içinde kullanacağımız komut.

(34)

Bu yazdıklarımızı bir örnekle açıklayalım.

Program bize sonucun yazdırıldığı alan.txt adında bir dosya verecektir.

(35)

Potansiyel enerji hesaplayan ve sonucu dosyaya yazdıran bir program yazalım

(36)

Potansiyel enerji hesaplayan ve sonucu dosyaya yazdıran bir program yazalım

(37)

Fahrenheit ı Celcius a çeviren bir program yazın.

Referanslar

Benzer Belgeler

Alacağı rehinle teminat altına alınmış olan bir alacaklı, o alacağını cebri icra yoluyla tahsil etmek isterse, borçluya karşı, kural olarak önce rehnin paraya çevrilmesi

Ekrana 10 kere &#34;Merhaba Dünya&#34; yazan bir programda, &#34;Merhaba Dünya&#34; yazdıran kodu aslında tek bir defa yazarsınız, döngü burada devreye girip, sizin için bu

Takip Talebinde Bulunmanın İcra Hukuku Bakımından Sonuçları ...100.. Takip Talebinde Bulunmanın Maddî Hukuk Bakımından

İcra ve iflas dairelerince yapılacak her türlü icra ve iflas iş ve işlemlerinde Ulusal       Yargı Ağı Bilişim Sistemi kullanılır; her türlü veri, bilgi, belge ve

Konunun daha iyi anlaşılabilmesi için, yarar fonksiyonu

Burada x= c için fonksiyonun tanımsız olması limitin var olmasına engel değildir..

Takip eden türev kurallarının hepsi türevin limit tanımı

Grafikte, 0 noktasından istenen toplam ürün eğrisi üzerindeki noktaya çizilen çizginin eğimi işçinin ortalama ürününü verir (grafikler için bkz. P&amp;R sayfa 183)