You are on page 1of 42

POINTER

(İŞARETÇİ-GÖSTERİCİ-GÖSTERGE)
•NEDİR?
•NASIL TANIMLANIR?
•NİÇİN İHTİYAÇ VAR?
•NE İŞE YARAR?

1
POINTER(İŞARETÇİ) NEDİR?
Bilgisayarın ana belleği (RAM) sıralı kaydetme
bölgelerinden(gözlerinden) oluşmuştur. Her göze
bir adres atanmıştır. Bu adreslerin değerleri 0 ila
RAM’e bağlı olarak MAX arasında değerler alabilir.

2
POINTER(İŞARETÇİ) NEDİR?
Programlama dillerinde bir değişken
tanımlandığında, o değişken için RAM’den bir
bölge ayrılır.
Bu bölgeler, değişkenin tipine bağlı olarak 2, 4, 8,
… byte’lık bölgelerdir.
Pointer(işaretçi); bellek alanındaki bir gözün
adresinin saklanabildiği değişkendir.
Pointerlara, veriler(yani değişkenlerin içeriği)
değil, o verilerin bellekte saklı olduğu bellek
gözlerinin başlangıç adresi atanır.
3
İŞARETÇİ(POINTER) DEĞİŞKEN
NASIL TANIMLANIR?
Pointer değişkenler şöyle tanımlanır:
türbildirimdeyimi *işaretçiadı;
Burada tür bildirim deyimi herhangi bir tip int,float,vb. olabilir.
Değişken isminin önüne konan * karakteri indirection operatörü
olarak adlandırılır ve türbildirimdeyimi deyimi ile bildirilen
işaretçiadı değişkenini işaret eder.

Örnekler:
int *p1; float *p2,*p3;
double *p_a; char *p_isim;
4
İŞARETÇİ(POINTER) DEĞİŞKEN
NASIL TANIMLANIR?
Bir işaretçiye, bir değişkenin adresini atamak
için & adres-operatörü kullanılır.
Bu operatör bir değişkenin önüne konursa, o
değişkenin içeriği ile değil de adresi ile
ilgileniliyor anlamına gelir.

5
İŞARETÇİ(POINTER) DEĞİŞKEN
NASIL TANIMLANIR?
Örneğin int tipindeki a adlı bir değişken ve *pa(pointer
tipinde) ise, a değişkenini işaret eden bir değişken
olsun. Söz konusu bu işlemleri sağlamak için öncelikle
değişkenlerin tanımlanması ve daha sonra gerekli atama
işlemlerinin yapılması gerekmektedir.
int tam=33,*ptam;
ptam=&tam;
/*tam değişkenine atanan değerin başlangıç adresi ptam adlı pointer
değişkene atanmaktadır.*/

6
BELLEKTEKİ DURUM

Pointer bir değişkenin adresini göstermesi

7
BELLEKTEKİ DURUM

ptam

33

8
Örnek-1
#include <stdio.h>
int main() {
int *ptam, tam = 33;
ptam = &tam;
printf("tam: icerik = %d\n", tam);
printf("tam: adres = %p\n",&tam);
printf("tam: adres = %p\n",ptam);
return 0;
}

9
İŞARETÇİ (POINTER) DEĞİŞKEN
NASIL TANIMLANIR?
Benzer şekilde float tipindeki b adlı bir
değişken ve *pb(pointer tipinde) ise b
değişkenini işaret eden bir değişken olsun.
Söz konusu bu işlemleri sağlamak için gerekli
kodlar:

float b,*pb; pb=&b;

10
Örnek-2
#include<stdio.h>
#include<conio.h>
main(){
int a,b,*p;
p=&a;//pointer değişken kendisi ile aynı tipten değişkenin adresine işaret edebilir
*p=5;//p nin işaret ettiği adrese 5 değerini ata...
b=*p;//p nin işaret ettiği adresteki değeri b değişkenine ata…
printf("\n\n int a:%d\t int *p:%d",a,*p);
printf("\nint a bellek adresi:%p\t p'nin adresi:%p",&a,p);
printf("\n int a:%d\tint *p:%d\t int b'nin degeri:%d",a,*p,b);
float y=10.2,*py;
//p=&y;HATA:13 Ornek-2.cpp-- [Error] cannot convert 'float*' to 'int*' in assignment
py=&y;
printf("\n\nfloat y:%f\tpointer y:%f",y,*py);
printf("\nfloat y'nin bellek adres no.su:%d\tpointer y:%d",&y,py);
//adresler 16 lı sayı sisteminde değil, 10'lu sayı sisteminde görüntüleniyor...
getch();}

