You are on page 1of 41

 İşaretçiler

› Hafıza adresleri
› İşaretçi tanımlama
› Bir işaretçinin gösterdiği adresi elde etme
› İşaretçinin işaretçisi
 Statik ve dinamil nesneler
› new ve delete operatörleri
 Herbir değişkenin değeri RAM de yer
alan bir hafıza hücresinde yer alır.
Değişkenin değeri değişince o hafıza
hücresinin içeriği de değişir.
Hafıza adresleri: 1020 1024 1032

… … 100 … 1024 …
a
int a = 100;
a değişkeninin değeri 100 dür ve bu değer hafızanın 1024
nolu hücresinde saklanır. 1024 sayısı a değişkeninin adresidir.
 İşaretçi bir değişkendir ancak özel bir
değişkendir. Görevi hafıza hücresinin
adresini tutmaktır.
 Programlarımızda işaretçi değişkenleri
hafıza hücrelerini göstermek, onları
işaret etmek için kullanırız.
Hafıza adresleri: 1020 1024 1032

… … 100 … 1024 …
integer
işaretçi
 işaretçi
› C++ her veri türü için işaretçilere sahiptir
 int veri türü için işaretçiler
 Char veri türü için işaretçiler
 Kullanıcının kendi tanımladığı nesneler için
işaretçiler

› işaretçiler için işaretçiler


 int veri türünün işaretçileri için işaretçiler
 İşaretçi değişken tanımlanması
veritipi* işaretçi_ismi;
//veya
veritipi *işaretçi_ismi;
Burada veritipi işaretçinin adresini tutmasını istediğimiz veri
tipidir (int, char vs).

Örnek:
int *n;
char *r;
int **p; // işaretçiye işaretçi atama
 Adres operatörü (&) değişkenin hafızadaki adres
bilgisini okumamızı sağlar.
› Kullanımı: &değişken_ismi

Hafıza adresleri: 1020 1024

… … 100 … … …
a

int a = 100;
//a nın değerini ekrana yazalım,
cout << a; //ekrana 100 yazar
//a nın Hafızada bulunduğu hücrenin adresini yazalım
cout << &a; //Adres ne ise hex olarak ekrana yazılır
Hafıza adresleri: 1020 1024 1032

… 88 100 … … …
a b
#include <iostream>
using namespace std;
Yukarıdaki hafızaya göre sonuç:
int main(){
a nın adresi : 1020
int a, b;
b nin adresi : 1024
a = 88;
b = 100;
cout << "a nın adresi: " << &a << endl;
cout << "b nin adresi: " << &b << endl;
System(" pause ");
Return 0;
}
Hafıza adresleri: 1020 1024 1032

… 88 100 … 1024 …
a p
int a = 100;  Sonuç:
int *p = &a; 100 1024
cout << a << " " << &a <<endl; 1024 1032
cout << p << " " << &p <<endl;
 p işaretçisinin değeri a değişkenin adresidir
 a işaretçisi de değişkendir ve onun da kendisine ait
bir hafıza adresi vardır.
Sonuç ?

58 58 58
 İşaretçinin işaret ettiği değişkenin değerini
referanstan ayırma operatörü ile elde edebiliriz
(*),
Hafıza adresleri: 1020 1024 1032

… 88 100 … 1024 …
a p
int a = 100;
int *p = &a;  Sonuç:
cout << a << endl; 100
cout << &a << endl; 1024
cout << p << " " << *p << endl; 1024 100
cout << &p << endl; 1032
 İşaretçi tanımlama bize sadece o değişkenin bir
işaretçi olduğunu söyler.
int *p;
 * ile ifade ettiğimiz diğer operatör olan referanstan
ayırma operatörü ise işaretçi ile işaret edilen
değişkenin değerini bize söyler.
 Bu iki işlem de * operatörü ile yapılır. Ancak ikisi de
farklı işlemlerdir.
int a = 100, b = 88, c = 8;
int *p1 = &a, *p2, *p3 = &c;
p2 = &b; // p2 points to b
p2 = p1; // p2 points to a
b = *p3; //assign c to b  Sonuç:
*p2 = *p3; //assign c to a
cout << a << b << c; 888
Hafıza gösterimi
Kod
kutu diyagramı
void ikiileCarp(int x,
main
int * p)
{ p 8192
a 18 (8200)
*p = 2 * x;
} İkiileCarp
int main() x 9
{ (8196)
int a = 16;
a 18 main
ikiileCarp(9, &a); ikiileCarp (8192)
return 0;
}
x 9

