2 N 2 Refernce Pointer-4

You might also like

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 29

Qarışıq növləri

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:

int ival = 1024;


int &refVal = ival;
refVal = 2; // refValın istinad etdiyi obyektə 2 təyin edir , yəni ival
int ii = refVal ; // ii = ival kimi
İstinad təyin edərkən, istinadın bağlı olduğu obyekti təyin edirik. İstinadın dəyərini əldə etdikdə,
həqiqətən istinadın bağlı olduğu obyektin dəyərini alırıq.

İ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 i = 1024, i2 = 2048; // i və i2 hər ikisi intsdir


int &r = i , r2 = i2; // r i ilə bağlı istinaddır ; r2 bir intdir
int i3 = 1024, & ri = i3; // i3 bir intdir ; ri i3-ə bağlı istinaddır
int &r3 = i3, &r4 = i2; // həm r3, həm də r4 istinadlardır

İstinadın növü və istinadın istinad etdiyi obyekt tam uyğun olmalıdır.


Bundan əlavə, istinad hərfi və ya daha ümumi ifadənin nəticəsi ilə deyil, yalnız obyektlə əlaqələndirilə bilər:

int &refVal4 = 10; // xəta: başlatıcı obyekt olmalıdır


ikiqat dval = 3.14;
int &refVal5 = dval ; // xəta: başlatıcı int obyekti olmalıdır
İş 2.15: Aşağıdakı təriflərdən hansı, əgər varsa, etibarsızdır? Niyə?
(a) int ival = 1,01;
(b) int &rval1 = 1,01;
(c) int &rval2 = ival ;
(d) int &rval3;
İş 2.16: Aşağıdakı tapşırıqlardan hansı, əgər varsa, etibarsızdır? Əgər
etibarlıdırlar, nə etdiklərini izah edin.
int i = 0, &r1 = i; ikiqat d = 0, &r2 = d;
(a) r2 = 3,14159;
(b) r2 = r1;
(c) i = r2;
(d) r1 = d;
İş 2.17: Aşağıdakı kod nə çap edir?
int i , & ri = i ;
i = 5; ri = 10;
std :: cout << i << " " << ri << std :: endl ;
Göstəricilər
Göstərici başqa bir növü "göstərən" mürəkkəb tipdir. İstinadlar, göstəricilər kimi
digər obyektlərə dolayı giriş üçün istifadə olunur. İstinaddan fərqli olaraq,
• göstərici özlüyündə bir obyektdir.
• Göstəricilər təyin edilə və kopyalana bilər;
• bir göstərici ömrü boyu bir neçə fərqli obyekti göstərə bilər.
• göstəricinin təyin olunduğu anda işə salınmasına ehtiyac yoxdur.
Digər daxili növlər kimi, blokun əhatə dairəsində müəyyən edilmiş göstəricilər
başlanğıclaşdırılmadıqda qeyri-müəyyən dəyərə malikdir.
deklaratorunu yazmaqla göstərici tipini təyin edirik , burada d müəyyən edilən addır. * hər bir
göstərici dəyişəni üçün təkrarlanmalı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:

*p = 0; // * obyekti verir; p vasitəsilə ival üçün yeni qiymət təyin edirik


cout << *p; // 0 çap edir
Bəzi Simvolların Çoxlu Mənaları Var
Bəzi simvollar, məsələn, & və * istifadə olunur:
• Bəyannamənin bir hissəsi kimi.
int i = 42;
int &r = i ; // & növü izləyir və bəyannamənin bir hissəsidir; r istinaddır
int *p; // * bir növü izləyir və bəyannamənin bir hissəsidir; p göstəricidir
int &r2 = *p; // & bəyannamənin bir hissəsidir, r2 istinaddır
• İfadədə operator kimi

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:

int *p1 = nullptr ; // int -ə ekvivalent *p1 = 0;


int *p2 = 0; // birbaşa p2-ni 0 hərfi sabitindən başlatır ,
int *p3 = NULL; // int -ə ekvivalent *p3 = 0; # cstdlib daxil etməlidir

Ə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;

saxlaya bilər boşluq *p1 ;

void * pv = & obj ; // obj istənilən növ obyekt ola bilər p1=&k;

pv = pd ; // pv istənilən tip üçün göstərici saxlaya bilər p1=&m;

boş* istifadə olunur:


• Onu başqa göstərici ilə müqayisə etmək üçün,
• onu funksiyaya ötürmək və ya funksiyadan qaytarmaq,
• Onu başqa boşluq* göstəricisinə təyin etmək üçün.
Biz onun ünvanladığı obyektlə işləmək üçün boşluqdan* istifadə edə bilmərik —
biz həmin obyektin tipini bilmirik və tip obyektdə hansı əməliyyatları yerinə yetirə biləcəyimizi
müəyyən edir.
int k=19;
ikiqat m=3,14;
boşluq *p0;
p0=&k;
std :: cout << *p0 << std :: endl ;
p0=&m;
std :: cout << *p0 << std :: endl ;