11
Örnek-2-Devam
AÇIKLAMA: Örnek-2’den görülebileceği gibi,
bir değişkenin adresi bir işaretçi(pointer)
değişkende saklandığı zaman hem değişkenin
kendisi, hem de bu alanı işaret eden değişkeni
kullanarak değişken alanındaki değere
erişilebilir.

12
İŞARETÇİLERDE ATAMA İŞLEMLERİ

13
İŞARETÇİLERDE ATAMA İŞLEMLERİ
• Bir göstergenin bellekte herhangi bir bellek
hücresini göstermesi istenmiyorsa NULL sabiti
kullanılır.
• NULL, göstergenin bellekte hiçbir yeri
göstermediğini belirten sabit değerdir.
int *gos=NULL;

14
İŞARETÇİLERİN FONKSİYONLARDA
KULLANIMI
• Daha önce fonksiyonlar konusunda parametre
gönderim yöntemlerinden “değerle çağır (call
by value)” yöntemi kullanıldı.
• Değerle Çağır yönteminde, çağıran
fonksiyondan gönderilen değerler, çağırılan
fonksiyondaki parametrelere kopyalanır.
Kopyaların değiştirilmesi orijinal değerleri
etkilemez.

15
İŞARETÇİLERİN FONKSİYONLARDA
KULLANIMI-Örnek3-3:
#include<stdio.h>
#include<conio.h>
//bu fonksiyon parametrelere gönderilen iki sayının yerlerini değiştirmekte MİDİR???
int yer_degistir(int a , int b) {
int c; Programın Çıktısı:
c=a; fonksiyon calısmadan onceki durum----a:10 b:20
a=b; fonksiyon calıstiktan sonraki durum-----a:10 b:20
b=c;
}
main(){
int i=10,j=20;
printf("\nfonksiyon calısmadan onceki durum----a:%d b:%d\n",i,j);
yer_degistir(i, j);//fonksiyon değerle çağırımı…..
printf("\nfonksiyon calıstiktan sonraki durum----a:%d b:%d\n",i,j);
}

16
İŞARETÇİLERİN FONKSİYONLARDA
KULLANIMI-Örnek-devam:
Açıklama:
Değerle Çağır yönteminde, çağıran
fonksiyondan gönderilen değerler, çağırılan
fonksiyondaki parametrelere kopyalanır.
Çağırılan fonksiyondaki kopyaların
değiştirilmesi çağıran fonksiyondaki orijinal
değerleri etkilemez.

17
İŞARETÇİLERİN FONKSİYONLARDA
KULLANIMI
• Fonksiyonların parametre gönderim
yöntemlerinden ikinci yöntem; “değerle
bağlantılı çağır (call by reference)” yöntemidir.
• Bu yöntem C dilinde işaretçilerin (pointer)
kullanılması ile gerçekleştirilebilir. Fonksiyona
gönderilen parametrelerin fonksiyon içinde
değerlerinin değişmesi isteniyor ise “değerle
bağlantılı çağır (call by reference)”
yönteminin kullanılması gerekir.

18
İŞARETÇİLERİN FONKSİYONLARDA
KULLANIMI
• Değerle çağır yöntemi fonksiyondan sadece
tek bir değer döndürülebilir.
• Bazı durumlarda fonksiyonların birden fazla
değer üretmeleri gerekir ki böyle bir durumda
değerle çağırılan ve bir tek değer döndüren
fonksiyonlar yetersiz kalır.

19
İŞARETÇİLERİN FONKSİYONLARDA
KULLANIMI
• Böyle durumlarda fonksiyonlara değer(veri)
göndermek amacıyla kullanılan
parametrelerin, çıktı parametresi olarak
kullanılması gerekir. Böylece bir fonksiyonun
ürettiği birden fazla değerin çağıran
fonksiyona göndermeleri sağlanır.
• Bu gibi durumlar ancak işaretçiler(pointer) ile
çözümlenebilir.