a =18 olur p
#include <iostream>  Sizce sonuçlar?
using namespace std;
int main (){ deger1==? / deger2==?
int deger1 = 5, deger2 = 15; p1=? p2=?
int *p1, *p2;
p1 = &deger1; // p1 = deger1 in adresi
p2 = &deger2; // p2 = deger2 in adresi
cout<<p1<<endl<<p2<<endl;
*p1 = 10; // p1 ile işaret edilen hucredeki deger p1=10
*p2 = *p1; // p2 ile işaret edilen hücredeki deger p1 ile isaret //edilen
hücredeki değere eşitleniyor
cout<<deger1<<endl<<deger2<<endl;
p1 = p2; // p1 = p2 (işaretçiler eşitlendi) artık p1 deger2 yi isaret
ediyor
cout<<p1<<endl<<p2<<endl;
*p1 = 20; // p1 in isaret ettiği deger 20 olarak guncellendi
cout<<*p1<<endl<<*p2<<endl;
cout << "deger1==" << deger1 <<endl<<"deger2==" << deger2<<endl;
cout<<"deger1 adresi: "<<&deger1<<endl<<"deger2 adresi: "<<&deger2<<endl;
system("pause");
return 0;
}
#include <iostream>
using namespace std;
int main ()
{
int a = 3;
char s = 'z';
double d = 1.03;
int *pa = &a;
char *ps = &s;
double *pd = &d;
// sizeof byte cinsinden boyut bilgisi dondurur
cout << sizeof(pa) << sizeof(*pa)
<< sizeof(&pa) << endl;
cout << sizeof(ps) << sizeof(*ps)
<< sizeof(&ps) << endl;
cout << sizeof(pd) << sizeof(*pd)
<< sizeof(&pd) << endl;
system("pause");
return 0;
}
Referans hafızadaki bir hücreye verilen
diğer ek bir isimdir.
işaretçi: Referans:

x 9 x
9
ref

ref int x = 9;
int &ref = x;

int x=9;
int x = 9;
int *ref;
int &ref = x; // Bu kullanimda
ref = &x;
// ref artık x hucresinin diger
// bir ismi olmustur
 Referans #include <iostream>
using namespace std;
hafızadaki bir int main ()
hücreye verilen {
diğer ek bir int m = 10;
isimdir. int &j = m; // j bir referans degiskendir
cout << «m in degeri= "<< m << endl;
//10 yazar
j = 18;
cout << «m in degeri= " << m << endl;
// 18 yazar

system("pause");

return 0;
}
 Bir Referans değişken daima aynı nesneyi
gösterir. Referans değişkenin değeri
değişirse o referans değişkenin gösterdiği
değişkenin değeri de değişir.
 Referans değişkenler genellikle
fonksiyonlara parametre gönderimi için
kullanılırlar.
#include <iostream>
using namespace std;

void Yerdegistir(char *Ptr1, char *Ptr2){


char temp = *Ptr1;
*Ptr1 = *Ptr2;
*Ptr2 = temp;
}
int main() {
char a = 'y';
char b = 'n';
Yerdegistir(&a, &b);
cout << a << b << endl;
system("pause");
return 0;
}
#include <iostream> Referans yolu ile parametre
using namespace std; gönderiminin iki faydası vardır.
void Yerdegistir(char& y, 1) Eğer fonksiyona buyuk boyutlu bir
char& z) { veri gönderilecekse referans
char temp = y; kullanılmadığı durumda bu verinin
y = z; bir kopyası oluşturulup fonksiyona
z = temp;
} gönderilecektir. Ancak referans
int main() { kullanılırsa bunun önüne geçilir.
char a = 'y'; 2) Dikkat edilirse referans ile fonksiyona
char b = 'n'; parametre gönderildiğinde
Yerdegistir(a, b); fonksiyondan return ile geri dönüş
cout << a << b << endl;
return 0; yapılmasına çoğu zaman gerek
system("pause"); kalmaz. Bu da programı hem verimli
} hale getirir hem de sadeleştirir.
 Birdizinin ismi aslında o dizinin ilk elemanını
