Tek İleti Göster
Eski 04.06.2007   #1 (permalink)
staticiation
 
Katılma Tarihi: Şub 2006
Nereden: Bursa/es-es
Yaş: 23
Mesajlar: 1,780
Varsayılan C de Pointerlar(İşaretçiler)anlatım+örnek...

Pointers(işaretçiler)

Sıra geldi pointerlara, C de ki en onemli konuya… Bu pointerları da iyice oğrenirsek artık C de onumuz acık demektir.Peki nedir bu pointer denen şey? Türkçe anlamı işaretçi demektir. Yani bunlar bir şeyleri işaret ederler.
Ama pointerların esas olayı RAMdeki byte'ların adreslerini tutan değişkenler olmalarıdır. Yani pointerlar da integer, double yada char gibi bir değişken turudur fakat sadece memory adresi tutarlar ve diğer degisken turlerinden farklı olarak baska bir degiskeni isaret edebilirler.Peki memory adresi dediğimiz şey nedir ve işaret etmekden kastımız ne ? Diye soranların sesini duyar gibiyim İlk önce RAMi inceleyelim biraz. RAM bilgisayarın işlemlerini yurutebilmesi icin bazı bilgileri geçici olarak kaydettigi bir cesit hard disktir. RAM byte'lardan oluşur mesela benim RAM im 256 mega byte. bu da (1MB = 1024 Kilo byte ve 1Kb = 1024 byte dersek) 268435456 byte oluyor sanırım. RAM adresi bu bytelarla
belirleniyor. 100000 diye bir RAM adresi, RAM deki 100000 inci byte demek oluyor. Bu byte dedigimiz şey de bit lerden oluşuyor.8 tane bit ten oluşan bir bloka byte demişler. bit dediğimiz şey de bilgisayar dunyasındaki o meşhur 0 ve 1 lerin kaydedildigi yerlerdir. Yani bir bit de sadece doğru yada yanlış bilgisi tutulabilir yani 0 yada 1 ... demek ki bir byte 8 tane 0 yada 1 den olusuyor ornek:

00001101 bir byte dir...
Bu 0 ve 1 lerin bilgisayarımıza taktığımız ve RAM dedigimiz o kartuşlarda nasıl olustugunu merak ediyorsanız onuda soliyim. RAM in icindeki binlerce kucuk elektronik switch lerle olusuyor. Bu switch ler acık yada kapalı
hale getirilerek 0 yada 1 i temsil ediyorlar. Elektronik dilinde bu switchlerin acık yada kapalı olmasını temsil
eden şey de aletteki pinlerin ucunda voltaj olması ya da olmamasıdır. Bunu da bir ek bilgi olarak soylemiş olalım

RAM i şu şekilde hayal edelim:

.
.
.
00110010 ----> 124561 inci byte
01110011 ----> 124562 inci byte
10110010 ----> 124563 inci byte
00001011 ----> 124564 inci byte
00011101 ----> 124565 inci byte
10010011 ----> 124566 inci byte
00001111 ----> 124567 inci byte
00100101 ----> 124568 inci byte
.
.
.
124561 inci byte RAM deki adres oluyor. karşısındaki 0 ve 1 ler de o adreste bulunan byte daki bilgilerdir. biz yazdıgımız programda

int x;
x=5;
yazdıgımızda x değişkeninde bir bilgi tutulabilmesi icin RAM de bir adres ayrılır ve o adrese 0 ve 1 ler kullanılarak x=5 bilgisi kaydedilir. Bu kadar genel bilgiden sonra pointer tanıtma ve kullanmayı kodlarla anlatalım artık...
pointerlar işaret edecekleri degiskenin turune gore tanıtılırlar,bir integer a pointer atamak istiyorsak pointerımızı şu şekilde belirleyecez:

int *p;
normal integer tanıtır gibi.. fakat tanıtacagımız degiskenin basına bir * işareti koyunca o degişken pointer oluyor. Yukardaki komuttan sonra artık bir pointer degişkenimiz var. Unutulmaması gereken bir nokta da pointerın da bir degişken oldugudur. Simdi bu pointerla neler yapabilecegimize ve nasıl kullanıldıgına bakalım.


