C Proqramlaşdırma Dili

Ünvan dəyişənləri

Ünvan dəyişənləri

Ünvan dəyişənləri proqramlaşdırmada çox geniş istifadə olunur. C dilində isə, ünvan dəyişənləri şahmatda 2 topun oynadığı rolu oynayır. Vəzir rolu isə, əlbəttə funksiyalara məxsusdur. Bu imkandan hansı kombinasiyada istifadə etmək isə, proqramçının təcrübəsinə bağlıdır. Ünvan dəyişənlərindən bir qayda olaraq, təcrübəli proqramçılar daha çox istifadə edir. Yaranan fikir belədir ki, təcrübə nə qədər artarsa, proqramçının ünvan dəyişənlərindən istifadəsi daha çox olur.
Biz qeyd etdik ki, yerinə yetirdiyi işdən asılı olmayaraq, proqram sadəcə və sadəcə hansısa məlumatları müəyyən mənbədən qəbul edir, yadda saxlayır, ötürür, dəyişdirir. İndiyə kimi baxdığımız proqramlarda istifadə etdiyimiz adi dəyişənlər vasitəsilə bu işin öhdəsindən asanlıqla gəlmək mümkündür (qəbul, saxlama...). Bəs onda ünvan dəyişənləri nəyə lazımdır?
Biz bildiyimiz adi dəyişənlər qeyd etdiyimiz işlərin öhdəsindən həqiqətən də, əla gəlirlər. Məsələn, əgər biz yaddaşda 4 bayt yer ayırıb, bu yerə 155 ədədini yerləşdirmək istəyiriksə, onda int x; x=155; operatorlarından istifadə edərik. Lakin bu dəyişənlərin böyük çatışmayan bir cəhəti var. Bu cəhət onların statik olmalarıdır. Yəni əgər yaddaşda hansısa məqsəd üçün yer ayırmaq tələb olunursa, bu, yalnız proqramın icraya başladığı zaman ola bilər. Proqramda elan etdiyimiz bütün dəyişənlər üçün proqram icraya başladığı zaman yaddaşda yer ayrılır və bu yaddaş sahəsi proqramın icrasına verilir. Proqram bu sahəyə istənilən məlumatları yaza, dəyişə və s. bilər.
Bəs birdən proqram yerinə yetirilərkən bizim əlavə yaddaşa ehtiyacımız oldu? Ya da, tutaq ki, biz proqramda 100 000 dənə int tipli dəyişəndən istifadə etmişik. Bu təqribən 1Mb-a yaxın yaddaş deməkdir (Qeyd edək ki, bu qədər yaddaş RAM-da ayrılır, Sərt diskdə yox. Ona görə, 1 Mb yaddaş çox qiymətlidir). Proqramın icrası davam edir, lakin bu dəyişənlərə daha müraciət etməyəcəyik. Bu dəyişənlər həmin sahəni boş-boşuna tutur. Biz bu sahədən o dəyişənləri silib, həmin yaddaş sahəsini yenidən proqramın istifadəsinə verə bilərikmi? İndi təsəvvür edin ki, int tipli dəyişənlər yox, özümüz tərtib etdiyimiz 100 baytlıq struct tipli 1000 000 dəyişəndən istifadə etmişik və bizə artıq lazım deyil. 100 000 000 bayt yaddaş proqram başa çatana kimi yaddaşda yer tutacaq, bu yerə həmin struct tipli dəyişənlərdən başqa dəyişənlər yerləşdirə bilmərik. Bu cür israfçılıqıa 2 proqram işləsə, kompüterin bütün yaddaşı tutular və 3-cü proqramı yükləmək üçün biz bu proqramlardan birini söndürməli olarıq.
Ünvan tipli dəyişənlər dinamik dəyişənlərdir. Yəni proqramın icrası boyu istənilən vaxt onları yaradıb, istifadə edə bilərik. İstədiyimiz vaxtda da, azad edə bilərik. Beləliklə də, onların tutduğu sahəni yenidən proqrama qaytara bilərik.
Lakin ünvan dəyişənlərinin özəllikləri sadəcə bununla bitmir. Adından göründüyü kimi, ünvan dəyişənləri özlərində qiymət olaraq, yaddaşın müəyyən sahəsinin ünvanını saxlayır, həmin sahəyə istinad edir. Bu isə proqramçıya yaddaşla güclü manipulyasiya imkanı verir. Bu cəhətə görə istifadəçi proqramlarının tərtibi üçün nəzərdə tutulmuş bir çox proqramlaşdırma dilləri, o cümlədən JAVA və PHP təhlükəsizlik məsələlərinə görə (ünvan dəyişənlərinin qiymətini dəyişməklə başqa istifadəçilərə məxsus məlumatlar yerləşdirilmiş yaddaş sahəsinə müraciət etmək olar) göstəricilərdən istifadə etməyə icazə vermir.
Bundan əlavə, ünvan dəyişənləri öz tiplərindən olan ünvan dəyişənlərinə mənimsədilə bilər. Bu imkandan əlaqələnmiş siyahıların yaradılmasında geniş istifadə edirlər. Əlaqələnmiş siyahılarla 8-ci paraqrafda məşğul olacağıq. Qeyd edək ki, kompüterdə ötürülən və qəbul olunan məlumatların böyük hissəsi (bir proqramdan digərinə, driverdən istifadəçi proqramına, TCP səviyyəsindən IP səviyyəsinə və s.) məhz əlaqələnmiş siyahılarla mümkün olur.

