Diğer programlama dillerinde olduğu gibi C Programlama Dili içinde fonksiyonlar konusu en önemli konuların başında gelmektedir. Programlama dilleri içinde fonksiyonlar temel yapı taşıdır. Yazılan programların yeniden kullanılabilirliğini, kodun okunurluğunu artırmak ve kodun bakımı kolaylaştıran en önemli etken fonksiyonlardır. C Programlama Dili Fonksiyonlar konusunu toplamda 3 konu olarak ayıracağız. Tüm başlıklar aşağıdaki gibidir. İlk dört başlık bu konu altında ele alınacaktır.
Fonksiyonlar başlığında bulabileceğiniz içerikler:
- C Programlama Dilinde fonksiyonlar nedir?
- C Programlama Dilinde fonksiyonlar nasıl kullanılır?
- C Programlama Dilinde fonksiyon tanımlama, bildirme, fonksiyon çağırma ve örnek program
- C Programlama Dilinde fonksiyon nasıl çağrılır?
- Değerine göre çağırma
- Referansına göre çağırma
- Parametreli ve dönüş (return) değerlerine göre C Programlama Dilinde fonksiyonlar
- Parametreli ve dönüş değeri olan C fonksiyonu
- Parametreli ve geri dönüş değeri olmayan C fonksiyonu
- Parametresiz ve dönüş değeri olmayan C fonksiyonu
- Parametresiz ve dönüş değeri olan C fonksiyonu
- C Programlama Dilinde fonksiyon tipleri
- header fonksiyonları
- Kullanıcı tanımlı fonksiyonlar
- C header fonksiyonu oluşturma / ekleme
- C Programlama Dilinde komut satırı parametreleri
- C Programlama Dilinde değişken uzunluk parametreleri
1. C Fonksiyonları Nedir?
Orta ve büyük ölçekli bir programda fonksiyonlar programın temel yapı taşıdır. C fonksiyonları, programın belirli işlemini gerçekletirir ve küme parantezi ‘{}’ ile başlayıp sonlanır. Yani, programı fonksiyonlar oluşturur.
2. C Fonksiyonları Nasıl Kullanılır?
- C fonksiyonları bir program içerisinde tekrar tekrar aynı mantık içerisinde yeniden yazmamak için kullanılır
- Gerekli her yerde aynı işlevi sağlayacak kodlar yazmamak için istenildiği kadar fonksiyonlar çağrılır ve kullanılır.
- Fonksiyonlara ayrılmış büyük bir C programı kolayca anlaşılır, geliştirilir ve bakımı kolay olur.
- Büyük bir işi yapan bir fonksiyon küçük fonksiyonlara ayrılarak temel görevlere ayrılabilir.
3. C Fonksiyonları Tanımlama, Bildirme, Fonksiyon Çağırma ve Örnek Program
Her bir C fonksiyonunun üç farklı görünüşü vardır.
- Fonksiyon bildirimi veya prototip – Derleyiciyi fonksiyon adı,fonksiyon parametreleri ve dönüş değerinin veri türü hakkında bilgilendirir.
- Fonksiyonu çağırma – Fonksiyonun işlevini yapması için fonksiyonu çağırmak gerekir.
- Fonksiyon tanımımlama – Bu yürütülecek tüm ifadeleri içerir ve sadece tanımlama işlemi yapar.
C Fonksiyon Görünüşleri | Syntax |
Fonksiyon bildirimi veya prototip | [Geri Dönüş Tipi] [Fonksiyon Adı](Parametre(zorunlu değil)){
Fonksiyon içerisindeki kodlar (body); } |
Fonksiyonu çağırma | fonksiyonAdi(gönderilen parametre/parametreler(zorunlu değil)) |
Fonksiyon tanımı | [Geri Dönüş Tipi] [Fonksiyon Adı](Parametre(zorunlu değil)); (fonksiyon içeriği (body) bulunmuyor) |
Basit Bir C Fonksiyon Örneği
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include<stdio.h>
/*
*Geri dönüş tipi float
*fonksiyon adı kareAlanHesapla
*Parametre: float tipinde bir parametre almaktadır.
*/
float kareAlanHesapla(float x); //main fonksiyonundan önce tanımlanmalıdır.
int main() {
float kenar = 11.2;
float alan;
alan = kareAlanHesapla(kenar);
printf("Bir kenarı %f olan karenin alani = %f'dir\n", kenar, alan);
return 0;
}
float kareAlanHesapla(float x) {
return x * x;
}
|
Çıktı:
Bir kenarı 11.200000 olan karenin alani = 125.439995’dir |
- Bildiğiniz gibi C programlama dilinde fonksiyonu kullanmadan önce bu fonksiyonun geri dönüş tipi, fonksiyon adı ve aldığı parametrelerle önce tanımlanmalıdır (main üstünde). Eğer fonksiyonu main’in üstüne yazarsanız bu tanımlama işlemini yapmanıza gerek yoktur. Bu şekilde program yazmanız kesinlikle önerilmez. Başka fonksiyon yazdığınızda ve diğer fonksiyonu kullanmak istediğinizde de bu fonksiyonu onun üstüne yazmak zorundasınız. Bu durumda hangi fonksiyonun hangi fonksiyonunu kullanacağını önceden düşünüp ona göre fonksiyonları sıralamanız gerekebilir. Bazı durumlarda bunu sağlayabilirsiniz ama karışık işlerde çok saçma bir iş yapmış olursunuz.
- main fonksiyonu üzerine kareAlanHesapla fonksiyonu tanımlandı. Tanımlama işleminde parametrelere isim vermeyebilirsiniz.
1 |
float kareAlanHesapla(float);
|
1 |
float kareAlanHesapla(float x);
|
Ben genellikle tanımlama işleminde parametreye isim vermiyorum. float tipinden bir parametre alacağını belirtmeniz de yeterlidir.
- Fonksiyon float tipinden bir dönüş yapacağından main içerisinde float tipinde alan değişkeni tanımlanmıştır. fonksiyon işlemi bittikten sonra geri dönüş olarak bir float değeri dönderir ve bu değer alan değişkenine aktarılır.1alan = kareAlanHesapla(kenar);
- Fonksiyon içerisinde x değişkenini tanımlamamıza gerek yoktur. Parametre ile gelen değerler zaten tanımlıdır. Bu yüzden
1
2
3
|
float kareAlanHesapla(float x) { //float x zaten bu alanda tanımlandı.
.....
}
|
1
2
3
|
float kareAlanHesapla(float x) {
float x; //HATALI
}
|
Bu şekilde tanımlama yapılmaz.
- Fonksiyon dönüş tipi olduğundan dolayı (dönüş yapmayan fonksiyonlarda vardır. Bu fonksiyonlar void olarak bilinir ve bu şekilde kullanılır.) fonksiyon içerisinde return ile bir değer döndürür.
1 |
return x * x;
|
x*x işlemi yapılır ve geri dönüş olarak bu değer döndürülür.
İstenilirse işlem önceden yapıp sadece değişkende döndürülebilir.
1
2
3
4
5
6
|
float kareAlanHesapla(float x) {
float sonuc;
sonuc = x * x;
return sonuc;
}
|
Bu fonksiyon ile diğeri arasında hiçbir fark yoktur. Kısa bir fonksiyon olacak ise return değeri içerisinde dönderme işlemi yapabilirsiniz. Tamamen kodun okunabilirliği için dikkat edilir. Herhangi bir kural yoktur. Bu konuda kendinizi geliştirmeniz önemlidir. Robert C. Martin’in Clean Code isimli kitabını okumanızı öneririm.
4. C Programlama Dilinde Fonksiyon Nasıl Çağrılır?
C programlama dilinde fonksiyon çağırma işlemi iki farklı yolla yapılabilir.
- Değerine göre çağırma
- Referansına göre çağırma
4.1. Değeri Göre Çağırma
- Parametre olarak değişkenler gönderilir.
- Örneğin main içerisinde gönderilen değişken sadece main içerisinde değiştirilebilir. Fonksiyon içerisinde ki değişim main içerisindeki değişkeni değiştirmez. Örnek üzerinde daha detaylı anlatım yapılacaktır.
Değerine Göre Çağırma Örneği
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include<stdio.h>
void takas(int, int);
int main() {
int sayi1 = 15, sayi2 = 33;
printf("1)main ici:\nsayi1:%d sayi2:%d\n", sayi1, sayi2);
takas(sayi1, sayi2);
printf("\n2)main ici:\nsayi1:%d sayi2:%d\n", sayi1, sayi2);
return 0;
}
void takas(int sayi1, int sayi2) {
int gecici;
gecici = sayi1;
sayi1 = sayi2;
sayi2 = gecici;
printf("\ntakas fonksiyonu ici:\nsayi1:%d sayi2:%d\n", sayi1, sayi2);
}
|
Çıktı:
1)main ici: sayi1:15 sayi2:33takas fonksiyonu ici: sayi1:33 sayi2:152)main ici: sayi1:15 sayi2:33 |
Örneği inceleyelim;
- sayi1 = 15, sayi2 = 33 olarak tanımlandı.
- ekrana sayi1 ve sayi2 değerleri gösterildi.
- takas fonksiyonuna sayi1 ve sayi2 gönderildi.
- void geri dönüşe sahip olan takas fonksiyonu geri dönüşü yoktur. Void fonksiyonlarda return bulunmaz (Bazı özel durumlarda bulunmatadır. Bu konular ileri seviye olduğu için bu konu da bahsedilmeyecektir.)
- takas fonksiyonu içerisinde ki sayi1 ve sayi2 değişkenleri main fonksiyonundaki sayi1 ve sayi2 değişkenlerinden farklıdır. Farklı bellek alanlarında değerleri tutulmaktadır.
- takas fonksiyonunda sayi1 ve sayi2 değerleri yer değiştirilir ve ekranda gösterilir.
- takas fonksiyonu görevini tamamladıktan sonra main fonksiyonunda bir alt satıra geçiş yapar ve program devam eder.
- Tekrar sayi1 ve sayi2 değerleri ekranda gösterilir.
- Dikkat edilmesi gereken nokta main fonksiyonu içerisinde 2 printf de aynı değerleri göstermektedir. Çünkü takas fonksiyonu içerisindeki sayi1 ve sayi2 farklı bellek adreslerinde tutuluyor. takas fonksiyonun da sayi1 ve sayi2 nin değerlerini yer değiştirmemiz main fonksiyonunda bir etkisi olmadı.
4.2. Referansına Göre Çağırma
- Parametre olarak değişkenlerin adresi gönderilir.
- main fonksiyonu içerisindeki değişken adres gönderildiğinden dolayı gönderilen fonksiyonda da değiştirilebilir.
Referansına Göre Çağırma Örneği
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include<stdio.h>
void takas(int *, int *);
int main() {
int sayi1 = 15, sayi2 = 33;
printf("1)main ici:\nsayi1:%d sayi2:%d\n", sayi1, sayi2);
takas(&sayi1, &sayi2);
printf("\n2)main ici:\nsayi1:%d sayi2:%d\n", sayi1, sayi2);
return 0;
}
void takas(int *sayi1, int *sayi2) {
int gecici;
gecici = *sayi1;
*sayi1 = *sayi2;
*sayi2 = gecici;
printf("\ntakas fonksiyonu ici:\nsayi1:%d sayi2:%d\n", *sayi1, *sayi2);
}
|
Çıktı:
1)main ici: sayi1:15 sayi2:33takas fonksiyonu ici: sayi1:33 sayi2:152)main ici: sayi1:33 sayi2:15 |
- Bu örnekte main içerisinde tanımlanmış sayi1 ve sayi2 değişkenlerinin adresleri takas fonksiyonuna gönderildi.
- Adres gönderildiği için atamalar pointerlara yapılmak zorundadır.
- takas fonksiyonu içerisindeki *sayi1 ve *sayi2 main fonksiyonu içerisindeki sayi1 ve sayi2’nin adreslerini referans olarak göstermektedir ve bu değişkenlerin adresleri üzerinden direk değişiklik yapmamıza imkan sağlar.
- takas fonksiyonunda sayi1 ve sayi2 değerleri yer değiştirildiğinde aynı değişiklik main fonksiyonu içerisinde de görülmektedir.