Professional Documents
Culture Documents
2 N 2 Refernce Pointer-4
2 N 2 Refernce Pointer-4
2 N 2 Refernce Pointer-4
Mürəkkəb tip başqa bir növ baxımından müəyyən edilmiş bir növdür. C++ var bir neçə birləşmə
növü var, bunlardan ikisi :
• istinadlar
• Göstəricilər
İstinadlar
İstinad obyekt üçün alternativ ad təyin edir. İstinad növü “istinad edir” başqa bir növü. Biz &d
formasının deklaratorunu yazmaqla istinad tipini təyin edirik . burada d elan edilən addır
növü və adı
int ival = 1024;
int & refVal = ival ; // refVal (başqa adıdır ) ival- a istinad edir
Bir qayda olaraq, biz dəyişəni işə saldığımız zaman başlatıcının dəyəri fayla kopyalanır
yaratdığımız obyekt. Başlatıcının surətini çıxarmaq yerinə istinad təyin etdiyimiz zaman dəyər,
biz istinadı onun başlatıcısına bağlayırıq. Başlandıqdan sonra istinad qalır ilkin obyektinə
bağlıdır. İstinadı başqasına istinad etmək üçün yenidən bağlamağın heç bir yolu yoxdur obyekt.
İstinadı yenidən bağlamağın heç bir yolu olmadığı üçün istinadlar işə salınmalıdır.
int &refVal2; // xəta: istinad işə salınmalıdır
İstinad Ləqəbdir
İstinad obyekt deyil. Bunun əvəzinə, istinad artıq mövcud olan obyektin başqa adıdır.
İstinad müəyyən edildikdən sonra həmin istinad üzərindəki bütün əməliyyatlar istinadın bağlı
olduğu obyekt üzərində faktiki əməliyyatlardır:
İstinadlar obyekt olmadığı üçün biz istinada istinad təyin etməyə bilərik.
İstinad tərifləri
Biz bir tərifdə birdən çox istinad təyin edə bilərik. Hər bir identifikator a
istinaddan əvvəl & simvolu olmalıdır:
int *ip1, *ip2; // həm ip1, həm də ip2 int üçün göstəricilərdir
ikiqat dp , *dp2; // dp2 ikiqat göstəricidir; dp ikiqatdır
Obyektin ünvanının götürülməsi
Göstərici başqa obyektin ünvanını saxlayır. istifadə edərək obyektin ünvanını alırıq
operatorun ünvanı (& operatoru):
int ival = 42;
int *p = & ival ; // p ival ünvanını saxlayır ; p ival üçün göstəricidir
İstinadlar obyekt deyil, onların ünvanları yoxdur. Beləliklə, istinad üçün göstərici təyin etməyə
bilərik . Göstəricinin növləri və onun işarə etdiyi obyekt uyğun olmalıdır
ikiqat dval ;
double * pd = & dval ; // ok: başlatıcı dublun ünvanıdır
ikiqat *pd2 = pd ; // ok: başlatıcı ikiqat göstəricidir
int *pi = pd ; // xəta: pi və pd növləri fərqlənir
pi = & dval ; // xəta: ikiqat ünvanın int -ə göstəriciyə təyin edilməsi
int k=19;
int ref=&k;
Göstərici Dəyəri
Göstəricidə saxlanılan dəyər (yəni ünvan) dörd vəziyyətdən birində ola bilər:
• Bir obyektə işarə edə bilər.
• O, obyektin sonundan dərhal keçmiş yeri göstərə bilər.
• , heç bir obyektə bağlı olmadığını göstərən null göstərici ola bilər .
• Etibarsız ola bilər; əvvəlki üçdən fərqli dəyərlər etibarsızdır.
Etibarsız göstəricinin dəyərini kopyalamaq və ya başqa yolla əldə etməyə cəhd etmək
xətadır
Obyektə daxil olmaq üçün göstəricidən istifadə
Göstərici obyektə işarə etdikdə, həmin obyektə daxil olmaq üçün dereference operatorundan (*
operatorundan) istifadə edə bilərik:
int ival = 42;
int *p = & ival ; // p ival ünvanını saxlayır ; p ival üçün göstəricidir
cout << *p; // * p nöqtəsi olan obyekti verir; çap 42
Göstəriciyə istinadın ləğvi göstəricinin göstərdiyi obyekti verir. İstinadın nəticəsini təyin etməklə
həmin obyektə təyin edə bilərik:
int i = 42;
p = & i ; // & operatorun ünvanı kimi ifadədə istifadə olunur
*p = i ; // * ifadədə istinad operatoru kimi istifadə olunur
int &r2 = *p; // * istinad operatorudur, r2 i -yə istinad edir ;
Null Göstəricilər
Null göstərici heç bir obyektə işarə etmir. Kod onu istifadə etməyə cəhd etməzdən əvvəl
göstəricinin boş olub olmadığını yoxlaya bilər. Null göstərici əldə etməyin bir neçə yolu var:
Ən birbaşa yanaşma, yeni standart tərəfindən təqdim edilən literal nullptr istifadə
edərək göstəricini işə salmaqdır. nullptr hər hansı digər göstərici növünə
çevrilə bilən xüsusi tipə malik hərfidir. Alternativ olaraq, biz p2 tərifində etdiyimiz kimi
göstəricini hərfi 0- a başlaya bilərik .
cstdlib başlığının 0 olaraq təyin etdiyi NULL adlı preprosessor dəyişənindən istifadə edir .
Null Göstəricilər
#include < iostream >
ad boşluğundan istifadə std ;
int main()
{
int *p1= nullptr ;
əgər(!p1)
cout << "p1 sıfırdır\n";
int *p2=0;
əgər(!p2)
# ./ a.out
cout << "p2 sıfırdır\n";
p1 sıfırdır
int *p3=NULL;
p2 sıfırdır
əgər(!p3)
p3 sıfırdır
cout << "p3 sıfırdır\n";
}
Ön prosessor
Preprocessor kompilyatordan əvvəl işləyən proqramdır. Preprosessor dəyişənləri preprosessor
tərəfindən idarə olunur və std ad sahəsinin bir hissəsi deyil . Nəticədə std :: prefiksi
olmadan birbaşa onlara istinad edirik.
Biz preprosessor dəyişənindən istifadə etdikdə, preprosessor avtomatik olaraq dəyişəni öz dəyəri
ilə əvəz edir. Beləliklə, göstəricini NULL- a başlamaq onu 0 -a başlatmağa bərabərdir .
Müasir C++ proqramları ümumiyyətlə NULL- dən istifadə etməməli və əvəzinə nullptr-
dən istifadə etməlidirlər .
Hətta dəyişənin qiyməti 0 olsa belə, int dəyişənini göstəriciyə təyin etmək qeyri-qanunidir .
int *pi;
int sıfır = 0;
pi = sıfır; // xəta: göstəriciyə int təyin edilə bilməz
Məsləhət: Bütün Göstəriciləri işə salın
Başlanmamış göstəricilər işləmə zamanı səhvlərinin ümumi mənbəyidir.
Əksər kompilyatorlarda, başlatılmamış göstəricidən istifadə etdiyimiz zaman, göstəricinin
yerləşdiyi yaddaşdakı bitlər ünvan kimi istifadə olunur. Başlanmamış göstəricidən istifadə,
ehtimal olunan yerdəki ehtimal olunan obyektə daxil olmaq üçün sorğudur. Göstəricinin ayrıldığı
yaddaşda olan bitlərdən yaranan etibarlı ünvanı etibarsız ünvandan ayırmaq üçün heç bir yol
yoxdur.
Bütün dəyişənləri işə salmaq tövsiyəmiz göstəricilər üçün xüsusilə vacibdir. Mümkünsə,
göstəricini yalnız onun göstərməli olduğu obyekt müəyyən edildikdən sonra təyin edin.
Göstəriciyə bağlamaq üçün heç bir obyekt yoxdursa, göstəricini nullptr və ya sıfır olaraq işə
salın. Beləliklə, proqram göstəricinin obyektə işarə etmədiyini aşkar edə bilər.
Tapşırıq və Göstəricilər
İstinad Göstərici
obyekt deyil. obyektdir.
Göstərici ilə onun tutduğu ünvan arasında belə bir
İstinad müəyyən edildikdən sonra həmin eynilik yoxdur. Kimi hər hansı digər ( istinadsız )
istinadı başqa obyektə istinad etmək dəyişən, biz göstəriciyə təyin etdikdə, göstəricinin
üçün heç bir yol yoxdur özünə yeni qiymət veririk. Təyinat göstəricini fərqli
obyektə işarə edir:
int i = 42;
int *pi = 0; // pi işə salınıb, lakin heç bir obyektə müraciət etmir
int *pi2 = & i ; // pi2 i ünvanını saxlamaq üçün işə salındı
int *pi3; // əgər pi3 blok daxilində müəyyən edilibsə, pi3 işə salınmayıb
pi3 = pi2; // pi3 və pi2 eyni obyektə ünvanlanır, məsələn, i
pi2 = 0; // pi2 indi heç bir obyektə müraciət etmir
Göstərici əməliyyatları
int *pi= nullptr ;
int ival =15;
pi = & ival ; // pi ilə qiymət dəyişdirilir; pi indi ival -a işarə edir
// pi-yə yeni dəyər təyin edilir, bu da pi-nin saxladığı ünvanı
dəyişir .
Digər tərəfdən, *pi = 0 ; // ivaldakı qiymət dəyişdirildi; pi dəyişməzdir
Göstərici vəziyyətdədir
göstərici 0 olarsa , şərt yanlışdır , sıfırdan fərqli hər hansı göstərici doğru
int ival = 1024;
kimi
int qiymətləndirilir
*pi = 0; // pi etibarlı, null göstəricidir
int *pi2 = & ival ; // pi2 ival ünvanını saxlayan etibarlı göstəricidir
əgər (pi) // pi 0 dəyərinə malikdirsə, şərt yanlış kimi qiymətləndirilir
//...
əgər (pi2) // pi2 ival- ı göstərirsə , 0 deyil; şərt doğru kimi qiymətləndirilir
//...
Göstəricilərin müqayisəsi
Eyni tipli iki etibarlı göstəricini nəzərə alaraq, biz onları bərabərlik (==) və ya
bərabərsizlik (!=) operatorlarından istifadə etməklə müqayisə edə bilərik. Bu
operatorların nəticəsi bool növünə malikdir
İki göstərici eyni ünvanı tutursa bərabərdir, əks halda isə qeyri-bərabərdir. İki göstərici
əgər hər ikisi null olarsa, eyni obyektə ünvanlanırsa və ya hər ikisi eyni obyektdən bir keçən
göstəricidirsə, eyni ünvanı saxlayın (yəni bərabərdir). Nəzərə alın ki, obyektin göstəricisi ilə fərqli
obyektin sonundan keçən göstərici eyni ünvanı tuta bilər. Belə göstəricilər bərabər müqayisə
edəcək.
boş* Göstəricilər
Void* növü istənilən obyektin ünvanını saxlaya bilən xüsusi göstərici növüdür. Hər hansı digər
göstərici kimi, void* göstəricisi də ünvanı saxlayır, lakin həmin ünvandakı obyektin növü
məlum deyil. int k=15;
ikiqat obj = 3.14, * pd = & obj ;
// ok: void* istənilən məlumat göstərici növünün ünvan dəyərini ikiqat m=3,14;
void * pv = & obj ; // obj istənilən növ obyekt ola bilər p1=&k;
(* və ya &) tək bir ifadədə müəyyən edilmiş bütün dəyişənlərə aid olduğunu düşünmək çox
yayılmış yanlış fikirdir . Problemin bir hissəsi ona görə yaranır ki, biz tip dəyişdiricisi ilə elan
edilən ad arasında boşluq qoya bilərik:
int i = 42;
int *p; // p int üçün göstəricidir
int *&r = p ; // r p göstəricisinə istinaddır
r = & i ; // r göstəriciyə istinad edir; & i-nin r-yə təyin edilməsi p-ni i -yə işarə
edir
*r = 0; // istinadın ləğvi r i verir , p nöqtəsi olan obyekt; i 0- a dəyişir
R növünü başa düşməyin ən asan yolu tərifi sağdan sola oxumaqdır. Dəyişənin adına ən yaxın simvol (bu
halda & in &r ) dəyişənin növünə ən çox təsir edən simvoldur. Beləliklə, r-nin istinad olduğunu bilirik .
Deklaratorun qalan hissəsi r-nin istinad etdiyi növü müəyyən edir . Növbəti simvol, * bu halda, r
tipinin işarə növü olduğunu bildirir. Nəhayət, bəyannamənin əsas növü deyir ki, r int üçün
göstəriciyə istinaddır .
#include < iostream >
int main() İstinad istinad etdiyi obyektin davranışını götürür.
{ Göstəriciyə istinad göstərici kimi müxtəlif obyekti göstərə bilər.
int i = 42;
int *p;
int *&r = p;
r = & i ;
*r = 0; # ./ a.out
std :: cout << " i =" << i << std :: endli ;=0
int k=55;
r=&k;
*r=13;
std :: cout << "k=" << k << std :: endl ;k=13
std :: cout << "*p=" << *p << std :: endl*p=13 ;
std :: cout << " i =" << i << std :: endli ;=0
0 qaytarmaq;
}
Belə bir hal var ki, int &r2=*p; r2 göstəriciyə istinad deyil, göstərici nöqtəsi olan obyektə istinaddır.
int m=16;
int *p=&m;
int &r2=*p;
r2=19;
cout << r2 << endl ;;
cout << m << endl ;; 19
cout << *p << endl ;; 19
int N=114; 19
=========
p=&N; // p N-ə işarə edir, lakin m-in r2 istinadı
cout <<"=========\n"<< r2 << endl ;; 19
cout << m << endl ;; 19
cout << *p << endl ;; 114
# ./ a.out # ./ a.out
-943488677 Seqmentasiya xətası (əsas boşaldılmış)
İş 2.25: Aşağıdakı dəyişənlərin hər birinin növlərini və qiymətlərini təyin edin.
(a) int *ip, &r = *ip,*&rp=ip;
(b) int i , * ip = 0;
(c) int * ip , ip2;