Ünvan dəyişənlərindən istifadə edən sadə proqrama baxaq.


//prg_4_1.c

#include <stdio.h>

int main(int argc, char *argv[]){

int x;
int *y;	/* tam tipli ünvan dəyişəni */
x=5;
y=&x;	/* & ünvan operatorudur */
printf("x-in qiyməti = %d, x-in ünvanı = %p\n",x,y);
return 0;
}

Nümunə

Yerinə yetirək:


user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# gcc prog_4_1.c -o prog_4_1
user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# ./prog_4_1
x-in qiyməti = 5, x-in ünvanı = 0xbfcdae50
user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# 

İzah:
Ünvan dəyişəni elan etmək üçün adi qaydada etdiyimiz kimi, dəyişən elan edirik, lakin dəyişənin əvvəlinə * simvolunu artırırıq.
int x; adi dəyişən elan edirik. int *y; int tipli y ünvan dəyişənini elan edirik.


int x; int *y;

y=&x; - burada biz y-ə x dəyişəninin yaddaşdakı ünvanını mənimsədirik. x dəyişəninin yaddaşdakı ünvanını təyin etmək üçün biz & operatorundan istifadə edirik.


y=&x;

 

Ünvan dəyişənləri elan etdik və onlara qiymət mənimsədə bildik. Növbəti məsələ ünvan dəyişənlərinin ünvanladığı yaddaş sahəsindən istifadə etmək məsələsidir.
Ünvan dəyişənlərinin ünvanladığı yaddaş sahəsinə müraciət etmək üçün, dəyişəni elan edərkən istifadə etdiyimiz * operatorundan istifadə edirik.

Nümunə proqrama baxaq.


//prg_4_2.c

#include <stdio.h>

int main(int argc, char *argv[]){

int x;
int *y;	/* tam tipli ünvan dəyişəni*/	
x=5;
printf("x-in qiymeti = %d\n",x);
y=&x;	/* & ünvan operatorudur */
*y=155;
printf("y-in qiyməti = %d\n",*y);	/* y x-in yaddaşına ünvanlandığından (y=&x), *y–i dəyişmək birbaşa x-i dəyişdirir. Bunu yoxlamaq üçün printf-dən istifadə edirik */
printf("x-in qiyməti = %d\n",*x);
return 0;	
}

Nümunə

Yerinə yetirək.


user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# gcc prog_4_2.c -o prog_4_2
user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# ./prog_4_2
x-in qiyməti = 5
y-in qiyməti = 155
x-in qiyməti = 155
user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# 

Beləliklə, biz ünvan dəyişənlərinin ünvanlandığı yaddaş sahəsindən istifadə edə bilirik. İndi isə, ünvan dəyişənləri ilə bağlı sonuncu və ən maraqlı məqam.

Dinamik yaradılma və yaddaşdan silmə.


//prg_4_3.c

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){

int x;
int *y;	/* tam tipli ünvan dəyişəni */
x=5;
y=(int *)malloc(sizeof(int));	/* dinamik yaradılma */
*y=176;
printf("y-in qiyməti = %d",*y);
free(y);	/* y-ə ayrılan yaddaş sahəsini y-dən azad edir və bu sahədə olan bütün məlumat silinir */

return 0;
}

Nümunə

Yerinə yetirək.


user@gnu_linux:~/prg#
user@gnu_linux:~/prg#gcc prog_4_3.c -o prog_4_3
user@gnu_linux:~/prg#
user@gnu_linux:~/prg#
user@gnu_linux:~/prg#./prog_4_3
y-in qiyməti = 176
user@gnu_linux:~/prg#
user@gnu_linux:~/prg#