Fonksiyon tanimi
Fonksiyon blogunun yapisi;
dönüs_tipi fonksiyon_adi(parametre listesi)
{
islem blogu
}
dönüs_tipi, fonksiyonun sonucu, fonksiyonun çagirildigi noktaya gidecek olan degerin tipini belirtir. Fonksiyonlar dizi hariç her tür veri tipi döndürebilirler. Parametre listesi ise, fonksiyon çagirilirken kulanilmasi gereken degiskenler ve onlarin veri tipleridir. Fonksiyon parametre kullanmadan da çagirilabilir -bos bir parametre listesi için void veri tipinden faydalanilir.
Degisken tanimlamada ayni veri tipine sahip degiskenler, birbirinden virgül ile ayrilarak tanimlanabiliyordu. Fakat fonksiyonlara ait parametre tanimlamasinda bu yöntem kullanilmaz. Parametre tanimlamalarinda her parametre, kendi ver tipi iel tanimlanir. Yani;
f(int i, int k, float f)
dogru iken
f(int i, k, float f)
yanlistir. Ikinci örnekte k degiskeni kendi veri tipine sahip olmalidir.
6.2 Fonksiyonun tanim alani
Her fonksiyon, kendi basina bir kod blogudur. Bu yüzden fonksiyonalr kendi tanim alanlarini olustururlar. Yani fonksiyonun kodu kendine özeldir ve program içinde yer alan herhangi bir ifade tarafindan bu kod parçasina erisilemez. Örnegin bir fonksiyon içinde goto’yu kullanarak baska bir fonksiyonun kodunun herhangi biryerine atlama yapilamaz. Fonksiyonu olusturan kod parçasi programdan saklanir ve bu kisim global degisken kullanmadikça ne programin bir kismi tarafindan etkilenir ne de programin baska bir kismini etkileyebilir.
Bir fonksiyonun içinde tanimlanmis degiskenlere local (yerel) degiskenler adi verilir. Local degiskenler, tanimlandigi fonksiyon çagirildiginda devreye girer ve fonksiyonun çalismasi sona erince kullanimdan kaldirilir. Bu yüzden local bir degisken fonksiyonlar arasinda deger tasimak için kullanilamaz. Deger tasimak için parametreler ve dönüs degerleri kullanilir.
6.3 Fonksiyon argümanlari
Eger fonksiyon argüman alacaksa bunlar parametre listesinde tanimlanmalidir. Örnegin;
int is_in(char *s, char c)
{
while(*s)
if(*s==c) return 1;
else s++;
return 0;
}
is_in fonksiyonunun s ve c olmak üzere 2 parametresi vardir. Bu fonksiyon verilen c karakterinin, s stringinde olup olmadigini kontrol eder.
Parametreler fonksiyonlar arasinda deger tasiam görevini yerine getiriyor olsalar da, fonksiyon içinde local degisken gibi davranirlar. Parametreler’e deger atanabilir veya bir ifade içinde kullanilabilirler.
C’de fonksiyona parametre gönderme islemi 2 ayri sekilde yapilir: Deger ile ve referans ile çagirma.
6.3.1 Deger ile çagirma
Deger ile çagirmada, fonksiyondan kullanilan degilskene argümanin degeri atanir. Bu durumda, fonksiyon içinde argüman üzerinde yapilan islemlerin argümanin çagirilan yerdeki degerini üeridne bir etkisi yoktur. Örnegin;
#include
int sqr(int x)
{
x = x*x;
return(x);
}
void main(void)
{
int t=10;
printf("%d %d", sqr(t), t);
}
kod parçasi gözönüne alindiginda, sqr fonksiyonuna parametre olarak verilen t degiskeninin degeri, fonksiyon içinde x’e atanmistir. x=x*x islemi yapildiginda degisen fonksiyon içinde local degisken olarak kullanilan x’in degeridir. Yani ana programdaki printf satirinin sonucu “100 10” dur.
6.3.2 Referans ile çagirma
Referans ile çagirma, deger yerine, gönderilecek parametrenin adresini gönderme yöntemidir. Fonksiyona gönderilen argüman bir deger degil bir adrestir - yani fonksiyon içinde bu adres kullanilarak,gönderilen argümanlarin degerleri degistirilebilir.
Pointer’larin fonksiyona argüman olarak gönderilmesi, diger tipler ile aynidir. Örnek program, adresleri verilen 2 sayinin degerlerini degistirir;
#include
void swap(int *x, int *y)
{
int temp;
temp = *x; /* save the value at address x */
*x = *y; /* put y into x */
*y = temp; /* put x into y */
}
void main(void)
{
int i, j;
i = 10;
j = 20;
printf("i and j before swapping: %d %d\n", i, j);
swap(&i, &j); /* pass the addresses of i and j */
printf("i and j after swapping: %d %d\n", i, j);
}
Bu örnekte swap() fonksiyonu, degiskenlerin degerlerini degistirebilir çünkü degiskenler fonksiyona deger ile degil referans ile, yani pointer ile gönderilmistir. Adres göndermek için & operatörünün kullanildigina dikakt edilmelidir.
6.3.3 Fonksiyona dizi gönderme
Fonksiyona parametre oalrak dizi gönderilmek istendiginde yapilan sey fonksiyona dizinin adresini göndermektir. Bunun sebebi, dizi adlarinin, dizinin hafizadaki baslangiça adresini vermesidir. Fonksiyon çagirilirken bu bir deger ile çagirilma gibi görünse de, aslinda referans ile çagirmadir ve fonksiyon içinde, gönderilen parametre üzerinde degisiklik yapilabilir. Örnegin;
#include
#include
void print_upper(char *string)
{
register int t;
for(t=0; string[t]; ++t) {
string[t] = toupper(string[t]);
putchar(string[t]);
}
}
void main(void)
{
char s[80];
printf("Enter a string: ");
gets(s);
print_upper(s);
printf("\ns is now uppercase: %s", s);
return 0;
}
print_upper() fonksiyonu, gönderilen stringin karakterleriin teker teker denk gelen büyük harfe çevirir ve ekrana yazar. Burada parametre olarak gönderilen string’in üzerinde degisiklik yapilmaktadir. Eger stringin içeriginin degismesi istenmiyorsa, ekrana yazdirma islemi
void print_upper(char *string)
{
register int t;
for(t=0; string[t]; ++t)
putchar(toupper(string[t]));
}
fonksiyonu ile yapilabilir.
6.4 argc ve argv - main() fonksiyonunun parametreleri
Genelde yazilan programlara deger göndermek gerekebilir. Bu islem komut satirindan, programin adi ile deger göndererek yapilir. Program adi ile birlikte gönderilen degerler, main() ana fonksiyonuna gönderilen parametreler olarak algilanir. Komut satiri argümanlarina , UNIX’te C kodu derelyicisinin kullanimi örnek verilebilir;
cc c_program_adi
C’de, programa argüman göndermek için iki özel degisken tanimlanmistir: argc ve argv. Bu iki degisken komut satirindan argüman almak için kullanilir. argc degiskeni, programa gönderilen argüman sayisini tutar. Bu deger her zaman 1’den büyüktür çünkü program adinin kendisi de bir argüman olarak kabul edilir. argv ise, karakter pointer’lari tutan bri diziyi gösteren pointer’dir. Bu dizideki her pointer, komut satirindan girilen argümanlardan birini göstermektedir.Komut satirindan girilen her agüman string olarak degerlendirilir. Eger bir sayi kullanilacaksa, bu önce uygun string formatina çevrilmelidir.
Örnek program ‘Merhaba’ dan sonra verilen ismi ekrana yazdirir;
#include
#include
void main(int argc, char *argv[])
{
if(argc!=2) {
printf("You forgot to type your name.\n");
exit(1);
}
printf("Hello %s", argv[1]);
}
Koda dikkat edeilecek olunursa, ana fonksiyonun diger örneklerdeki gibi void main(void) olarak degil, void main(int argc, char *argv[]) olarak tanimlandigi görülür. Bu standart fonksiyon tanimlama sekline uygundur ve burada main fonksiyonu int tipinde argc ve char* tipinde bir argv dizisini argüman olarak alir. Programa girildiginde yapilan kontrol, argüman sayisinin dogru olup olmadiginin kontrolüdür. Bu programa test adi verilip derlenirse, programi çagirma sekli,
test isim
seklinde olacaktir. Komut satirinda her argüman bosluk (space) karakteri ile ayrilir. Örnegin;
test ad1 ad2
2 argüman aliyorken, bu satir;
test ad1,ad2
olarak yazilirsa bir argüman alir. argv argümaninin, char *argv[] olarak tanimlanmasi, argüman olarak verilen dizinin eleman sayisinin belli olmadigini ifade eder. Bu dizinin ilk elemani, yani argv[0], programin adini verir. Yani programa verilen gerçek argümanlar, dizinin 2. gözünden itibaren baslar.
Bri diger örnek de, verilen bir sayidan geriye dogru sayan bir program;
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int disp, count;
if(argc<2) {
printf("You must enter the length of the count\n");
printf("on the command line. Try again.\n");
exit(1);
}
if(argc==3 && !strcmp(argv[2], "display")) disp = 1;
else disp = 0;
for(count=atoi(argv[1]); count; --count)
if(disp) printf("%d\n", count);
putchar('\a'); /* this will ring the bell */
printf("Done");
}
Bu programa sinir sayinin yaninda, geri sayimi ekranda gösterip göstermeyecegini belirten bir de komut verilir. Eger bu komut ‘display’ ise, geri sayim ekranda gösterilir.
argc ve argv parametreleri, genelde bir programin ilk çalistirilma aninda, bazi opsiyonlar veya kullanilacak dosyalarin adlarini vermek için kullanilir. argc ve argv isimlerini kullanma zorunlulugu yoktur ama bu kullanim geneldir. Bunlar yerine programci kendi istedigi herhangi bir ismi kullanabilir.
6.5 return ifadesi
return ifadesinin 2 ayri görevi vardir: Biri, daha önce akis kontrolünde de bahsedilen bir fonksiyondan çikma, digeri de bulundugu fonksiyondan bir deger döndürme. Aslinda, her iki görevi de aynidir çünkü return ifadesi bir deger döndürmeden fonksiyondan çikma islemini gerçeklestiremez.
6.5.1 Fonksiyondan dönüs
Kontrolün, fonksiyondan çagirildigi yere dönmesi 2 sekidle olur: birincisi fonksiyonun çalismasinin sona ermesi, ikincisi ise return ifadesi ile. Asagidaki örnekte, kontrol fonksiyonun isi bittigi için ana programa döner;
void pr_reverse(char *s)
{
register int t;
for(t=strlen(s)-1; t>=0; t--) putchar(s[t]);
}
void main(void)
{
pr_reverse("I like C");
}
Burada fonksiyon, parametre olarak verilen stringi tersten yazdirdiktan sonra, main fonksiyonuna döner. Genele fonksiyonalr bu sekilde kodlanmazlar. Hatta bir fonksiyon farkli durumlara göre farkli degerler döndürebilecek sekilde kodlanir. Örnegin;
int find_substr(char *s1, char *s2)
{
register int t;
char *p, *p2;
for(t=0; s1[t]; t++) {
p = &s1[t];
p2 = s2;
while(*p2 && *p2==*p) {
p++;
p2++;
}
if(!*p2) return t; /* 1st return */
}
return -1; /* 2nd return */
}
void main(void)
{
if(find_substr("C is fun", "is") != -1)
printf("Substring is found.");
}
Bu programdaki find_substr, verilen bir string içinde, isetnilen ikinci bir string geçiyorsa bunun baslangiç adresini, eger geçmiyor ise -1 döndürür. Görüldügü gibi 2 ayri return ifadesi kullanilmistir ve bu ifadelerden biri her defasindafarkli deger döndürebilecek sekilde kodlanmistir.
6.5.2 Deger döndürme
void olarak tanimlanmamis her fonksiyon return ifadesi ile bir deger döndürmek zorundadir. Eger fonksiyon void tanimlanmadigi halde return ile bir deger döndürmüyorsa, garbage value döndürüyor denir.
Fonksiyonlar deger döndürebildikleri için, dönüs degerinin tipine göre, program içindeki ifadelerde kullanilabilirler. Bu yüzden asagidaki yazimlar dogrudur;
x = power(y);
if(max(x,y) > 100) printf("greater");
for(ch=getchar(); isdigit(ch); ) ... ;
Fonksiyonlar çagirildiklari noktalarda bir deger ifade ettikleri için, atama islemlerinde sol tarafta bulnamazlar. Örnegin;
swap(x,y) = 100; /* incorrect statement */
yanlis bir yazimdir.
Program yazarken genel anlamda 3 çesit fonksiyon kullanilir:
Birinci tip fonksiyonlar hesap islemleri yaparlar. Fonksiyon parametre olarak verilen degerler üzerinde bir islem yapar ve sonucu ana programa döndürür. sqrt() veya sin() gibi aritmetik fonksiyonlar bunlara örnektir.
Ikinci tip fonksiyonlar kendilerine verilen bilgiyi degerlendirir ve bu bilgi sonucunda yapilan islemin basariyla mi basarisizlika mi sonuçlandigini döndürür. Dosya üzerinde islem yapan fclose() fonksiyonu bu tip fonksiyonlara bir örnektir. Parametre olarak verilen dosya düzgün kapatilabilirse 0, aksi halde EOF döndürür.
Son fonksiyon tipi, herhangi bir dönüs degeri olmayan ve tamamen prosedürel yapida çalisan fonksiyonlari içerir. Bu tip fonksiyonlar çagirildiktan sonra, tanimli olan islem kümesini gerçeklestirir ve ana programa dönerler.
Deger döndüren fonksiyonlarda, Pascal’da oldugu gibi, dönüs degerini herhangi bri degiskene atama zorunlulugu yoktur. Fonksiyon, degisken kullanmadan da, bir islemin sonucunu veya direkt oalrak bir degeri kullanarak, programa deger döndürebilir. Örnegin;
int mul(int a, int b)
{
return a*b;
}
int main(void)
{
int x, y, z;
x = 10; y = 20;
z = mul(x, y); /* 1 */
printf("%d", mul(x,y)); /* 2 */
mul(x, y); /* 3 */
return 0;
}
Bu programda mul() fonksiyonu, verilen 2 parametrenin çarpim sonucunu, yedek bir degisken kullanmadan döndürmektedir.
6.5.3 Pointer döndürme
Pointer döndüren fonksiyonlar, diger veri tipleridne deger döndüren fonksiyonlarla ayni görevi yaparlar. Bu tip fonksiyonlari tanimalrken dikkat edilmesi gereken sey döencek pointer’in ne tip bir degiskeni gösterdigi bilgisidir. Çünkü dönüs degeri aritmetik islemde kullanildiginda tipi sorun çikartabilir. Bazi durumlarda, hangi tip pointer dönecegi bilinmediginden, genel pointer tipi olan void * kullanilabilir.
#include
char *match(char c, char *s)
{
while(c!=*s && *s) s++;
return(s);
}
void main(void)
{
char s[80], *p, ch;
gets(s);
ch = getchar();
p = match(ch, s);
if(*p) /* there is a match */
printf("%s ", p);
else
printf("No match found.");
}
6.5.4 void tipinde fonksiyonlar
void veri tipinin kullanim alanlarindan biri, herhangi bir deger döndürmeyen fonksiyonlarin dönüs tipi olarak kullanilmasidir. Bu tip fonksiyonlar prosedürel fonksiyonlardir. Örnegin;
#include
void print_vertical(char *str)
{
while(*str)
printf("%c\n", *str++);
}
void main(int argc, char *argv[])
{
if(argc > 1) print_vertical(argv[1]);
}
programindaki print_vertical() fonksiyonu, verilen bir stringin her karakterini bir satira yazar ve ana programa döner. Herhangi bir dönüs degeri yoktur.
6.6 main() fonksiyonu
C, fonksiyon temelli bir programlama dili oldugundan, bir programin ana fonksiyonu olarak main() tanimlanir. main() in dönüs tipi, gelistirme platformuna göre degisir. Çogu C compiler’i main’in default dönüs ipini void olarak kabul ederken, UNIX’te main dönüs tipi int’tir.
6.7 Fonksiyon prototipleri
C’de fonksiyon kodu yazilamdan önce fonksiyona ait prototip yazilmali ve fonksiyon tanimlanmalidir. Bu teknik olarak gerekli olmasa da kullanimi genelde desteklenmektedir. Prototip kullanimi fonksiyona tip kontrolünde kolaylik saglamaktadir. Prototip kullanimi ayrica derleyiciye argüman sayisini ve tipini farkli noktalarda kontrol etme imkani da saglar. Fonksiyon prototipinin genel yazimi;
dtipi fonk_adi (argüman listesi);
Argüman listesinde argümanlarin isimlerini kullanma zorunlulugu yoktur. Fakat veri tiplerini verem zorunlulugu vardir. Asagidaki kod örnegi, prototip kullanmanin gerekliligini gösterir. sqr_it() fonksiyonu int * yerine int ile çagrilmaya çalisildigindan, derleyici programin çalismasindan önce derleme aninda hata verecektir;
void sqr_it(int *i); /* prototype */
int main(void)
{
int x;
x = 10;
sqr_it(x); /* type mismatch */
return 0;
}
void sqr_it(int *i)
{
*i = *i * *i;
}
Fonksiyon blogunun yapisi;
dönüs_tipi fonksiyon_adi(parametre listesi)
{
islem blogu
}
dönüs_tipi, fonksiyonun sonucu, fonksiyonun çagirildigi noktaya gidecek olan degerin tipini belirtir. Fonksiyonlar dizi hariç her tür veri tipi döndürebilirler. Parametre listesi ise, fonksiyon çagirilirken kulanilmasi gereken degiskenler ve onlarin veri tipleridir. Fonksiyon parametre kullanmadan da çagirilabilir -bos bir parametre listesi için void veri tipinden faydalanilir.
Degisken tanimlamada ayni veri tipine sahip degiskenler, birbirinden virgül ile ayrilarak tanimlanabiliyordu. Fakat fonksiyonlara ait parametre tanimlamasinda bu yöntem kullanilmaz. Parametre tanimlamalarinda her parametre, kendi ver tipi iel tanimlanir. Yani;
f(int i, int k, float f)
dogru iken
f(int i, k, float f)
yanlistir. Ikinci örnekte k degiskeni kendi veri tipine sahip olmalidir.
6.2 Fonksiyonun tanim alani
Her fonksiyon, kendi basina bir kod blogudur. Bu yüzden fonksiyonalr kendi tanim alanlarini olustururlar. Yani fonksiyonun kodu kendine özeldir ve program içinde yer alan herhangi bir ifade tarafindan bu kod parçasina erisilemez. Örnegin bir fonksiyon içinde goto’yu kullanarak baska bir fonksiyonun kodunun herhangi biryerine atlama yapilamaz. Fonksiyonu olusturan kod parçasi programdan saklanir ve bu kisim global degisken kullanmadikça ne programin bir kismi tarafindan etkilenir ne de programin baska bir kismini etkileyebilir.
Bir fonksiyonun içinde tanimlanmis degiskenlere local (yerel) degiskenler adi verilir. Local degiskenler, tanimlandigi fonksiyon çagirildiginda devreye girer ve fonksiyonun çalismasi sona erince kullanimdan kaldirilir. Bu yüzden local bir degisken fonksiyonlar arasinda deger tasimak için kullanilamaz. Deger tasimak için parametreler ve dönüs degerleri kullanilir.
6.3 Fonksiyon argümanlari
Eger fonksiyon argüman alacaksa bunlar parametre listesinde tanimlanmalidir. Örnegin;
int is_in(char *s, char c)
{
while(*s)
if(*s==c) return 1;
else s++;
return 0;
}
is_in fonksiyonunun s ve c olmak üzere 2 parametresi vardir. Bu fonksiyon verilen c karakterinin, s stringinde olup olmadigini kontrol eder.
Parametreler fonksiyonlar arasinda deger tasiam görevini yerine getiriyor olsalar da, fonksiyon içinde local degisken gibi davranirlar. Parametreler’e deger atanabilir veya bir ifade içinde kullanilabilirler.
C’de fonksiyona parametre gönderme islemi 2 ayri sekilde yapilir: Deger ile ve referans ile çagirma.
6.3.1 Deger ile çagirma
Deger ile çagirmada, fonksiyondan kullanilan degilskene argümanin degeri atanir. Bu durumda, fonksiyon içinde argüman üzerinde yapilan islemlerin argümanin çagirilan yerdeki degerini üeridne bir etkisi yoktur. Örnegin;
#include
int sqr(int x)
{
x = x*x;
return(x);
}
void main(void)
{
int t=10;
printf("%d %d", sqr(t), t);
}
kod parçasi gözönüne alindiginda, sqr fonksiyonuna parametre olarak verilen t degiskeninin degeri, fonksiyon içinde x’e atanmistir. x=x*x islemi yapildiginda degisen fonksiyon içinde local degisken olarak kullanilan x’in degeridir. Yani ana programdaki printf satirinin sonucu “100 10” dur.
6.3.2 Referans ile çagirma
Referans ile çagirma, deger yerine, gönderilecek parametrenin adresini gönderme yöntemidir. Fonksiyona gönderilen argüman bir deger degil bir adrestir - yani fonksiyon içinde bu adres kullanilarak,gönderilen argümanlarin degerleri degistirilebilir.
Pointer’larin fonksiyona argüman olarak gönderilmesi, diger tipler ile aynidir. Örnek program, adresleri verilen 2 sayinin degerlerini degistirir;
#include
void swap(int *x, int *y)
{
int temp;
temp = *x; /* save the value at address x */
*x = *y; /* put y into x */
*y = temp; /* put x into y */
}
void main(void)
{
int i, j;
i = 10;
j = 20;
printf("i and j before swapping: %d %d\n", i, j);
swap(&i, &j); /* pass the addresses of i and j */
printf("i and j after swapping: %d %d\n", i, j);
}
Bu örnekte swap() fonksiyonu, degiskenlerin degerlerini degistirebilir çünkü degiskenler fonksiyona deger ile degil referans ile, yani pointer ile gönderilmistir. Adres göndermek için & operatörünün kullanildigina dikakt edilmelidir.
6.3.3 Fonksiyona dizi gönderme
Fonksiyona parametre oalrak dizi gönderilmek istendiginde yapilan sey fonksiyona dizinin adresini göndermektir. Bunun sebebi, dizi adlarinin, dizinin hafizadaki baslangiça adresini vermesidir. Fonksiyon çagirilirken bu bir deger ile çagirilma gibi görünse de, aslinda referans ile çagirmadir ve fonksiyon içinde, gönderilen parametre üzerinde degisiklik yapilabilir. Örnegin;
#include
#include
void print_upper(char *string)
{
register int t;
for(t=0; string[t]; ++t) {
string[t] = toupper(string[t]);
putchar(string[t]);
}
}
void main(void)
{
char s[80];
printf("Enter a string: ");
gets(s);
print_upper(s);
printf("\ns is now uppercase: %s", s);
return 0;
}
print_upper() fonksiyonu, gönderilen stringin karakterleriin teker teker denk gelen büyük harfe çevirir ve ekrana yazar. Burada parametre olarak gönderilen string’in üzerinde degisiklik yapilmaktadir. Eger stringin içeriginin degismesi istenmiyorsa, ekrana yazdirma islemi
void print_upper(char *string)
{
register int t;
for(t=0; string[t]; ++t)
putchar(toupper(string[t]));
}
fonksiyonu ile yapilabilir.
6.4 argc ve argv - main() fonksiyonunun parametreleri
Genelde yazilan programlara deger göndermek gerekebilir. Bu islem komut satirindan, programin adi ile deger göndererek yapilir. Program adi ile birlikte gönderilen degerler, main() ana fonksiyonuna gönderilen parametreler olarak algilanir. Komut satiri argümanlarina , UNIX’te C kodu derelyicisinin kullanimi örnek verilebilir;
cc c_program_adi
C’de, programa argüman göndermek için iki özel degisken tanimlanmistir: argc ve argv. Bu iki degisken komut satirindan argüman almak için kullanilir. argc degiskeni, programa gönderilen argüman sayisini tutar. Bu deger her zaman 1’den büyüktür çünkü program adinin kendisi de bir argüman olarak kabul edilir. argv ise, karakter pointer’lari tutan bri diziyi gösteren pointer’dir. Bu dizideki her pointer, komut satirindan girilen argümanlardan birini göstermektedir.Komut satirindan girilen her agüman string olarak degerlendirilir. Eger bir sayi kullanilacaksa, bu önce uygun string formatina çevrilmelidir.
Örnek program ‘Merhaba’ dan sonra verilen ismi ekrana yazdirir;
#include
#include
void main(int argc, char *argv[])
{
if(argc!=2) {
printf("You forgot to type your name.\n");
exit(1);
}
printf("Hello %s", argv[1]);
}
Koda dikkat edeilecek olunursa, ana fonksiyonun diger örneklerdeki gibi void main(void) olarak degil, void main(int argc, char *argv[]) olarak tanimlandigi görülür. Bu standart fonksiyon tanimlama sekline uygundur ve burada main fonksiyonu int tipinde argc ve char* tipinde bir argv dizisini argüman olarak alir. Programa girildiginde yapilan kontrol, argüman sayisinin dogru olup olmadiginin kontrolüdür. Bu programa test adi verilip derlenirse, programi çagirma sekli,
test isim
seklinde olacaktir. Komut satirinda her argüman bosluk (space) karakteri ile ayrilir. Örnegin;
test ad1 ad2
2 argüman aliyorken, bu satir;
test ad1,ad2
olarak yazilirsa bir argüman alir. argv argümaninin, char *argv[] olarak tanimlanmasi, argüman olarak verilen dizinin eleman sayisinin belli olmadigini ifade eder. Bu dizinin ilk elemani, yani argv[0], programin adini verir. Yani programa verilen gerçek argümanlar, dizinin 2. gözünden itibaren baslar.
Bri diger örnek de, verilen bir sayidan geriye dogru sayan bir program;
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int disp, count;
if(argc<2) {
printf("You must enter the length of the count\n");
printf("on the command line. Try again.\n");
exit(1);
}
if(argc==3 && !strcmp(argv[2], "display")) disp = 1;
else disp = 0;
for(count=atoi(argv[1]); count; --count)
if(disp) printf("%d\n", count);
putchar('\a'); /* this will ring the bell */
printf("Done");
}
Bu programa sinir sayinin yaninda, geri sayimi ekranda gösterip göstermeyecegini belirten bir de komut verilir. Eger bu komut ‘display’ ise, geri sayim ekranda gösterilir.
argc ve argv parametreleri, genelde bir programin ilk çalistirilma aninda, bazi opsiyonlar veya kullanilacak dosyalarin adlarini vermek için kullanilir. argc ve argv isimlerini kullanma zorunlulugu yoktur ama bu kullanim geneldir. Bunlar yerine programci kendi istedigi herhangi bir ismi kullanabilir.
6.5 return ifadesi
return ifadesinin 2 ayri görevi vardir: Biri, daha önce akis kontrolünde de bahsedilen bir fonksiyondan çikma, digeri de bulundugu fonksiyondan bir deger döndürme. Aslinda, her iki görevi de aynidir çünkü return ifadesi bir deger döndürmeden fonksiyondan çikma islemini gerçeklestiremez.
6.5.1 Fonksiyondan dönüs
Kontrolün, fonksiyondan çagirildigi yere dönmesi 2 sekidle olur: birincisi fonksiyonun çalismasinin sona ermesi, ikincisi ise return ifadesi ile. Asagidaki örnekte, kontrol fonksiyonun isi bittigi için ana programa döner;
void pr_reverse(char *s)
{
register int t;
for(t=strlen(s)-1; t>=0; t--) putchar(s[t]);
}
void main(void)
{
pr_reverse("I like C");
}
Burada fonksiyon, parametre olarak verilen stringi tersten yazdirdiktan sonra, main fonksiyonuna döner. Genele fonksiyonalr bu sekilde kodlanmazlar. Hatta bir fonksiyon farkli durumlara göre farkli degerler döndürebilecek sekilde kodlanir. Örnegin;
int find_substr(char *s1, char *s2)
{
register int t;
char *p, *p2;
for(t=0; s1[t]; t++) {
p = &s1[t];
p2 = s2;
while(*p2 && *p2==*p) {
p++;
p2++;
}
if(!*p2) return t; /* 1st return */
}
return -1; /* 2nd return */
}
void main(void)
{
if(find_substr("C is fun", "is") != -1)
printf("Substring is found.");
}
Bu programdaki find_substr, verilen bir string içinde, isetnilen ikinci bir string geçiyorsa bunun baslangiç adresini, eger geçmiyor ise -1 döndürür. Görüldügü gibi 2 ayri return ifadesi kullanilmistir ve bu ifadelerden biri her defasindafarkli deger döndürebilecek sekilde kodlanmistir.
6.5.2 Deger döndürme
void olarak tanimlanmamis her fonksiyon return ifadesi ile bir deger döndürmek zorundadir. Eger fonksiyon void tanimlanmadigi halde return ile bir deger döndürmüyorsa, garbage value döndürüyor denir.
Fonksiyonlar deger döndürebildikleri için, dönüs degerinin tipine göre, program içindeki ifadelerde kullanilabilirler. Bu yüzden asagidaki yazimlar dogrudur;
x = power(y);
if(max(x,y) > 100) printf("greater");
for(ch=getchar(); isdigit(ch); ) ... ;
Fonksiyonlar çagirildiklari noktalarda bir deger ifade ettikleri için, atama islemlerinde sol tarafta bulnamazlar. Örnegin;
swap(x,y) = 100; /* incorrect statement */
yanlis bir yazimdir.
Program yazarken genel anlamda 3 çesit fonksiyon kullanilir:
Birinci tip fonksiyonlar hesap islemleri yaparlar. Fonksiyon parametre olarak verilen degerler üzerinde bir islem yapar ve sonucu ana programa döndürür. sqrt() veya sin() gibi aritmetik fonksiyonlar bunlara örnektir.
Ikinci tip fonksiyonlar kendilerine verilen bilgiyi degerlendirir ve bu bilgi sonucunda yapilan islemin basariyla mi basarisizlika mi sonuçlandigini döndürür. Dosya üzerinde islem yapan fclose() fonksiyonu bu tip fonksiyonlara bir örnektir. Parametre olarak verilen dosya düzgün kapatilabilirse 0, aksi halde EOF döndürür.
Son fonksiyon tipi, herhangi bir dönüs degeri olmayan ve tamamen prosedürel yapida çalisan fonksiyonlari içerir. Bu tip fonksiyonlar çagirildiktan sonra, tanimli olan islem kümesini gerçeklestirir ve ana programa dönerler.
Deger döndüren fonksiyonlarda, Pascal’da oldugu gibi, dönüs degerini herhangi bri degiskene atama zorunlulugu yoktur. Fonksiyon, degisken kullanmadan da, bir islemin sonucunu veya direkt oalrak bir degeri kullanarak, programa deger döndürebilir. Örnegin;
int mul(int a, int b)
{
return a*b;
}
int main(void)
{
int x, y, z;
x = 10; y = 20;
z = mul(x, y); /* 1 */
printf("%d", mul(x,y)); /* 2 */
mul(x, y); /* 3 */
return 0;
}
Bu programda mul() fonksiyonu, verilen 2 parametrenin çarpim sonucunu, yedek bir degisken kullanmadan döndürmektedir.
6.5.3 Pointer döndürme
Pointer döndüren fonksiyonlar, diger veri tipleridne deger döndüren fonksiyonlarla ayni görevi yaparlar. Bu tip fonksiyonlari tanimalrken dikkat edilmesi gereken sey döencek pointer’in ne tip bir degiskeni gösterdigi bilgisidir. Çünkü dönüs degeri aritmetik islemde kullanildiginda tipi sorun çikartabilir. Bazi durumlarda, hangi tip pointer dönecegi bilinmediginden, genel pointer tipi olan void * kullanilabilir.
#include
char *match(char c, char *s)
{
while(c!=*s && *s) s++;
return(s);
}
void main(void)
{
char s[80], *p, ch;
gets(s);
ch = getchar();
p = match(ch, s);
if(*p) /* there is a match */
printf("%s ", p);
else
printf("No match found.");
}
6.5.4 void tipinde fonksiyonlar
void veri tipinin kullanim alanlarindan biri, herhangi bir deger döndürmeyen fonksiyonlarin dönüs tipi olarak kullanilmasidir. Bu tip fonksiyonlar prosedürel fonksiyonlardir. Örnegin;
#include
void print_vertical(char *str)
{
while(*str)
printf("%c\n", *str++);
}
void main(int argc, char *argv[])
{
if(argc > 1) print_vertical(argv[1]);
}
programindaki print_vertical() fonksiyonu, verilen bir stringin her karakterini bir satira yazar ve ana programa döner. Herhangi bir dönüs degeri yoktur.
6.6 main() fonksiyonu
C, fonksiyon temelli bir programlama dili oldugundan, bir programin ana fonksiyonu olarak main() tanimlanir. main() in dönüs tipi, gelistirme platformuna göre degisir. Çogu C compiler’i main’in default dönüs ipini void olarak kabul ederken, UNIX’te main dönüs tipi int’tir.
6.7 Fonksiyon prototipleri
C’de fonksiyon kodu yazilamdan önce fonksiyona ait prototip yazilmali ve fonksiyon tanimlanmalidir. Bu teknik olarak gerekli olmasa da kullanimi genelde desteklenmektedir. Prototip kullanimi fonksiyona tip kontrolünde kolaylik saglamaktadir. Prototip kullanimi ayrica derleyiciye argüman sayisini ve tipini farkli noktalarda kontrol etme imkani da saglar. Fonksiyon prototipinin genel yazimi;
dtipi fonk_adi (argüman listesi);
Argüman listesinde argümanlarin isimlerini kullanma zorunlulugu yoktur. Fakat veri tiplerini verem zorunlulugu vardir. Asagidaki kod örnegi, prototip kullanmanin gerekliligini gösterir. sqr_it() fonksiyonu int * yerine int ile çagrilmaya çalisildigindan, derleyici programin çalismasindan önce derleme aninda hata verecektir;
void sqr_it(int *i); /* prototype */
int main(void)
{
int x;
x = 10;
sqr_it(x); /* type mismatch */
return 0;
}
void sqr_it(int *i)
{
*i = *i * *i;
}





