Fonksiyonlar, parametre 
  parantezleri içerisinde belirtilmiş argüman sayısı kadar parametre değişkenine 
  sahip olabilirler. Dolayısıyla biz bir fonksiyonu çağıracağımız zaman, bu fonksiyona 
  aktaracağımız parametre değişkenlerinin sayısı bellidir. Ancak C dili, argüman 
  sayısı değişebilen fonksiyonlar tanımlanmasına da olanak tanır. C dilinde fonksiyon 
  tanımlamanın en genel biçimi şöyledir :
  
 
   
     [geri_dönüş_değeri_türü] 
      <fonksiyon_adı> ([parametre_değişkenleri]) 
      { 
              //fonksiyonun yaptığı işler 
      }
  
   
 
Fonksiyon tanımlaması 
  sırasında, fonksiyona aktarılacak parametre değişkenlerinin sayısı da belirtilmiş 
  olur. Örneğin :
  
 
   
     int topla 
      (int sayi1, int sayi2) 
      { 
                return sayi1 + sayi2; 
      }
  
   
 
şeklinde bir fonksiyon 
  tanımlanmışsa, çağrım sırasında fonksiyona iki tane parametre değişkeni aktarılır. 
  Peki, öyle bir durumla karşı karşıya kalalım ki bu sayı değişebilir olsun. Bu 
  sayı kimi durumlarda iki, kimi durumlarda üç vs şeklinde olsun. Bu durumda ne 
  yapacağız ? Bu sorunun cevabı, bugünkü makalemizin konusunu oluşturuyor. C dilinde, 
  parametre değişkeni sayısı değişken olan fonksiyonlar yazılabilir. Bu konuda 
  iyi bilinen bir örnek standart printf fonksiyonudur. Ekrana kaç değer yazdırmak 
  istersek isteyelim, her defasında printf fonksiyonu ile bunu gerçekleştirebiliyoruz. 
  
  
Değişken argümana 
  sahip fonksiyon yazarken mutlaka en az bir argüman ismi ile belirtilmelidir. 
  Fonksiyonun tanımlanması sırasında, bu isim başlangıç noktası olarak kullanılacaktır. 
  Argüman sayısının belirsiz olduğunu derleyiciye anlatmak için argüman listesinin 
  sonuna üç nokta (...) operatörü yazılır. (Ellipsis operatörü) İsmi ile verilen argümanlara "isimlendirilmiş 
  argümanlar", üç nokta ile belirtilmiş sayısı belirsiz olan argümanlara 
  ise "isimlendirilmemiş argümanlar" denilmektedir. Bir örnekle durumu 
  açıklayalım :
  
   
    int topla 
      (int a,...) 
      { 
           //... 
      }  | 
   
 
Bu tanımlamada, 
  tamsayı türünde olan a argümanı isimlendirilmiş argümandır. Üç nokta ile belirtilen 
  diğer argümanlar ise isimlendirilmemiş argümanlardır. Bu fonksiyonu çağıracağımız 
  zaman parametre parantezi içerisine bir tane tamsayı türünde değişken ve sayısını 
  çağırma sırasında belirleyeceğimiz kadar değişken yazabiliriz. Bu tamamen programcıya 
  kalmıştır. Fonksiyon içerisinde belli araçlar kullanarak, fonksiyona aktarılmış 
  tüm parametre değişkenlerine ulaşabiliriz. Bu şekilde tanımlanmış bir fonksiyon 
  aşağıdaki şekillerde çağrılabilir :
  
   
     
      { 
           int a = 10; 
           int sonuc; 
           //... 
           sonuc = topla(a,1,2,3); 
           sonuc = topla(a,1); 
           sonuc = topla(a,1,5,8,9,34);  }
  
     | 
   
 
Fonksiyonun tanımlanması 
  sırasında argümanlara isimleriyle ulaşıyoruz. Peki bu isimlendirilmemiş argümanlara 
  nasıl ulaşacağız ? Bunun için öncelikle "include" önişlemci direktifi 
  ile "stdarg.h" başlık dosyasını kodumuza eklememiz gerekir. Bu başlık 
  dosyası, böyle bir fonksiyonun oluşturulması için tanımlanmış özel bir tip ve 
  üç tane makro içermektedir. Fonksiyon içerisinde bunları kullanarak isimlendirilmemiş 
  argümanlara ulaşabileceğiz. Söz konusu özel tip, çoğu derleyicide va_list ismi 
  ile kullanılır. Diğer üç makronun isimleri de va_arg, va_start ve va_end’dir. 
  
  
 
   
     
  
   
 
   
     
      ADI
  
     | 
     
      İŞLEVİ
  
     | 
     
      BİLDİRİMİ
  
     | 
   
   
     
      va_list
  
     | 
    va_list 
      tipi, va_arg ve va_end tarafından ihtiyaç duyulan bilgileri içeren bir dizidir. 
      Fonksiyonun başında bu tipten bir nesne tanımlanır. Bu nesneye argüman işaretçisi 
      diyelim. | 
    typedef 
      char *va_list | 
   
   
     
      va_start
  
     | 
    va_start 
      makrosu ile argüman işaretçisi, fonksiyona aktarılan ilk isimlendirilmemiş 
      argümana konumlandırılır. Dolayısıyla işleme başlarken öncelikle bu fonksiyonu 
      çağırmamız gereklidir. Bu makro çağrıldıktan sonra, argüman işaretçisine 
      ilk değer ataması yapılmış olur. | 
    void 
      va_start(va_list vl, isimlendirilmis_arguman); | 
   
   
     
      va_arg
  
     | 
    va_arg 
      makrosu ile eğer argüman işaretçisi fonksiyona aktarılan isimlendirilmemiş 
      argümanlardan ilki üzerine konumlanmışsa, isimlendirilmemiş argüman listesindeki 
      bir sonraki argümana ulaşım sağlanır. va_arg makrosu, argüman işaretçisinin 
      değerini de değiştirir. Bu şekilde adım adım ilerlenerek makro her çağrıldığında, 
      listedeki bir sonraki isimlendirilmemiş argümana ulaşılır. | 
    arguman_tipi 
      va_arg(va_list vl, arguman_tipi); | 
   
   
    | va_end | 
    va_end 
      makrosu ile fonksiyondan çıkılmadan önce birtakım düzenlemelerin yapılması 
      sağlanır. Bu makro fonksiyon tanımlamasından çıkılmadan önce mutlaka bir 
      defa çağrılmalıdır. | 
    void 
      va_end(va_list vl); | 
   
 