20
İŞARETÇİLERİN FONKSİYONLARDA
KULLANIMI
Bir fonksiyonun, onu çağıran fonksiyona
birden fazla değer döndürmesi gerektiğinde
işaretçilerden (pointer) yararlanılır.
Aşağıda, birden fazla değer döndüren ve bu
özellikteki fonksiyonlar için işaretçilerin
kullanımı örneklendirilmektedir.

21
Örnek-3
#include<stdio.h>
#include<conio.h>
//bu fonksiyon parametrelere gönderilen iki sayının yerlerini değiştirmekte ve
// yerleri değişmiş iki değer yeni şekli ile çağıran programa gönderilmektedir…
int yer_degistir(int *a,int *b) {
int c;
c=*a; Programın Çıktısı:
*a=*b; fonksiyon calismadan onceki durum----a:10 b:20
*b=c; fonksiyon calistiktan sonraki durum----a:20 b:10
}
main(){
int i=10,j=20;
printf("\n fonksiyon calısmadan onceki durum---a:%d b:%d\n",i,j);
yer_degistir(&i,&j);//değerle bağlantılı fonksiyon çağırımı…..
printf("\n fonksiyon calistiktan sonraki durum---a:%d b:%d\n",i,j);
getch();}

22
Örnek-4
#include<stdio.h>
#include<conio.h>
#include <math.h>
/*Bu fonksiyon parametresine ondalıklı olarak gelen bir sayıyı tam, ondalıklı ve
işaretine(+/-) ayrıştırarak bu 3 değeri çağıran programa yolluyor…*/
void ayir(double sayi,char *isaret,int *tam,double *ondalik){
double pozitifdeger;
if(sayi>0) *isaret='+';
else if(sayi<0)*isaret='-';
else *isaret=' ';
pozitifdeger=fabs(sayi);//sayinin mutlak değeri
*tam=floor(pozitifdeger);//ondalik değerin tam kısmı alınıyor.
*ondalik=pozitifdeger- *tam;
}

23
Örnek-4-devam
main(){
double sayi,ondalik;
char isaret;
int tam;
printf("\n\n Bir ondalik sayi giriniz");
scanf("%lf",&sayi);
ayir(sayi,&isaret,&tam,&ondalik); //değerle bağlantılı fonksiyon çağırımı…..
printf("\n*** %.4lf Sayisinin ANALIZI***\n",sayi);
printf("\nSayinin ISARETI :%c\n",isaret);
printf("\nSayinin TAM KISMI : %d\n",tam);
printf("\nSayinin ONDALIKLI KISMI : %.4lf\n",ondalik);
printf("\nBitirmek için Bir tuşa basiniz.....");
getch();}

24
Örnek-5
#include<stdio.h>
#include<conio.h>
//Bu fonksiyon toplam ve fark olmak üzere 2 sonuç bulup gönderiyor….
void topla_cikar(int a,int b, long *t,long *c)
{
//toplam ve fark sonuçları *t ve *c işaretçileri aracılığı ile gönderiliyor…
*t=a+b;
*c=a-b;
}
main(){
int i=10,j=20;long k,l;
topla_cikar(i,j,&k,&l); //değerle bağlantılı fonksiyon çağırımı…..
printf("\n%d + %d=%ld \n\n",i,j,k);
printf("\n%d - %d=%ld \n\n",i,j,l);
getch();
}

25
Örnek-6
#include<stdio.h>
#include<conio.h>
void say(int xx[],int n,int *ps,int *ns, int *ss)
{ int i; *ps=0;*ns=0;*ss=0;
for(i=0;i<n;i++){
printf("\n%d",xx[i]);
if (xx[i]<0) *ns=*ns+1;
else if(xx[i]>0) *ps=*ps+1;
else *ss=*ss+1;
}
}