işaret eden bir işaretçidir.

1000

1004

1008

1012

1016
Dizi İsmi Bir İşaretçi Sabittir
#include <iostream>
using namespace std;

int main (){


int a[5];
cout << "a[0] in adresi : " << &a[0] << endl
<< "isaretci : " << a << endl;
system("pause");
return 0;
}

Sonuç:
a[0] in adresi: 0x6ffe00
işaretçi: 0x6ffe00
Bir Dizi İsmini Referanstan Ayırma

Bu eleman a[0]
veya *a olarak
ifade edilir
#include <iostream>
using namespace std;
a[0] 2 int main(){
a int a[5] = {2,4,6,8,22};
a[1] 4
cout << *a <<endl<< a[0]<<endl;
a[2] 6 system("pause");
a[3] 8 return 0;
}
a[4] 22
a
Dizi İsimleri Olarak İşaretçiler
 Bir diziye erişmek için o dizinin ismi yerine dizinin
ilk elemanını işaret eden herhangi bir işaretçi
kullanılabilir.
*p yerine *a yazabiliriz

#include <iostream>
using namespace std;
a p int main(){
int a[5] = {2,4,6,8,22}; Sonuç:
a[0] 2 int *p = a; 22
a[1] 4 cout << a[0] << " "
a[2] 6 << *p;
a[3] 8 system("pause");
a[4] 22 return 0;
a }
İşaretçi Aritmetiği
 Birp işaretçisi verildiğinde, p+n o işaretçinin n
sayısı kadar sonraki hafıza hücresini işaret eder.

#include <iostream>
using namespace std;
int main(){
int a[5] = {2,4,6,8,22};
int *p = a;
cout << a[2] << " "
<< *(p+2);
system("pause");
return 0;
}
Dizi İşaretçilerini Referanstan Ayırma

a[0] veya *(a + 0) 2 a


a[1] veya *(a + 1) 4 a + 1
a[2] veya *(a + 2) 6 a + 2
a[3] veya *(a + 3) 8 a + 3
a[4] veya *(a + 4) 22 a + 4

*(a+n) a[n] ile aynıdır


İşaretçi Dizileri ve Diziler için İşaretçiler
a
p
b
c

Bir işaretçi dizisi Bir dizi için işaretçi


int a = 1, b = 2, c = 3; int list[5] = {9, 8, 7, 6, 5};
int *p[5]; int *p;
p[0] = &a; p = list;//ilk elemanı işaret eder
p = &list[0];// ilk elemanı işaret eder
p[1] = &b;
p = &list[1];//ikinci elemanı işaret
p[2] = &c; eder
p = list + 1; // ikinci elemanı işaret
eder
 Statik Bellek Tahsisi
› Bellek derleme aşamasında tahsis edilir
 Dinamik Hafıza
› Bellek yürütme aşamasında tahsis edilir
 Statik nesne  Dinamik nesne
› Bellek otomatik olarak › Program çalışırken bellek
ayrılır "isteyebiliriz".
› Nesne çalışma alanı dışına › Hafızayı kendimiz tahsis edebilir
çıktığında hafıza otomatik ve serbest bırakabiliriz!
olarak iade edilir. › Daha güçlü programlama
yeteneği (tabii daha fazla hata
potansiyeli!)
› Büyük bellek
değişkenlerinin (örn dizilerin) › Bellek, tahsis talebiyle program
bildirimi, program tarafından alınır
derlenmeden önce new işlevi
belirlenmelidir. › Dinamik nesneler tahsis edildikleri
› int öğrenciler [10]; fonksiyon dışında da var
› Peki ya önceden tam olabilirler
öğrenci sayısını bilmiyorsak
ne olur? › Nesneye ayrılan bellek bir iade
talebi ile iade edilir.
 delete işlevi
Bellek Tahsisi

new
delete
{
int a[200]; int* ptr;
int *ptr = a; ptr = new int[200];

}

delete [] ptr;
Syntax
ptr = new VeriTipi;

