Ünvan
Gələcəyin güclü proqramçıları ilə tələbələrin ayrıldığı yerə çatdıq.
Proqramda istifadə olunan dəyişənlər yaddaşda yer ayrılmasına görə iki cür olur, adi və dinamik. Bizim indiyə qədər istifadə etdiyimiz dəyişənlər hamısı adi dəyişənlərdir. Aşağıda onların müqaisəsi verilir.
Adi dəyişənlər :
Ancaq proqramın əvvəlində onlara yer ayrılır, proqramın icrası boyu onlara ayrılan yer olduğu kimi qalır və bu yer dəyişəndən geri alınıb, hansısa başqa məqsəd üçün istifadə oluna bilməz, proqramın icrası boyu yaddaşda eyni bir ünvana istinad edirlər, bu dəyişənlərin istinad etdiyi ünvanı dəyişdirmək olmaz.
Dinamik dəyişənlər :
Dinamik dəyişənləri proqramın icrasının istənilən anında yaratmaq olar, onlara ayrılmış yaddaş proqramın icrasının istənilən anında geri alıb, həmin yeri istənilən digər məqsəd üçün istifadə etmək olar, dinamik dəyişənlərin yaddaşda istinad etdikləri ünvanı istənilən digər ünvana dəyişdirmək olar, hətta digər proqramın və ya nüvənin yaddaş sahəsinə. Ancaq bunu etmək istədiyimiz ilk cəhddə nüvə proqramımızı tamamilə söndürər (başqa proqramların məlumatlarına icazəsiz müraciət etmək olmaz).
Ünvan dəyişənlərinin özəlliyi odur ki, onlar özlərində məlumat olaraq, bizim üçün əhəmiyyətli olan məlumatın ünvanını saxlayırlar. Əgər biz bu ünvanı dəyişsək, onda onlar ayrı məlumata istinad edəcəklər. Bu C/C++ dillərinə xarakterik olan, proqramçıya yaddaşla istədiyi kimi manipulyasiya etmə imkanı yaradan güclü vasitələrdən biridir.
Proqramda hər hansı tipdən ünvan dəyişəni elan etmək üçün aşağıdakı sintaksisdən istifadə olunur:
tip *dəyişən;
Tam tipli hər hansı ünvan dəyişəni elan edək:
int *x;
Göründüyü kimi, bunun adi dəyişən elan etmək qaydasından (int x;) fərqi, ancaq dəyişən adının əvvəlində * (ulduz) simvolunun olmasıdır.
Bu zaman yaddaşın vəziyyəti belədir (şəkil 5):
İndi mən x ünvan dəyişənini istənilən yaddaş ünvanına və ya istənilən dəyişənin yaddaş sahəsinə mənimsədə bilərəm, yaxud, yaddaşda dinamik şəkildə əlavə yer ayıra və həmin yerə mənimsədə bilərəm.
Misal üçün, gəlin adi int tipli y dəyişəni elan edək (int y;) və onun yaddaş sahəsinə 5 qiyməti yazaq (y = 5;).
Yaddaşın vəziyyəti:
İndi mən x-i y-in yaddaş sahəsinə mənimsədə bilərəm.
Bunun üçün & ünvan operatorundan istifadə edəcəm.
& operatoru istənilən dəyişənin və funksiyanın ünvanını almaq üçün istifadə olunur.
x-i y-in ünvanına mənimsətmək üçün sadəcə olaraq yazırıq:
x = &y ;
Yaddaşın vəziyyəti:
Əgər bizə ünvan dəyişəninin istinad etdiyi ünvana müraciət etmək lazımdırsa, onda sadəcə ünvan dəyişəninin adından istifadə edirik. Əgər biz həmin ünvanda yerləşən məlumata müraciət etmək istəyiriksə, bu zaman dəyişənin əvvəlinə elanda olduğu kimi * simvolu artırırıq.
Gəlin, bu dediklərimizi proqram nümunəsində test edək.
//prg_4_1.cpp
#include <iostream>
int main(int argc, char *argv[])
{
int *x; // tam tipli unvan dəyişəni
int y;
y=5;
x=&y; // & unvan operatorudur
// y-in qiymətini çap edek
std::cout<<"y-in qiyməti = "<<y;
// x-in qiymətini çap edək (aha y-in unvanı)
std::cout<<"\n x-in qiyməti (y-in unvanı) "<<x;
// x ünvanında yerləşən məlumatı çap edək
std::cout<<"\n x-in istinad etdiyi məlumat "<<*x;
// x-in istinad etdiyi məlumatı dəyişək
*x=67;
// y-in qiymətini çap edək
std::cout<<"y-in yeni qiyməti = "<<y;
return 0;
}
Nümunə
Proqramı icra edək:
C:\cpp\prog2\Debug>
C:\cpp\prog2\Debug>prog2.exe
y-in qiyməti = 5
x-in qiyməti (y-in unvani) 0x7fffb4cbe824
x-in istinad etdiyi məlumat 5
y-in yeni qiyməti = 67
C:\cpp\prog2\Debug>
C:\cpp\prog2\Debug>
Burada x-in qiyməti olaraq 0x7fffb4cbe824 çap olunmuşdur. Ünvan ədədlə ifadə olunur və adətən 16-lıq say sistemində göstərilir (hex). Mövzudan kənar olduğuna görə, biz fiziki yaddaşın strukturu və fiziki, virtual ünvanlar barəsində söhbət açmayacağıq.
* (çətinliyi artırılmış mövzudur, bu hissəni oxumadan 4.2-yə keçə bilərsiniz)
Biz dedik ki, ünvan dəyişənlərinə hər hansı adi dəyişənin və ya funksiyanın ünvanını mənimsətmək üçün & operatorundan istifadə olunur. Gəlin, int tipindən olan x dəyişəni elan edək və ona proqramın icraya başlama ünvanını (main funksiyasının ünvanını) mənimsədək və bu ünvanı çap edək.
#include <iostream>
int main(int argc, char *argv[])
{
int *x;
x = &main;
std::cout<<x;
return 0;
}
İcra edək:
C:\cpp\prog2\Debug>
C:\cpp\prog2\Debug>prog2.exe
0x4004c4
C:\cpp\prog2\Debug>
C:\cpp\prog2\Debug>
Başqa bir proqram tərtib edin və onun icraya başladığı ünvanı çap edin, eyni nəticə alacaqsınız. Sual: necə ola bilər ki, iki müxtəlif proqram yaddaşda eyni ünvandan icra olunmağa başlasın? - Cavab virtual yaddaş.
4.2 Dinamik yaradılma
Biz ünvan dəyişənlərinə qiymət mənimsədilməsi, həmin ünvanda yerləşən məlumata müraciət ilə tanış olduq və qeyd elədik ki, ünvan dəyişənləri proqramın icrası zamanı dinamik yaradıla və yaddaşdan silinə bilər. Ünvan dəyişənləri üçün yaddaşda yer ayırmaq üçün new funksiyasından istifadə edirlər.
Sintaksis aşağıdakı kimidir:
unvan_deyisheni = new tip;
Aşağıdakı kimi:
int x;
x = new int;
Bu zaman yaddaşın vəziyyəti belə olar:
4.3 Dinamik silinmə
Ünvan dəyişəni üçün ayrılan yaddaş sahəsini silmək üçün delete funksiyasından istifadə edirlər.
Sintaksis belədir:
delete unvan_dəyişəni;
Misal üçün:
delete x;
Yaddaşın vəziyyəti:
Biz demək olar ki, ünvan dəyişənləri ilə bağlı bir çox əsas anlayışlarla tanış olduq.
İrəlidəki paraqraflarda biz bu biliklərimizi daha da möhkəmləndirəcəyik.
İndi isə, proqram nümunələri ilə tanış olaq.
Bu proqramların hər biri üzərində ayrı-ayrılıqda işləmədən növbəti paraqrafa keçmək məsləhət deyil.
Aşağıadkı proqramları icra edib yerinə yetirin və onların nə etdiyini izah edin.
//prg_4_2.cpp
#include <iostream>
int main(int argc, char *argv[])
{
int x;
int *y;
// tam tipli ünvan dəyişəni
x=5;
std::cout<<"x-in qiyməti = "<<x<<"\n";
y=&x;
// & ünvan operatorudur
*y=155;
std::cout<<"y-in istinad etdiyi qiymət = "<<*y<<"\n";
// y x-in yaddaşına ünvanlandığından(y=&x)
// *y-i dəyişmək birbaşa x-i dəyişdirir.
std::cout<<"x-in qiyməti = "<<x<<"\n"
return 0;
}
Nümunə
//prg_4_3.cpp
#include <iostream>
int main(int argc, char *argv[])
{
int x;
int *y;
x=5;
y= new int; // dinamik yaradılma
*y=176;
std::cout<<"y-in istinad etdiyi qiymət = "<<*y<<"\n";
delete 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ə
4.4 Ünvan dəyişənlərinin qiymətlərinin dəyişdirilməsi
Biz qeyd etdik ki, ünvan dəyişənləri özlərində qiymət olaraq fiziki yaddaşın hansısa ünvanını saxlayır. Bu ünvanda hər hansı məlumat və ya proqram kodu yerləşə bilər. Həm də, biz qeyd elədik ki, ünvan dəyişənlərinin istinad etdikləri bu ünvanı yaddaşın istənilən başqa yerinə yönləndirə bilərik. Gəlin, proqram kodlarında bütün bu dedikləmizlə əyani tanış olaq.
// prg_4_4.cpp
#include <iostream>
int main(){
int x,y,*z;
x=35;
y=68;
// x və y-in qiymətlərini çap edək
std::cout<<" x-in və y-in qiymətləri "<<x<<" , "<<y<<"\n";
// əvvəlcə z-ə x-in ünvanını mənimsədək
z=&x;
// bu ünvanda olan məlumatı çap edək
std::cout<<z<<" unvaninda olan məlumat "<<*z<<"\n";
// sonra z-ə y-in ünvanını mənimsədək
z=&y;
// bu ünvanda olan məlumatı çap edək
std::cout<<z<<" ünvanında olan məlumat "<<*z<<"\n";
return 0;
}
Nümunə
Proqramı icra edək:
C:\cpp\prog2\Debug>
C:\cpp\prog2\Debug>prog2.exe
x-in və y-in qiymətləri 35 , 68
0x7fff036b1d54 ünvanında olan məlumat 35
0x7fff036b1d50 ünvanında olan məlumat 68
C:\cpp\prog2\Debug>
C:\cpp\prog2\Debug>
İzahı:
Proqramda x və y adlı iki adi dəyişən və z ünvan dəyişəni elan edirik. x və y-ə qiymətlər mənimsədirik. Daha sonra, z-ə əvvəlcə x-in ünvanını mənimsədirik və bu ünvanda yerləşən məlumatı çap edirik, daha sonra, z-ə y-in ünvanını mənimsədirik. Gördüyümüz kimi, ünvan dəyişənlərinin özlərinin qiymətlərini dəyişməklə yaddaşın müxtəlif ünvanlarına istinad etmək olar.