26
Örnek-6-devam
main(){
int x[5],j;
for(j=0;j<5;j++)
{printf("%d. sayiyi giriniz",j+1);
scanf("%d",&x[j]);}
int a=0,b=0,c=0;
say(x,5,&a,&b,&c); //değerle bağlantılı fonksiyon çağırımı…..
printf("\nPozitiflerin sayisi:%d",a);
printf("\nNegatiflerin sayisi:%d",b);
printf("\nSifirlarin sayisi:%d",c);
int y[]={-1,-2,-3,4,0,12,11,-12,-15};
say(y,9,&a,&b,&c); //değerle bağlantılı fonksiyon çağırımı…..
printf("\nPozitiflerin sayisi:%d",a);
printf("\nNegatiflerin sayisi:%d",b);
printf("\nSifirlarin sayisi:%d",c);
getch();}

27
İşaretçi Tipindeki Fonksiyonlar
Bir fonksiyon tanımlanırken, parametreleri
işaretçi(pointer) olabileceği gibi, dönüş tipi de
işaretçi (pointer) olabilir. Bu, o fonksiyonun
kendisini çağırana bir adres göndereceği
anlamına gelir. Bu tip uygulamalar özellikle
string uygulamalarında sık kullanılır.

28
Örnek-7
main(){
int a,b,*p;
a = 2;
b = 4;
p = topla(a,b);
printf("Toplam : %d ---adresi %p \n",*p,p);
}

29
Örnek7-devam
int *topla(int x,int y)
{
int *ptr,toplam;
toplam = x+y;
ptr = &toplam;
return ptr;
}

30
İşaretçi tipi döndüren fonksiyonlar
Örnek-8
#include<stdio.h>
#include<conio.h>
//int bir sayının pozitif/negatif olduğunu bulan bir fonksiyon…
char *bul(int a){
char *b;
if (a<0) b="negatif";
else if(a>0) b="pozitif";else b="sıfır";
return b;}
int oku(){
int sayi;
printf("\nBir sayı giriniz");
scanf("%d",&sayi);
return sayi;}
main(){
int a;
for(int i=1;i<=5;i++){
a=oku();
printf("\n %d sayisi %s dir",a,bul(a));
getch(); }}

31
İŞARETÇİ ARİTMETİĞİ VE DİZİLER
İşaretçi değişkenler üzerinde + veya –
operatörler uygulanarak bellekte tutulan farklı
adreslere gidilebilir. Böylece o adreslerde
bulunan değerlere erişilebilir.
İşaretçi değişken belli bir bellek adresine işaret
ettiğinde;
+ işlemi uygulanması sonraki adrese,
-: işlemi uygulanması önceki adrese ilerlemeyi
sağlar.
32
İŞARETÇİ ARİTMETİĞİ VE DİZİLER
Örnek-9
#include<stdio.h>
main(){
float dizi[]={10.1,20.2,30.3,40.4,50.5};
float *p;
p=dizi;
printf("\n ilk deger:%.1f",*p);
p++;
printf("\n p++ isleminden sonra deger:%.1f",*p);
p=p+2;
printf("\n p=p+2 isleminden sonra deger:%.1f",*p);
p--;
printf("\n p-- isleminden sonra deger:%.1f",*p);
p=p-2;
printf("\n p=p-2 isleminden sonra deger:%.1f",*p);
for(p=dizi;p<&dizi[5];p++)
printf("\n\n dongu isleminde deger:%.1f",*p);
}

33
DİZİLER VE İŞARETÇİLER
ARASINDAKİ İLİŞKİ
• C dilinde işaretçiler ve diziler arasında yakın bir ilişki
vardır. Bir dizinin adı, dizinin ilk elemanının adresini
saklayan bir işaretçidir. Bu nedenle, bir dizinin
herhangi bir elemanına işaretçi ile de erişilebilir.
Örneğin:
int kutle[5], *p, *q;
şeklinde bir bildirim yapılsın. Buna göre aşağıda yapılan
atamalar geçerlidir:
p = &kutle[0]; /* birinci elemanın adresi p işaretçisine atandı */
p = kutle; /* birinci elemanın adresi p işaretçisine atandı */
Yukarıdaki iki satırdaki atamalar aynı anlamdadır.
q = &kutle[4]; /* 4. elemanın adresi q işaretçisine atandı */
34
DİZİLER VE İŞARETÇİLER
ARASINDAKİ İLİŞKİ
Dizi adı bir işaretçi olduğu için, doğrudan aynı
tipteki bir işaretçiye atanabilir.
p = kutle; /* birinci elemanın adresi p işaretçisine atandı */
Ayrıca, i bir tamsayı olmak üzere,
kutle[i]; ile *(p+i);
aynı anlamdadır.
Bunun sebebi, p işaretçisi kutle dizisinin başlangıç
adresini tutmuş olmasıdır.
p+i işlemi ile (i+1). elemanın adresi, ve *(p+i) ile
de bu adresteki değere erişilebilir.