burada ptr VeriiTipi ile belirtilen tipte bir işaretiçidir.

Örnek
int* p = new int;
Henüz başlatılmamış
int türde bir değişken

p
Syntax
delete p;
#include <iostream>
p ile gösterilen hafıza serbest
using namespace std;
bırakılır. p artık tanımsızdır.
int main (){
Örnek int* p = new int;
int* p = new int; *p = 10;
*p = 10; cout << *p << endl;
delete p;
delete p; cout << *p << endl;
system("pause");
return 0;
p 10 }
New ile dizi: dinamik diziler
Syntax
p = new VeriTipi[aciklama];
Burada
p VeriTipi tipinde bir işaretçidir. aciklama ise üretilecek nesne
sayısıdır.

new
p
 int *p, n=10;
p = new int;
new

p = new int[100]; p
new
p = new int[n]; p
Hafıza Tahsisi Örneği
// Boyutunu bilmediğimiz bir dizi tanımlamak istiyoruz
#include <iostream>
using namespace std;

int main()
{
int n;
cout <<"Kac ogrenci ? ";
cin >> n;
int *notlar = new int[n];
for(int i=0; i < n; i++){
int puan;
cout << (i+1)<<". Ogrenci notu : ";
cin >> puan;
notlar[i] = puan;
}
cout<<endl<<"Girdiginiz Notlar : "<<endl<<endl;
for(int i=0; i < n; i++){
cout << (i+1)<<". Ogrenci notu : "<<notlar[i]<<endl;
}
system("pause");
return 0;
}
Hafızayı serbest bırakma (delete)
Artık İşaretçi Problemi
int *A = new int[5]; #include <iostream>
using namespace std;
for(int i=0; i<5; i++)
A[i] = i; int main()
{
int *B = A; int *A = new int[5];
for(int i=0; i<5; i++)
A[i] = i;
A int *B = A;
0 1 2 3 4
B for(int i=0; i<5; i++)
cout<<B[i]<<endl;
cout<<endl<<endl;
delete [] A; delete [] A;
B[0] = 1; // hata!
for(int i=0; i<5; i++)
Bu alan artık programa ait değil cout<<B[i]<<endl;

A system("pause");
return 0;
B }
Hafıza Kaybı Problemi
#include <iostream>
int *A = new int [5]; using namespace std;
for(int i=0; i<5; i++)
int main()
A[i] = i; {
int *A = new int[5];
for(int i=0; i<5; i++)
A 1 A[i] = i;
0 2 3 4
for(int i=0; i<5; i++)
cout<<A[i]<<endl;
A = new int [5];
cout<<endl<<endl;

A = new int [5];


Bu alanlar artık programa ait değil
for(int i=0; i<5; i++)
0 1 2 3 4 cout<<A[i]<<endl;
system("pause");
A return 0;
}
#include <iostream>
using namespace std;
void F1(int* temp){ *temp = 99; }
int main()
{
int *p1, *p2;
p1 = new int;
*p1 = 50;
p2 = p1;
F1(p2);
cout << *p1 << " " << *p2 << endl;
p1 = new int;
*p1 = 88;
cout << *p1 << " " << *p2 << endl;
delete p1;
delete p2;

system("pause");
return 0;
}
#include <iostream>
using namespace std;
int main( ){
int i, *p, *r, t[4]={0,1,2,3};

p = new int[4];
for(i=0; i<4; i++)
p[i] = 6*(i+1);
r = t;
for(i=3; i>=0; i--)
r[i] -= 1;
r[2] = 8;
for(i=0; i<4; i++)
t[i] = p[i] + r[i];
for(i=0; i<4; i++)
cout << t[i] << " ";
delete [] p;
system("pause");
return 0;
}
 Aşağıdaki kodu inceleyiniz ve hangi amaçla
kullanılabileceğini değerlendiriniz.
#include <iostream>
using namespace std;
int main( ){
int i, *p, *r, t[4]={0,1,2,3};

try {
char* c = new char[100000000000];
}
catch (std::bad_alloc&) {
cout<<endl<<"Hata!!! Hafizada Yeterli Alan Yok"<<endl;
}

system("pause");
return 0;
}

You might also like