root@SH :/home/ shahin /DƏRS/C++/2/2_0_LEC # clang++ - std = c++ 11 1_4.cpp


1_4.cpp:8:13: xəta : binar ifadə üçün etibarsız operandlar (' ostream ' (aka '
basic_ostream <char>') və 'void')
std :: cout << *p0 << std :: endl ;
Biz onun ünvanladığı obyektlə işləmək üçün boşluqdan* istifadə edə bilmərik —
biz həmin obyektin tipini bilmirik və tip obyektdə hansı əməliyyatları yerinə yetirə biləcəyimizi
müəyyən edir.
int k=19;
ikiqat m=3,14;
boşluq *p0;
p0=&k;
std :: cout << *p0 << std :: endl ;std:: cout << * (int *) p0 << std::
endl ;
p0=&m;
std :: cout << *p0 << std :: endl std::
; cout << * (ikiqat *) p0 << std::
endl ;
# ./ a.out
19
3.14
İş 2.20: Aşağıdakı proqram nə edir?
int i = 42;
int *p1 = & i ;
*p1 = *p1 * *p1;
İş 2.21: Aşağıdakı təriflərin hər birini izah edin. olub olmadığını göstərin
hər hansı bir qanunsuzdur və əgər belədirsə, niyə.
int i = 0;
(a) ikiqat* dp = & i ;
(b) int * ip = i ;
(c) int *p = & i ;
İş 2.22: p-nin int üçün göstərici olduğunu fərz etsək , aşağıdakı kodu izah edin:
əgər (p) // ...
əgər (*p) // ...
İş 2.23: Göstərici p verilmişdirsə, p-nin a nöqtəsini göstərib-göstərmədiyini
müəyyən edə bilərsiniz
etibarlı obyekt? Əgər belədirsə, necə? Əgər yoxsa, niyə də olmasın?
İş 2.24: Nə üçün p- nin başlanğıcı qanunidir, amma lp qanunsuz?
int i = 42; void *p = &i; uzun *lp = &i;
Mürəkkəb tip bəyannamələr
Tək bir tərif müxtəlif növ dəyişənləri təyin edə bilər:

// i intdir ; _ p int üçün göstəricidir ; r int -ə istinaddır


int i = 1024, *p = & i , &r = i ;

(* 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 *p; // qanuni, lakin yanıltıcı ola bilər


int *p1, p2; // p1 int üçün göstəricidir ; p2 intdir
int *p1, *p2; // həm p1, həm də p2 int üçün
göstəricilərdir
Göstəricilərə göstəricilər
deklaratora neçə növ dəyişdiricinin tətbiq oluna biləcəyinə dair heç bir məhdudiyyət yoxdur .
Birdən çox dəyişdirici olduqda, onlar məntiqli, lakin həmişə aydın olmayan üsullarla birləşirlər.
Bir nümunə olaraq bir göstəricini nəzərdən keçirək. Göstərici yaddaşda olan bir obyektdir, ona
görə də hər hansı bir obyekt kimi onun da ünvanı var. Buna görə də, göstəricinin ünvanını başqa
bir göstəricidə saxlaya bilərik.
* - göstərici.
** - göstəriciyə göstərici,
***
int- göstəriciyə
ival = göstəriciyə
1024; göstərici pi int üçün göstəricidir
int *pi = & ival ; // pi int-i göstərir və ppi int üçün
int ** ppi = &pi; // ppi int üçün göstəriciyə işarə göstəriciyə göstəricidir .
edir
#include < iostream >
# ./ a.out
int main() İval dəyəri
birbaşa dəyər: 1024
{ int ival = 1024;
dolayı dəyər: 1024
int *pi = & ival ; ikiqat dolayı dəyər: 1024
int ** ppi = &pi;
std :: cout << " ivalın dəyəri \n"
<< "birbaşa dəyər: " << ival << "\n"
<< "dolayı dəyər: " << *pi << "\n"
<< "ikiqat dolayı dəyər: " << ** ppi
<< std :: endl ;
0 qaytarmaq;
}
Göstəricilərə istinadlar
İstinad obyekt deyil.

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

Bu vəziyyətdə R int -ə istinad edəcək , qeyri-müəyyən dəyəri çap edəcək;

int *p1; int *p1= nullptr ;


int &R=*p1; int &R=*p1;
cout << R << endl ;; cout << R << endl ;;

# ./ 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;

Məşq 2.25. r,rp dəyişəninin qiymətini təyin edin


(b) (c)
int main() int main()
{ {
int * ip , &r =* ip ,*& rp = ip ; int N=19;
int u=100; int * ip =&N, &r =* ip ,*& rp = ip ;
ip =&u; int u=100;
cout << r << endl ; ip =&u;
cout << * rp << endl ; cout << r << endl ;
cout << * rp << endl ;
}
}

You might also like