35
DİZİLER VE İŞARETÇİLER
ARASINDAKİ İLİŞKİ
NOT: Bir dizinin, i. elemanına erişmek için
*(p+i) işlemi yapılması zorunludur.
Yani;
*p+i; /* p nin gösterdiği değere (dizinin ilk
elemanına) i sayısını ekle */
*(p+i); /* p nin gösterdiği adresten i blok ötedeki
sayıyı hesapla */
anlamındadır. Çünkü, * operatörü +
operatörüne göre işlem önceliğine sahiptir.

36
DİZİLER VE İŞARETÇİLER
ARASINDAKİ İLİŞKİ-Örnek-10
/* işaretçi ile dizi ilişkisi */
#include <stdio.h>
#include <conio.h>
double ortalama(double dizi[], int n);
int main()
{
double a[5] = {1.1, 2.2, 3.3, 4.4, 5.5};
double ort;
ort = ortalama(a,5);
printf("Dizinin ortalamasi = %lf\n",ort);
getch();
return 0;
}

37
DİZİLER VE İŞARETÇİLER
ARASINDAKİ İLİŞKİ-Örnek 10-devam
double ortalama(double dizi[], int n) /*yandaki fonksiyonun 2. sürümü*/
{ double ortalama(double dizi[], int n)
double *p, t=0.0; { double *p, t=0.0;
int i; for(p=dizi; p < &dizi[n]; p++)
t += *p;
p = dizi; // veya p = &dizi[0] return (t/n); }
for(i=0; i<n; i++)
t += *(p+i);
return (t/n);
}

38
DİNAMİK BELLEK KULLANIMI
• Programın çalışması sırasında özel komutlar
kullanarak bellekten yer alınıp kullanılmasına
dinamik bellek kullanımı denir.
• Dinamik değişkenler için bellekte ayrılan yere
yığın (heap) denir.

39
DİNAMİK DİZİLER
VE İŞARETÇİLER
Statik bir dizi, programın başında sabit boyutlu olarak
tanımlanan dizidir. Statik dizinin kaç elemanlı olduğu
programın başında bildirilmektedir.
Statik bir dizinin tanımlanması ile derleyici o dizi için gerekli
bellek alanını program sonlandırılıncaya kadar saklı tutar. O
bellek alanı başka amaçlar için kullanılmaz.
Dizilerde dinamik çalışma, programın çalıştırılması
sırasında gerekli bellek alanının işletim sisteminden
istenmesi ve işi bittiğinde bu alanın geri verilmesidir. Bu
amaçla standart kütüphanede malloc(), calloc(), realloc()
ve free() fonksiyonları kullanılır.
Bu şekilde dizileri kullanmak için:

40
DİNAMİK DİZİLER
VE İŞARETÇİLER
...
tip *ptr;
...
ptr = malloc(50); /* herbiri 8 bit olan 50 elemanlık
yer isteniyor */ . . /*
/*kullanılıyor */ .
free(ptr); /* geri veriliyor */
...
41
Örnek-11: Dinamik Dizi Kullanımı
#include <stdio.h>
#include <stdlib.h>
main(){
int *x,i,n,toplam=0;
float ortalama;
printf("Eleman sayisi?: ");
scanf("%d",&n);
x = (int *) malloc(n*sizeof(int));// n elemanlı dizi x
/* n tane int gözü isteniyor (Nx4 byte) */
printf("%d adet sayi giriniz\n ",n);
for(i=0;i<n;i++){
printf("%d.eleman = ",i+1);
scanf("%d",&x[i]); /* x[i] ile *(x+i) aynı anlamda !... */
toplam += x[i];
}

free(x); /* ayrılan yer boşaltılıyor... */


ortalama = (float) toplam/n;
printf("Bu %d sayinin ortalamasi %f dir\n",n,ortalama);
}

42

You might also like