Durumu:
Papatyam No :
1397
Üyelik T.:
20 January 2009
Arkadaşları:0
Cinsiyet:
Memleket:istanbul
Yaş:35
Mesaj:
131 Konular:
Beğenildi:
Beğendi:
Takdirleri:10
Takdir Et:
Konu Bu
Üyemize Aittir!
|
Ynt: C Dökümanları
Temel C Dokümanları 6 (Pointerlar[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);
return 0;
}
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.
DEVAMI ALTTA
__________________
Biz Bu Hallere Düşecek Adammıydık ???
|