Örnek olarak çokgenlerin 
  çevresini hesaplayacak bir fonksiyon yazalım. Bir çokgen üç, dört, beş vb kenara 
  sahip olabilir. Sadece bir fonksiyon yazıp, tüm çokgenler için bu fonksiyonu 
  kullanarak işimizi halletmek istiyorsak, değişken sayıda argümana sahip olabilecek 
  bir fonksiyon yazmak iyi bir çözüm olabilir. Fonksiyonumuzun prototip bildirimini 
  yapalım :
  
   
    
      
        double 
          CevreBul(int kenar_sayisi,...);
  
       
     | 
   
 
Görüldüğü üzere 
  fonksiyonumuz bir isimlendirilmiş parametreye ve isimlendirilmemiş parametrelere 
  sahip. (En az bir tane isimlendirilmiş parametre olması gerektiğini hatırlayınız) 
  Şimdi fonksiyonumuzun tanımına geçelim :
  
   
     
       
        double 
          CevreBul(int kenar_sayisi,...) 
          { 
             va_list argList; 
             double arg; 
             double toplam = 0.0; 
             int i;   va_start(argList,kenar_sayisi); 
             for (i = 0; i < kenar_sayisi; ++i) 
             { 
                arg = va_arg(argList,double); 
                toplam += arg; 
             }    va_end(argList); 
             return toplam; 
          }
  
       
     | 
   
 
Fonksiyonun kodunu 
  inceleyelim. İlk olarak va_list tipinden argList isimli bir nesne tanımladık. 
  Bu nesne, argüman işaretçisi ismiyle anılır ve yukarıda bahsettiğimiz makrolarla 
  beraber kullanılarak fonksiyona aktarılan parametre değişkenlerine ulaşmamızı 
  sağlar. double türünde tanımladığımız arg isimli nesne, fonksiyon içerisinde 
  sırayla ulaşacağımız parametre değişkenlerini tutacak. toplam isimli double 
  türünden nesne ise, parametre değişkenlerinin toplam değerini tutacak. Fonksiyonun 
  ilk parametresi, çokgenin kenar sayısı bilgisini tutuyor. İlk olarak va_start 
  makrosunu çağırarak argüman işaretçisinin ilk isimsiz parametreye konumlanmasını 
  sağlıyoruz. Çevre değerini hesaplarken, kenar_sayisi parametre değişkenini döngünün 
  kaç kez döneceği bilgisi olarak kullanabiliriz. Döngü içerisindeki ilk satırda, 
  va_arg makrosu ile sıradaki parametre değişkenine ulaşıyoruz, ve bu değeri arg 
  nesnesinde saklıyoruz. arg nesnesinde saklanan bu değeri her adımda toplam isimli 
  nesneye ekliyoruz. Döngüden çıkıldığında, va_end makrosunu çağırarak gerekli 
  düzenlemelerin yapılmasını sağlıyoruz ve toplam nesnesinin değerine dönüyoruz. 
  Artık bu fonksiyonu istediğimiz sayıda kenara sahip olan bir çokgenin çevresini 
  bulmak için kullanabiliriz. 
  
   
     
       CevreBul(3,10.0,10.0,10.0); 
                //Kenar uzunlukları 10 olan üçgenin çevresi
  CevreBul(4,10.0,20.0,30.0,40.0);
         //Kenar uzunlukları 10, 20, 30, 40 olan çokgenin çevresi 
     | 
   
 
Bu çağırmalar sonucunda 
  ekrana sırasıyla 30.0 ve 100.0 değerleri yazacaktır. Bir sonraki makalemizde görüşmek üzere...
  
   
  
  Kaynak 
    kod için tıklayın.
  
   
                
                Makale: 
                Farklı Sayıda Argümana Sahip Olabilen Fonksiyonlar C ve Sistem Programlama Çiğdem Çavdaroğlu 
             |