int *p;
int x;
x=5;
p=&x;

yukardaki kodlarla once bir integer pointerı belirledik. Sonra x adında bir integer değişkeni belirledik ve ardından bu degiskenin degerini 5 yaptık. Son satırda da pointerın x e işaret etmesini sağladık. Bunu & sembolu ile yaptık. & işareti şu anlama geliyor: " ...nın adresi" yani &x, "x in adresi" anlamına geliyor. Son satırdan sonra p nin degeri x in memory adresine eşitlendi. Mesela x degiskeninin tasıdıgı degeri aklında tutmak icin bilgisayar 156789 uncu byte a 0 ve 1 lerle 5 degerini kaydetti. Artık p nin degeri 156789 oldu.

main()
{
int *p;
int x;
x=5;
p=&x;
printf("%d\n",x);
printf("%d\n",p);

}


yukardaki kodu yazıp calıstırırsanız, programın x in degeri olarak 5 i ve x in tutuldugu memory adresini yani p nin degerini verdigini goreceksiniz. p nin alacagı deger her bilgisayarda farklı olacaktır. Cunku x degiskeni RAM deki ilk bos yere yazılacaktır ve bu bilgisayarın calısma durumuna ve RAM in kapasitesine gore degisir.
Bir degiskene pointer atadıktan sonra o pointerı kullanarak degiskene istedigimis degisikligi yapabiliriz. p, isaret ettigi degiskenin adresini ifade ederken, *p, degiskenin degerini ifade eder. yukardaki kodlarda
printf("%d\n",p); komutunu
printf("%d\n",*p); seklinde degistirirsek x degiskeninin
adresi yerine degerinin yani gene 5 in ekrana verildigini goreceksiniz.

Aynı sekilde x in degerini de degistirebiliriz.

*p=6;

yazdıktan sonra x in degeri artık 6 olur.Yani *p ifadesi p pointerının işaret ettigi degişken anlamına geliyor ve x yerine istedigimiz zaman *p ifadesini kullanabiliyoruz. Bu noktaya kadar pointerların ne oldugu ve ne ise yaradıklarını ogrendik. Peki nedir bu pointerları bu kadar onemli yapan, nedir bu pointerların marifetleri ? Gelelim pointerların marifetlerine ve C deki kullanım alanlarına...
C de tanıttıgımız her şey, degisken, array, fonksiyon... her şey RAM e yazılır Dolayısıyla RAM e yazılan her şeye RAM adresini taşıyan bir pointer atanabilir. Yani pointer C de her programda, her algoritmada kullanılabilir.Baslıcalarına deinelim.

Pointerlarla arrayler:

int A[5]

diye bir satırla tanıttıgımız A arrayine beş tane integer(tam sayı) tasıyabilecek sekilde RAM de yer ayrılır. Program bir integerı aklında tutabilmesi icin 2 yada 4 byte yer ayırır hafızada Dielimki bizim compilerımız 4 byte yer ayırıyor bir integer icin. A arrayine yer acılması icin 5 * 4= 20 byte lık alan hafızada ayrıldı. Diyelimki RAM de ilk bos byte 123456 ıncı byte olsun. Bu byte dan baslayarak arrayın elemanları icin 20 bytelık yer ayrılacak. Şu şekilde:

________ 123456 ıncı byte A[0]
________
________
________
________ 123460 ıncı byte A[1]
________
________
________
________ 123464 uncu byte A[2]
________
________
________
________ 123468 ıncı byte A[3]
________
________
________
________ 123472 ıncı byte A[4]
________
________
________

Yukardaki sekilde "________" diye gosterilen yerler RAM deki bir byte ı temsil ediyor. A[0] icin 4 tane byte ayrılmıs. 123456, 123457, 123458 ve 123459 uncu byte lar... Ama A[0] in RAM adresi kendisine ayrılan ilk byte olan 123456 dır. Bu aynı zamanda A arrayinin ilk elemanının adresi oldugu icin A arrayinin de adresi oluyor. A arrayine bir pointer atamak istersek yapmamız gereken mesela p diye bir integer pointer ı belirledikten sonra p=A satırını yazmak. A zaten A[5] arrayının ilk elemanının pointerı oluyor otomatik olarak. Simdi bu yazdıklarımızı kodlara dokerek acıklayalım:


#incluıde<stdio.h>
main()
{
int *p;
int A[5];
A[0]=10;
printf("%d\n",A);
printf("%d\n",A[0]);
printf("%d\n",*A);
p=A;
printf("%d\n",p);
printf("%d\n",*p);
}


Bu programı calıstırırsak şu sekilde bir cıktı verecektir: (A arrayının adresinin 123456 oldugunu kabul ediyorum)
123456 ---->A
10 ---->A[0]
10 ---->*A
123456 ---->p
10 ---->*p

goruldugu gibi A , A[5] arrayinin adresi olan 123456 degerini veriyor. Cunku A nın kendisi bir pointer. A[0] , arrayin ilk elemenı ve 10 a esitlenmisti. *A , A pointerının işaret ettigi degiskenin degerini verecek. Bu da arrayin ilk elemanına işaret ediyor ve 10 degerini ekrana veriyor.p pointrerı, A ya esitlendigi icin boylece arrayın adresini tasımıs oluyor ve ekrana 123456 veriliyor.*p, 123456 adresindeki degiskenin degerini verecegine gore *p icin ekrana 10 veriliyor... ( yukarda bahsedilen 123456 degeri sizin bilgisayarınızdaki ilk bosalan RAM adresine gore degisecektir.)

Bir arrayin adının o arrayin pointerı oldugunu ogrendik. Bunu kullanarak (*A seklinde) arrayin ilk elemanına ulasmayı da ogrendik. Peki arrayin diger elemanlarına nasıl ulaşacaz ? Diyelim ki p diye bir integer pointerı belirledik ve p=A dedik. p yi kullanarak A[1] e yani arrayin ikinci elemanına nasıl ulasabiliriz ?

p++;

yazarsak p nin degeri bir artırılacak. p nin degeri ornegimizde 123456 idi. Yeni degeri 123457 mi olacak ? Hayır C, bunun bir array pointerı oldugunu bilecek ve bir sonraki array elemanına denk gelecek sekilde p nin degerini
artıracak. Bizim ornegimizde integer arrayı kullandık ve her integer icin 4 byte ayrılmıstı. C, bunu bildigi icin p nin degerini 4 artıracak.

p++;

komutundan sonra p nin degeri 123460 olacak. Bundan sonra *p yazarsak bu ifade 123460 adresinde bulunan degiskenin degerine esit olacak. yani A[1] e... mesela p yi kullanarak A[1] e bir deger atamak istersek:

p=A
p++;
*p=11;

bu komutlarla A[1] in degeri 11 olacak...
Peki bu arraylerin elemanlarını neden pointer kullanarak deistirelimki ? Neden işimizi uzatalımki ? Direk A[1]=11 yazsak daha kolay olur deilmi
Simdi bunu neden ogrendigimizi gosteriyim...
Fonksiyonları işlemiştik. Mesela

int topla(int a,int b);

seklindfe tanıtılan bir fonksiyon girdi olarak iki tane tam sayı alıyor ve bunların toplamını veriyor diyelim.
Fonksiyona bu sekilde tamsayı girdisi yada cıktısı almak kolay. Peki fonksiyonumun bir array almasını yada bir array vermesini istersek bunu nasıl yapacaz ? Ponter kullanarak

int topla(int *t,int n);

seklinde bir fonksiyon tanıtalım. Burda *t bir array pointerı olsun, n de arrayın uzunlugu...
Bu fonksiyon, arrayin elemanlarını toplasın ve sonucu versin:

int topla(int *t, int n) //1.satır
{ //2.satır
int i; //3.satır
int toplam = 0; //4.satır
for(i=0; i<n; i++) //5.satır
{ //6.satır
toplam=*t + toplam; //7.satır
t++; //8.satır
} //9.satır
return toplam; //10.satır
} //11.satır

Bu fonksiyonun yaptıgı işi satır satır anlatalım:
1.satırda fonksiyonumuzu yazdık, 2. satırda fonksiyonumuzun yaptıgı işi anlatacagımız { } isaretlerinin ilkini
actık.
3. satırda for dongusunde kullanacagımız degiskeni tanıttık. 4. satırda
arrayin elemanlarını toplayacagımız toplam degiskeninin tanıttık ve ilk degerini 0 a esitledik.
5. satırda for dongumuzu yazdık.dongumuz 0 dan baslayıp
arrayin uzunluguna kadar kendini tekrarlıycak. Mesela “int A[3]” diye tanımladığımı uzunluğu 3 olan bir arrayi
bu fonksiyona sokacaksak
fonksiyonu şu sekilde kullanacaz main in icinde :
topla(A,3)
burda t, A ya esitlenecek n de 3 e esitlenecek. for dongusu 3 kere donecek.
7.satır da dongu her seferinde toplam degiskenine *t nin degerini ekleyecek.
donguye ilk girildiginde *t arrayin ilk elemanının degeri olacak. Sonra 8. satırda t, bir sonraki elemana
isaret edecek. Donguye tekrar girildiginde bu sefer *t arrayin 2. elemanının degerine esit oloacak... bu sekilde
devam ederek toplam degiskenine arrayin her elemanı teker teker eklenecek. 10.satırda elde edilen toplam
fonksiyonun cıktısı olacak...

yukardaki kodları birlestirerek bir ornek program yazalım:

#include<stdio.h>
int topla(int *t, int n);
main()
{
int Q[5] = {2,4,6,8,10} ;
int x;
x=topla(Q,5);
printf("%d",x);
return 0;
}

int topla(int *t, int n)
{
int i;
int toplam = 0;
for(i=0; i<n; i++)
{
toplam=*t + toplam;
t++;
}
return toplam;
}



Bu programı calıstırırsanız ekrana 2 4 6 8 ve 10 un toplamını verecektir, sanırım 30 ediyor son olarak pointerın pointerı diye bir şey var onu anlatalım:
Pointer da bir degişken olduguna gore ve bilgisayarın pointerın adresini aklında tutabilmek icin onu da RAM de bir yere yazdıgına gore, bir pointer a da işaret eden bir pointer belirlenebilir.Yani pointerın pointerı… kafalar biraz daha karısacak

int **a;
int *b;
int c;
c=3;
b=&c;
a=&b;

yukardaki kodlarda b pointerı c integerına isaret ediyor, a pointer pointerı da b pointerına isaret ediyor.

a --> b --> c
seklinde...

c nin degeri 3, b nin degeri c nin memory adresi, a nın degeri de b nin memory adresi oluyor.
c degiskeni degeri : 3 , RAM adresi : 123456
b degiskeni degeri : 123456 , RAM adresi : 123460
a degiskeni degeri : 123460 , RAM adresi : 123464

seklinde bir RAM adresleri ve degisken degerleri tablosu oluşacaktır. RAM adreslerini kafadan attım tabiki...

printf("%d",a) ----> 123460 ı verir
printf("%d",*a) ----> 123456 yı verir
printf("%d",**a) ----> 5 i verir

pointerın pointerı iki boyutlu arraylerde kullanılabilir... A[2][3] gibi... Ama bukadar ayrıntıya girip anlatamıycam yoksa yazının sonu gelmez Benden size ana hatları ile pointerlar... Ayrıntıları ogrenmek size kalmıs... Kafanıza takılan ayrıntılar, ogrenmek istediginiz şeyler yada anlamadıgınız noktalar olursa sorun forumda
Buraya kadar kafa karıstırabilecek bir iki şeyden bahsediyim.

Birincisi matemetiksel işlemlerde *p seklinde kullanılan bir pointer carpma işlemi olan
* isareti ile karışmaz merak etmeyin. mesela a * *b; seklinde bir ifade a carpı b pointerının işaret ettigi deger anlamına gelir.C, * leri birbirinden ayırmasını bilir merak etmeyin
İkincisi pointerı tanıtırken kullanılan * ile pointerın işaret ettigi degiskenin degeri anlamına gelen * sempolunu birbirine karıştırmamak gerekir. Gene C buınları karıstırmaz ama siz karıstırabilirsiniz
mesela bir fonksiyonu tanıtırken

fonksiyon(int *p);
yazıldıgında "int *p" kısmında kullanılan * isareti p nin bir integer pointerı oldugunu anlatır.
pointer tanıtma isaretidir.
Misal başka bir fonksiyon tanıtıldıktan ve implement edildikten sonra main in icinde kullanırken mesela:

fonksiyon(*p);

dersek, buradaki * işareti ise p pointerının işaret ettigi degişkenin degeri anlamına geliyor...
Pointerlar sadece intergerlar icin kullanılmaz tabiki... mesela char degiskenlerşi ve string ler icin de bir iki ornek yazalım:

char A[] = "radres";
seklinde bir string tanımlanınca A bu stringin ilk elemanına işaret eden bir pointerdır.
*A, r yi verir...
p=A;
p++;
yazdıktan sonra *p, a ya esittir.
yada

p=A;
*(p+3)='\0';

dersek
printf("%s",A);

bize “rad” ı verir. Cunku stringin 4. elemanının olan *(p+3) u stringin bitiş elemanı anmlamına gelen '\0' a
eşitledik. pointerlarla ilgili soyliyecegim son şey fonksiyonlarla degisken degerlerini degistirmektir. Daha onceki fonksiyonlar dersimizde scope olayından bahsetmistik. Scopu main olan bir degiskeni bir fonksiyona vererek degerini degistiremiyorduk. Pointer kullanarak bunu becerebiliriz.
Simdi iki ornek yazacam. Biri main de kullanılan bir degiskenin degerini degistiremeyen bir fonksiyon digeri ise pointer kullanarak degeri degistiren bir fonksiyon.

#include<stdio.h>
void degistir1(int a);
void degistir1(int a)
{
a=a+1;
}
void degistir2(int *a);
void degistir2(int *a)
{
*a=*a + 1;
}

main()
{
int x=5;
int *p;
p=&x;
degistir1(x);
printf("%d\",x);
degistir2(p);
printf("%d",x);
return 0;
}

bu programda mainde belirlenen x degiskeninin ilk degeri 5 e esitleniyor. ardından p diye bir integer pointerı belirlenip p=&x; satırı ile x i işaret etmesi saglanıyor. sonra degistir1 fonksiyonuna x veriiyor. printf komutu ile x in degerine bakılıyor. Program calıstırılırsa x in degerinin degistirilemedigi gorulecektir. Bunun sebebi fonksiyonlar dersinde anlatıldı. Sonra degistir2 fonksiyonuna x in pointerı olan p veriliyor. Ardından printf ile tekrar x in degerine bakılıyor. Program calısınca ekrana gelen ikinci degerin bu sefer degistirildigini ve x in yeni degerinin 6 oldugu gorulecektir.

Bunun sebebi degistir2 fonksiyonuna scope olayının etki etmemesidir. Degistir2 nin kodlarına bakarsanız aldıgı pointerın isaret ettigi degeri bir artırdıgını gorursunuz. Pointer direk olarak RAM deki “x” in adresine gidip orda depolanan degeri degistiriyor. Bu yuzden x in yeni degeri sorgulandıgında RAM de ki x in adresine gidip degeri okuyan bilgisayar degerin 6 oldugunu gorecek ve bize bu degeri verecektir.
Daha cok, bi suru anlatacagım şey var pointerlarla ilgili ama bir dokumanda bu kadar oluyor…
Bu temel pointer bilgisinden sonra siz program yaza yaza, C dokumanları okuya okuya pointerların marifetlerini
kendiniz anlayacaksınız. Bu sefer odev yok, anca kafanızı toparlarsınız bu yazıdan sonra
staticiation Şuanda Forumda Değil   Alıntı yaparak cevapla