Pointer

Tanımlanması ve Kullanımı

Bir veri bloğunun bellekte bulunduğu adresi içeren (gösteren) veri tipidir. Tanımlama biçimi:

veri tipi *p;

p değişkeni ile belirtilen tipte bir verinin bellekte saklandığı adresi içerir.

int *iptr;
float *fptr;

Bu kadar tanımla sonucunda bellekte p değişkeni mevcuttur. Ancak işaret ettiği veri bloğu yoktur. Bunun için iki yol vardır. Birincisi kullanılan herhangi bir değişkeni işaret etmek, ikincisi ise veri bloğunu boş belleği kullanarak oluşturmak.

İşaretçi değişkenin var olan bir değişkenin bulunduğu adresi göstermesi.

Bu işlemi yapabilmek için var olan değişkenin adresinin bilinmesi gerekmektedir.

& işleci : Bir değişkenin adresinin belirlenmesi için kullanılır. Kullanım biçimi:

&değişken

&i : i değişkenin adresini verir.

main()
{
int i;
int *iptr;
i = 5;
iptr = &i;
clrscr();
printf("i değişkeninin adresi %p\n", &i);
printf("iptr değişkeninin değeri %p\n", iptr);
}

Bellek modeline göre SSSS:OOOO veya OOOO biçiminde adres yazar.

8FF8:1000


Veri bloğunu boş belleği kullanarak oluşturmak.

Bu yolla veriler için dinamik yer ayırılır. Bunun için malloc işlevi kullanılır
void *malloc(n) : Boş bellekten n byte yer ayırıp başlangıç adresini döndürür.
iptr = (*int) malloc(2);
!!!!!!!!! Daha sonra dönüş yapılacak. sizeof, cast işleci (*tip) ...

Veriye işaretçi değişken yoluyla erişim

Bir işaretçinin gösterdiği adresteki veriye erişmek için işaretçi değişkeninin önüne * karakteri konur.
main()
{
int i;
int *iptr;
iptr = &i;
*iptr = 8;
printf("i değişkeninin değeri %d\n", i);
printf("iptr adresinin içeriği %d\n", *iptr);

}

Ekranda çıktı :
i değişkeninin değeri 8
iptr adresinin içeriği 8

!!! İşaretçi değişkenin gösterdiği adresin içeriği değişken ilklendirmeden kullanılmamalıdır

İşaretçi Aritmetiği

İşaretçi değişkenler üzerinde toplama ve çıkartma işlemleri (++, --) geçerlidir. Ancak eklenecek değer tamsayı olmalıdır.
İşaretçi değişkenin değeri 1 arttırıldığı zaman değişken bir sonraki veri bloğunu işsaret eder. Değişkenin alacağı yeni değer işaretçi değişkenin ne tip bir veri bloğunu işaret ettiğine bağlıdır.

int *iptr, i;
...
iptr = &i; i değişkenin adresinin 1000 olduğunu varsayalım. iptr nin değeri 1000 dir.
iptr++; iptr nin değeri 1002 olur. ( int değeri işaret ettiği için)


aynı örneği double için yaparsak
double *iptr, i;
...
iptr = &i; i değişkenin adresinin 1000 olduğunu varsayalım. iptr nin değeri 1000 dir.
iptr++; iptr nin değeri 1008 olur. ( double değeri işaret ettiği için)


int *iptr, i, j;
...
iptr = &i; i değişkenin adresinin 1000 olduğunu varsayalım. iptr nin değeri 1000 dir.
*(iptr+4)=2; 1008 adresinin içeriğini 2 yapar.


!!! Arttırma işaret edilen veri bloğuna göre yapılır Yani bir sonraki veri bloğunun gösterilmesi sağlanır.


iptr++ ; bir sonraki veri bloğunu göster
(*iptr)++; iptr değişkeninin gösterdiği adresteki değeri 1 arttır


İşaretçiler ve Diziler

İşarteçiler üzerinde geçerli aritmetik yardımıyla dizilere işaretçi değişkenler ile erişmek mümkündür.

#include
main()
{
int i[10], j;
int *iptr;

for (j=0; j<10; j++)
i[j]=j;

/* Dizinin başlangıç adresine erişmek için ilk elemanın adresi kullanılabilir &i[0] veya doğrudan */

iptr = i;

clrscr();

for (j=0; j<10; j++) {
printf("%d ", *iptr);
iptr++;
}
printf("\n");
/* iptr artık dizinin başını göstermez */

iptr = i;
for (j=0; j<10; j++)
printf("%d ", *(iptr+j));

printf("\n");
/* iptr hala dizinin başını gösterir */
getch();
}


