Funksiyalar
C dilinin proqramçılar arasında ən məşhur dil olmasında rol oynayan 2 ən güclü imkanından biri funksiyalardır. Digəri isə, yaddaş dəyişənləridir. Funksiyalar proqramın hər hansı bir hissəsinə ad verməklə bu hissəyə proqramın istənilən yerindən, digər funksiyalardan və eləcə də, digər proqramlardan müraciət etməyə imkan verir. Bu hissəyə funksiyanın mətni, bu hissəyə verilən ada isə, funksiyanın adı deyilir.
Nümunə proqrama baxmazdan əvvəl, funksiyalarla bağlı bir neçə məqama nəzər salaq.
Ola bilsin ki, funksiyanın mətni yerinə yetirildikdən sonra, hansısa bir nəticə alınsın və ya bu mətn hissəsi hansısa əməliyyatlar yerinə yetirsin və heç bir nəticə qaytarmasın ((void)
). Digər bir məqam odur ki, funksiya mətnində istifadə olunan bəzi dəyişənlərin qiyməti funksiya çağırılarkən ona parametr kimi ötürülsün və ya funksiya çağırılarkən ona heç bir parametr ötürülməsin ((void)
).
İndi isə, gəlin, konkret proqram nümunələrində funksiyalar, onların tərtibi, çağırılma qaydası ilə tanış olaq və bu məqamların hər birini ayrı-ayrı təhlil edək.
//proq_5_1.c
#include <stdio.h>
int main(int argc, char *argv[]){
printf("Sətirlərin ekrana verilməsi\n");
printf("Sətir 1\n");
printf("Bu gün yağış yağır\n");
printf("Bu gün külək əsir\n");
return 0;
}
Nümunə
Proqramı yerinə yetirək.
user@gnu_linux:~/prg#
user@gnu_linux:~/prg# gcc prog_5_1.c -o prog_5_1
user@gnu_linux:~/prg#
user@gnu_linux:~/prg# ./prog_5_1
Sətirlərin ekrana verilməsi
Sətir 1
Bu gün yağış yağır
Bu gün külək əsir
user@gnu_linux:~/prg#
Proqram bizə tam aydındır. İndi isə, gəlin,
printf("Sətir 1\n");
printf("Bu gün yağış yağır\n");
printf("Bu gün külək əsir\n");
proqram hissəsindən ibarət cap_et
funksiyası yaradaq və proqramımızda bu funksiyadan istifadə edək.
//prog_5_2.c
#include <stdio.h>
void cap_et(void);
int main(int argc, char *argv[]){
cap_et();
return 0;
}
/*----------------------- cap_et funksiyası --------------------------------*/
void cap_et(void)
{
printf("Sətirlərin ekrana verilməsi\n");
printf("Sətir 1\n");
printf("Bu gün yağış yağır\n");
printf("Bu gün külək əsir\n");
}
Nümunə
Proqramı yerinə yetirək.
user@gnu_linux:~/prg#
user@gnu_linux:~/prg#gcc prog_5_2.c -o prog_5_2
user@gnu_linux:~/prg#
user@gnu_linux:~/prg#./prog_5_2
Sətirlərin ekrana verilməsi
Sətir 1
Bu gün yağış yağır
Bu gün külək əsir
user@gnu_linux:~/prg#
İzahı:
Proqramda ilk #include <stdio.h>
sətrindən sonra gələn void cap_et(void);
sətridir. Bu sətir funksiyanın elanı sətridir. Hər bir funksiyanı proqramda istifadə etməzdən əvvəl, onu elan etmək lazımdır. Bu sətir kompilyatora funksiyanın adı, qaytaracağı nəticənin tipi və ona ötürüləcək parametrlər haqqında məlumat verir. Bu sətirdə birinci yerdə gələn söz funksiyanın qaytaracağı nəticənin tipini bildirir. Əgər funksiya heç bir nəticə qaytarmırsa, onda bu yerdə void
yazılır, baxdığımız haldakı kimi. Funksiyanın tipindən sonra funksiyanın adı qeyd olunur – cap_et
. Addan sonra ()
mötərizələri arasında funksiyanın parametrləri haqda məlumat qeyd olunur. Əgər funksiya heç bir parametr qəbul etmirsə, burada void
yazırıq.
prog_5_3.c-ni yerinə yetirin və onu başa düşməyə çalışın.
//prog_5_3.c
#include <stdio.h>
void cap_et(void);
int main(int argc, char *argv[]){
int i;
for(i=0; i<5; ++i)
cap_et();
return 0;
}
/*----------------------- cap_et funksiyası --------------------------------*/
void cap_et(void)
{
printf("Sətirlərin ekrana verilməsi\n");
printf("Sətir 1\n");
printf("Bu gün yağış yağır\n");
printf("Bu gün külək əsir\n");
}
Nümunə
Digər proqrama baxaq.
//prog_5_4.c
#include <stdio.h>
int sahe(int,int);
int main(int argc, char *argv[])
{
int x,y,z;
printf("Düzbucaqlının enini daxil edin\n");
scanf("%d",&x);
printf("Düzbucaqlının uzunluğunu daxil edin\n");
scanf("%d",&y);
z=sahe(x,y);
printf("Düzbucaqlının sahəsi = %d\n",z);
return 0;
}
int sahe(int t1, int t2)
{
int sh;
sh=t1*t2;
return sh;
}
Nümunə
Proqramı yerinə yetirək.
user@gnu_linux:~/prg#
user@gnu_linux:~/prg# gcc prog_5_4.c -o prog_5_4
user@gnu_linux:~/prg#
user@gnu_linux:~/prg# ./prog_5_4
Düzbucaqlının enini daxil edin
6
Düzbucaqlının uzunluğunu daxil edin
8
Düzbucaqlının sahəsi = 48
user@gnu_linux:~/prg#
user@gnu_linux:~/prg#
İzahı:
Burada biz yeni sahe funksiyası yaradırıq, hansı ki, int
tipli 2 parametr qəbul edir və nəticə olaraq, int
tipli ədəd (düzbucaqlının sahəsini) qaytarır. (int sahe(int,int);
)
Mötərizələr arasında funksiyaya ötürülən parametrlərin tipləri, vergüllə ayrılaraq sadalanır. Qeyd edək ki, bu zaman hər parametrin tipinin qarşısında ad da verə bilərik, kompilyator bunu nəzərə almır, o, ancaq tipə əhəmiyyət verir. Yəni əgər yuxarıdakı proqramda sahə funksiyasını elan edərkən biz int sahe(int,int);
sətri əvəzinə int sahe(int teref2,int teref2);
də yaza bilərdik. Sadəcə özümüzə və bu proqrama daha sonra baxan proqramçılara məlumat məqsədilə. Əgər proqramda bir funksiyada istifadə olunursa, bunun elə də əhəmiyyəti yoxdur, lakin proqramda minlərlə funksiyadan istifadə olunduqda (məsələn, nüvənin yaddaşın idarə olunması hissəsi və ya şəbəkə hissəsi), bunun əhəmiyyəti hiss olunur.
Biz proqramda sahe funksiyasını z=sahe(x,y);
sətrində çağırırıq. x və y dəyişənlərinin qiymətləri scanf
funksiyası vasitəsilə istifadəçidən alınır və sahə funksiyasına parametr kimi ötürülür. sahe funksiyasında bu 2 dəyişənin hasili hesablanır və qaytarılan nəticə z dəyişəninə mənimsədilir.
sahe
funksiyasının mətnində biz int
tipli sh
dəyişəni elan edirik və parametrlərin hasilini hesablayaraq, bu dəyişənə mənimsədirik. Daha sonra, return əmri vasitəsilə, funksiyanın proqramda çağırılma nöqtəsinə (z=sahe(x,y);
) qaytarılacaq nəticə göstərilir. return
əmri funksiyanın icrasını başa çatdırır və proqramın icrası funksiyanın çağırılma yerindən davam edir.
Biz burada x,y
dəyişənləri daxil etdik və onlara scanf vasitəsilə istifadəçinin daxil etdiyi qiymətləri mənimsətdik, daha sonra, sahə funksiyasını çağırdıq. x,y
-in qiymətlərini bu funksiyaya parametr kimi ötürdük. z=sahe(x,y);
- bu yerdə proqramın icrası sahə funksiyasına ötürüldü və x,y
-in qiymətlərindən istifadə olunaraq, hesablama aparıldı, nəticə z dəyişəninə mənimsədildi və proqramın icrası davam etdi.
Sual? Tutaq ki, istifadəçi 5 və 7 ədədlərini daxil edib.
x=5; y=7;
. sahə
funksiyası yerinə yetirildikdən sonra x və y-in qiyməti dəyişmədi ki? Yəni funksiyanın mətnində ona ötürülən arqumentlərə edilən dəyişiklik funksiya icra olunduqdan sonra öz qüvvəsini saxlayırmı? Bunu yoxlamaq üçün printf funksiyasından istifadə edək.
//prog_5_5.c
#include <stdio.h>
int sahe(int,int);
int main(int argc, char *argv[])
{
int x,y,z;
printf("Düzbucaqlının enini daxil edin\n");
scanf("%d",&x);
printf("Düzbucaqlının uzunluğunu daxil edin\n");
scanf("%d",&y);
z=sahe(x,y);
printf("Düzbucaqlının sahəsi = %d\n",z);
printf("x=%d, y= %d\n",x,y);
return 0;
}
int sahe(int t1, int t2)
{
int sh;
sh=t1*t2;
return sh;
}
Nümunə
Proqramı yerinə yetirək.
user@gnu_linux:~/prg#
user@gnu_linux:~/prg# gcc prog_5_5.c -o prog_5_5
user@gnu_linux:~/prg#
user@gnu_linux:~/prg# ./prog_5_5
Düzbucaqlının enini daxil edin
6
Düzbucaqlının uzunluğunu daxil edin
8
Düzbucaqlının sahəsi = 48
x=6, y= 8
user@gnu_linux:~/prg#
user@gnu_linux:~/prg#
Qeyd edək ki, bu halda biz sahə funksiyasında ona ötürülən parametrlərin qiymətlərini dəyişmədik. İndi gəlin, digər proqramda sahə funksiyasında bu qiymətləri dəyişək və nəticəni yenidən yoxlayaq.
//proq_5_6.c
#include <stdio.h>
int sahe(int,int);
int main(int argc, char *argv[])
{
int x,y,z;
printf("Düzbucaqlının enini daxil edin\n");
scanf("%d",&x);
printf("Düzbucaqlının uzunluğunu daxil edin\n");
scanf("%d",&y);
z=sahe(x,y);
printf("Düzbucaqlının sahəsi = %d\n",z);
printf("x=%d, y= %d\n",x,y);
return 0;
}
int sahe(int t1, int t2)
{
int sh;
sh=t1*t2;
/* funksiyaya ötürülən arqumentlərin (t1,t2) qiymətlərini burada dəyişirik */
t1=1; t2=2;
return sh;
}
Nümunə
Gördüyümüz kimi, sahə funksiyasında biz sahəni hesabladıqdan sonra ona ötürülən parametrlərin qiymətlərini dəyişdirdik.
Nəticəni yoxlayaq.
user@gnu_linux:~/prg#
user@gnu_linux:~/prg# gcc prog_5_6.c -o prog_5_6
user@gnu_linux:~/prg#
user@gnu_linux:~/prg# ./prog_5_6
Düzbucaqlının enini daxil edin
4
Düzbucaqlının uzunluğunu daxil edin
7
Düzbucaqlının sahəsi = 28
x=4, y= 7
user@gnu_linux:~/prg#
user@gnu_linux:~/prg#
Gördüyümüz kimi, funksiyanın daxilində ona ötürülən parametrlərin qiymətlərinin dəyişdirilməsi funksiya icra olduqdan sonra öz qüvvəsini itirdi, x və y-in qiymətləri olduğu kimi qaldı. Dəyişənlərin funksiyaya belə ötürülməsinə qiymətə görə ötürmə deyirlər.
Bunun səbəbi odur ki, funksiya çağırılarkən parametr kimi ona əslində x və y ötürülmür, bu dəyişənlərin surətləri yaradılır və funksiyaya ötürülür. Funksiyanın mətnində bu dəyişənlər üzərində aparılan bütün dəyişikliklər, əslində onların surətləri üzərində aparılır.
Dəyişənlərin funksiyaya bu cür ötürülməsinin müsbət və mənfi tərəfləri var. Müsbət hal odur ki, qiymətə görə ötürülmə zamanı bütün əməliyyatlar dəyişənlərin surətləri üzərində aparıldığından, dəyişənlərin qiymətləri hər cür dəyişiklikdən qorunmuş olur. Mənfi hal odur ki, bu zaman dəyişənlərin surətləri yaradılır və buna proqramçı üçün ən qiymətli resurslar – əməli yaddaş və zaman sərf olunur.
Parametrlərin funksiyaya ötürülməsinin digər variantı da, ünvana görə ötürülmədir. Bu zaman dəyişənlərin surətləri yaradılmır və funksiyaya dəyişənlərin ünvanları ötürülür. Nəticədə funksiyada dəyişənlər üzərində aparılan bütün əməliyyatlar məhz onların əsli üzərində aparılmış olur.
Parametrlərin ünvana görə ötürülməsi
prog_5_7.c-ni yerinə yetirək.
//prog_5_7.c
#include <stdio.h>
int sahe(int *,int *);
int main(int argc, char *argv[])
{
int x,y,z;
printf("Düzbucaqlının enini daxil edin\n");
scanf("%d",&x);
printf("Düzbucaqlının uzunluğunu daxil edin\n");
scanf("%d",&y);
z=sahe(&x,&y);
printf("Düzbucaqlının sahəsi = %d\n",z);
printf("x=%d, y= %d\n",x,y);
return 0;
}
int sahe(int *t1, int *t2)
{
int sh;
sh=(*t1)*(*t2);
*t1=1; *t2=2;
return sh;
}
Nümunə
Proqramı yerinə yetirək.
user@gnu_linux:~/prg# gcc prog_5_7.c -o prog_5_7
user@gnu_linux:~/prg#
user@gnu_linux:~/prg# ./prog_5_7
Düzbucaqlının enini daxil edin
3
Düzbucaqlının uzunluğunu daxil edin
8
Düzbucaqlının sahəsi = 24
x=1, y=2
user@gnu_linux:~/prg#
Gördüyümüz kimi, funksiyada ona ötürülən parametrlər üzərində edilən dəyişiklik öz qüvvəsini saxladı.
İzahı:
int sahe(int *,int *);
sətri ilə sahə funksiyası elan edilir. Bu sətirdə göstərilir ki, sahə
funksiyası nəticə olaraq int
tipli qiymət qaytarır. Bizim üçün maraqlısı ()
mötərizələri arasında olan hissədir. Qiymətə görə ötürmə zamanı biz yalnız tipi göstərirdik. Ünvana görə ötürmə zamanı isə, sadəcə tipdən sonra *
simvolu yazırıq. Sahə funksiyasına proqramda z=sahe(&x,&y);
sətrində müraciət edirik. Burada &
operatoru vasitəsilə sahə funksiyasına parametr kimi x və y dəyişənlərinin yaddaşdakı ünvanları ötürülür.