Örnek: İşaretçi ve dizgi kullanımı.
#include
main()
{
char *a="1234567890";
char b[11];
char *p1, *p2;

printf("%s\n", a);
p1 = a;
p2 = b;
while (*p1 != '\0') {
*p2 = *p1;
p1++;
p2++;
}
printf("%s\n", b);
}

İşlevleri Referans Yoluyla Çağırma

Şu ana yazdığımız işlevlerde gönderilen parametrelerin (diziler hariç) değerlerinin değiştirilmesi mümkün değil idi. İşlev çağırıldığı zaman parametrelerin bir kopyası çıkartılıp işleve gönderiliyordu. Bir işlevin birden fazla değer gönderebilmesi için işaretçilere gereksinimiz vardır.


void arttir(int);
main()
{
int i;
i = 5;
printf("öncesi %d\n", i);
arttir(i);
printf("sonrası %d\n", i);
getch();
}
void arttir(int k)
{
k++;
}

Çıktı :
öncesi 5
sonrası 5


Gönderilen parametrenin kopyası işleve gönderildiği için işlev içerisinde yapılan değişiklikler işlevin çağırıldığı yeri etkilemez. Eğer parametredeki değişikliklerin işlevin çağırıldığı yerde de geçerli olmasını istiyorsak işleve parametrenin adresini göndermek gerekir.

void arttir(int*);
main()
{
int i;
i = 5;
printf("öncesi %d\n", i);
arttir(&i);
printf("sonrası %d\n", i);
getch();
}
void arttir(int *k)
{
(*k)++;
}

öncesi 5
sonrası 6


Örnek : Sayısal dizgiyi tamsayıya dönüştüren işlevde iyileştirme. Geçersiz karakterin konumu da verilsin.
int deger(char *s, int *konum)
konum = -1 ise tüm karakterler rakam
>=0 ise geçersiz karakterin konumu


Örnek : Sıraya dizme. Yer değişikliği işlevde ve parametrelere referans yolu ile erişim.

#include
#include

#define N 20
void degistir (int *, int *);

main()
{
int s[N];
int i, k;

clrscr();

for (i=0; i s[i] = rand() % 100;
printf("%4d",s[i]);
}
printf("\n");
k=1;
do {
k=0;
for (i=0; i if (s[i] > s[i+1]) {
degistir (&s[i], &s[i+1]);
k = 1;
}
} while (k);

for (i=0; i printf("%4d",s[i]);
printf("\n");
getch();
}

void degistir (int *a, int *b)
{
int gec;
gec = *a;
*a = *b;
*b = gec;
}

!!! Dizilerde işaretçi olduğu için a değişkeni bir dizi(veya işaretçi ise)
a[i] ile *(a+i) ifadeleri aynı anlamı taşır.


Örnek : İşleve gönderilen dizinin işlev içerisinde işaretçi olarak kullanımı.

#include
#include

#define N 5

float ort (int *);

main()
{
int s[N];
int i, k;

clrscr();
for (i=0; i s[i] = rand() % 100;
printf("%4d",s[i]);
}
printf("\n");
getch();
}

float ort (int *a)
{
int i;
float t = 0;

for (i=0; i t = t + *(a+i);

return t/N;
}

Örnek : işleve gönderilen işaretçinin işlev içerisinde dizi olarak kullanımı .

void malloc(n): En az n byte uzunluğunda bellekten yer ayırır. İşlevin değeri
>0 ise bloğun bellekteki yeri, NULL yer yok demektir.

int *i;
i = (int *) malloc(2000) ; 2000 byte yer ayırıp bloğun başlangıç adresini i 'ye atar
( 1000 elemanlı int dizisi )
double *x;
x = (double *) malloc(8*2000); 2000 elemanlı double dizi

sizeof(n) : n ifadesinin/tipinin byte olarak uzunluğunu verir.
i = (int *) malloc(1000*sizeof(int)) ; 1000 tane int değer içerecek bellek uzunluğu

x = (double *) malloc(2000*sizeof(double)); 2000 elemanlı double dizi

void free (void *block) : mallock işlevivi tersi. Block değişkenin tuttuğu yeri boş belleğe gönderir

0 yorum: