İşaretciler - Pointer İçindekiler Giriş Pointer değişken tanımlama ve ilk değer atama Pointer üzerinde çalışan operatörler Fonksiyonları referasnla çağırma const ifadesi ve Pointer ler Pointer İfadeler ve Pointer Aritmetik Pointers ve Array arasındaki ilişkiler Pointer Dizileri Functionları adresleyen pointerlar
Pointer Giriş Göstergeler, başka değişkenlerin bellek adreslerini depolamaya yarayan değişkenlerdir. C nin çok önemli bir gücünü ve esnekliğini oluştururlar. Ancak aynı zamanda karmaşık ve zor kullanılan bir yapıdır. call-by-reference işlemlerini gerçekleştirirken kullanılırlar. Dizi ve string lerle yakın çalışma mantığı gösterirler
Pointer Değişken Tanımlama ve İlk Değer Atama Normal değişkenler özel bir adres değeri içerir. adet 7 Pointer değişkenler Değerin hafıza adresini içerirler padet adet 7 Erişim doğrudan değil adres referansı üzerinden yapılır
Pointer Değişken tanımlama ve ilk değer atama Pointer definitions * işareti ile tanımlanır. Bu dolayı tanım (indirection) oparatörü olarak isimlendirilir. örnek tipadı *ptradı; int *pdegisken; Yukarıdaki ifade int türünde değer saklanan bir pointer değişken tanımlanır. Bir satırda iki pointer tanımlamak her değişkenin yanına * eklenmelidir. int *myptr1, *myptr2; Herhangi bir veri türünde pointer tanımlanabilir. Pointerler ilk değer olarak 0, NULL, veya bir adres alabilir. 0 veya NULL hiç birşeye işaret etmez (NULL tercih edilir.)
Pointer Operatörleri & (adres operatör) Üzerinde çalıştığı değişken veya ifadenin adresini döndürür. int y = 5; int *yptr; yptr = &y; /* yptr, y değişkeninin adresini alır*/ yptr işaret eder y yptr y 5 yptr 500000 600000 y 600000 5 Y nin adresi yptr nin değeridir.
& operatörü başka bir örnek int x,y; int *ptr; x 1000 0 y 1002 0 ptr 1004 0 y=5 x 1000 0 y 1002 5 ptr 1004 0 ptr=&y; x 1000 0 y 1002 5 ptr 1004 1002
Pointer Operatörleri * (dolaylama/referanstan ayırma) Pointerin işaret ettiği değişkeni döndürür. *yptr ifadesi y yi döndürür. (çünkü yptr y yi işaret eder.) * atama için kullanılabilir. Returns alias to an object *yptr = 7; /* changes y to 7 */ * ile tanımlı işaretçi bir değişken olmalı. Sabit olmamalıdır. "&" adres operatörü, kendisinden sonra gelen ifadenin adresini gösterir. * ve & birbirinin tersi gibi çalışır. &*p : değişkenin adresini gösterir.
int ptr= 33; Adres değerlerinin gösterimi printf("icerik: %d\n", ptr); printf("adres : %p\n",& ptr);
Gösterici Aritmetiği Göstericiler kullanılırken, bazen göstericinin gösterdiği adres taban alınıp, o adresten önceki veya sonraki adreslere erişilmesi istenebilir. Bu durum, göstericiler üzerinde, aritmetik işlemcilerin kullanılmasını gerektirir. Göstericiler üzerinde yalnızca toplama (+), çıkarma (-), bir arttırma (++) ve bir eksiltme (--) operatörleri işlemleri yapılabilir.
Gösterici Aritmetiği Aşağıdaki gibi üç tane gösterici bildirilmiş olsun: char *kar; int *tam; double *ger; Bu göstericilerin herhangi bir anda, tuttukları adresler de sırasıyla 10000 (0x2710), 20000 (0x4e20) ve 30000 (0x7530) olsun. Buna göre aşağıdaki atama işlemlerinin sonucu: kar++; tam++; ger++; sırasıyla 10001 (0x2711), 20004 (0x4e24) ve 30008 (0x7538) olur. Göstericiye 1 eklemek göstericinin bir sonraki adresi göstermesine sebep olur. http://www1.gantep.edu.tr/~bingul/c/index.php?ders=11
Fonksiyonları referansla çağırma Fonksiyonlarda pointer argüman kullanarak call by referance gerçekleştirilebilir. Adres geçişi için & operatörü kullanılabilir. Gerçek değerin hafıza üzerinden değiştirilmesini sağlar. Diziler için & kullanılmaz çünkü diziler zaten pointerdir * operatör Fonksiyonunun içindeki değişken için takma isim gibi davranır. void double( int *number ) { } *number = 2 * ( *number ); *number geçilen değişken için takma isim gibidir.
İlkel parametrelerin metot içine geçişi geçişi byval ile olur Metodun içerisinde yapılan değişiklikler metottan çıkınca kaybolur. Örnek : void main() { int x = 3; passmethod(x); İlkel veri türlerinin metotlara geçişi // print x to see if its // value has changed printf("after invoking passmethod, x = %d", x); } } // passmethod() içinde parametrelerin değiştirilmesi public static void passmethod(int p) { p = 10; } Çıktı = 3;
İlkel veri türlerinin metoda geçişi Metod int a=3; a 3 değerine sahiptir a=5
Pointerlarla bilgi geçişi Bu şekilde metodun içerisinde yapılan değişiklikler metottan çıkınca kaybolmaz. Çünkü metot içinde ve dışında aynı adres alanına referans edilir. Örnek: void movecircle(int *circle, int deltax, int deltay) { *circle=3; } Metot içinde mycircle pointerına referans edilir. Bu değişiklikler metot geri dönse de kalıcı olur.
Referans veri türlerinin metoda geçişi Metod int *p,int *y; *p=&y; *p=3 *p=10 *p 10 değerine sahiptir. Metot çağrılırken kullanılan değişken (aktüel değişken) metod içerisinde aynı nesneye (hafıza alanına) işaret ettiğinden, metot içinde değişirse metodun dışında da değişimin etkisi sürer.
Örnek İki tamsayının birbiri ile takas edilmesi http://stackoverflow.com/questions/8403447/swapping-pointers-in-c-char-int
Pointerler ile const niteleyiciler const qualifier Değiştirilemez değişkenler oluşturma amaçlı kullanılır. Eğer fonksiyonun değişkenin değerini değiştirmesi istenmiyorsa const kullanılmalıdır. const değişken değiştirilmek istenirse hata oluşur. const pointer ler Sabit bir hafıza adresini işaretler Tanımlandığı anda ilk değer atanmalıdır. int *const myptr = &x; Type int *const constant pointer to an int Veri değişebilir. Pointer değişemez. const int *myptr = &x; const int değerine işaret eden normal pointer Veri değişmez. Pointer değişebilir. const int *const Ptr = &x; const pointer işaret eder const int x değişebilir, *Ptr değişmez.
#include<stdio.h> int main(void) { int var1 = 0, var2 = 0; int *const ptr = &var1; ptr = &var2; printf("%d\n", *ptr); return 0; } Const pointer örnekler Bu kod çalışmaz. Çünkü ptr = &var2; satırı «error: assignment of read-only variable ptr» hatası verir.
Pointer Constant örnek Tanım const <type of pointer>* <name of pointer> Örnek const int* ptr; #include<stdio.h> int main(void) { int var1 = 0; const int* ptr = &var1; *ptr = 1; printf("%d\n", *ptr); } return 0; *ptr = 1; atama satırı «assignment of read-only location *ptr» hatası verir.
Constant Pointer Constant const <type of pointer>* const <name of pointer> const int* const ptr; #include<stdio.h> int main(void) { int var1 = 0,var2 = 0; const int* const ptr = &var1; *ptr = 1; ptr = &var2; printf("%d\n", *ptr); } return 0; constptr.c:7: error: assignment of read-only location *ptr constptr.c:8: error: assignment of read-only variable ptr
sizeof SizeOf İfadelerin byte cinsinden uzunluğunu döndürür. Diziler için: Tek bir elemanın büyüklüğü ile eleman sayısı çarpımıdır. Eğer sizeof( int ) 4 byte a eşitse int myarray[ 10 ]; printf( "%d", sizeof( myarray ) ); 40 yazdırır. sizeof aşağıdaki ifadelerle kullanılabilir. Değişken isimleri Tür ismi Sabit değerler sizeof ile değişken türlerinin bellekte ne kadar yer tutacağı bulunabilir.
Call-by-reference Fonksiyon Örneği void swap(int *ptr1, int *ptr2){ int hold=*ptr1; *ptr1=*ptr2; *ptr2=hold; } main (){ int a[5];. swap(&a[i],&a[i-1]); }
Pointer İfadeler ve Pointer Aritmatik Pointerler üzerinde aritmetik işlemler gerçekleştirilebilir. Increment/decrement pointer (++ or --) Add an integer to a pointer( + or +=, - or -=) Pointers may be subtracted from each other Operations meaningless unless performed on an array
Pointer İfadeler ve Pointer Aritmatik 5 eleman int dizisi 4 bit integer bir makinede vptr v dizisinin ilk elemanının adresini gösterir &v[ 0 ] 3000 adresinde (vptr = 3000) vptr += 2; sets vptr to 3008 vptr v[ 2 ] adresini gösterir (2 artarak), ancak makine 4 byte ints olduğundan, adres olarak 3008 gösterilir. location 3000 3004 3008 3012 3016 v[0] v[1] v[2] v[3] v[4] pointer variable vptr
Pointer İfadeler ve Pointer Aritmatik Pointer ların birbirinden çıkartılması Birbiri arasındaki eleman sayısını verir. vptr2 = v[ 2 ]; vptr = v[ 0 ]; vptr2 - vptr = 2 dir Pointer karşılaştırma ( <, ==, > ) Bir dizinin en üst yüksek indisli elemanını bulmak Pointer ın 0 ı adresleyip adreslemediğini kontrol etmek
Pointer İfadeler ve Pointer Aritmatik Aynı türdeki pointerler birbirine aranabilir. Eğer aynı türde değilse cast operatörü kullanılmalıdır. Harici Durum: Void gösteren pointer (type void *) Genel pointer, herhangi bir türü gösterebilir. Bir pointer ı void pointer e çevirmek için casting gerekmez. void pointer ın sonradan tekrar referansı çözülemez (dereference).
Pointer ve Diziler Arası İlişkiler C de İşaretçiler ve diziler arasında çok yakın bir ilişki vardır. Bir dizinin ismi, dizideki ilk elemanın adresini içeren sabit bir değişkendir. Pointer işlemlerde dizi indisi gibi kullanılabilir. dizi b[ 5 ] ve pointer bptr Aşağıdaki atamalar geçerlidir. bptr = b; bptr = &b[ 0 ]
b[ 3 ] Pointer ve Diziler Arası İlişkiler *( bptr + 3 ) şekline erişilebilir. bptr[ 3 ] şekline erişilebilir. pointer/subscript gösterilimi olarak isimlendirilir. bptr[ 3 ] b[ 3 ] gibidir. Dizi üzerinde pointer aritmetik kullanılarak da erişilebilir. *( b + 3 )
Outline Dizide dolaşma yöntemleri Klasik indisler kullanarak for ( i = 0; i < 4; i++ ) { printf( "b[ %d ] = %d\n", i, b[ i ] ); } /* end for */ Diziyi pointer ile gezerek (Pointer/offset yazımı Pointer array ismi olarak düşünülecektir. ) int *ptr; ptr=b; for ( i = 0; i < 4; i++ ) { printf( "b[ %d ] = %d\n", i, *p++ ); } /* end for */
Outline Program Output Array b printed with: Array subscript notation b[ 0 ] = 10 b[ 1 ] = 20 b[ 2 ] = 30 b[ 3 ] = 40 Pointer/offset yazımı Pointer array ismi olarak düşünülecektir. *( b + 0 ) = 10 *( b + 1 ) = 20 *( b + 2 ) = 30 *( b + 3 ) = 40 Pointer subscript yazılımı bptr[ 0 ] = 10 bptr[ 1 ] = 20 bptr[ 2 ] = 30 bptr[ 3 ] = 40 Pointer/offset gösterilimi *( bptr + 0 ) = 10 *( bptr + 1 ) = 20 *( bptr + 2 ) = 30 *( bptr + 3 ) = 40
1 /* Fig. 7.21: fig07_21.c 2 Copying a string using array notation and pointer notation. */ 3 #include <stdio.h> 4 5 void copy1( char *s1, const char *s2 ); /* prototype */ 6 void copy2( char *s1, const char *s2 ); /* prototype */ 7 8 int main() 9 { 10 char string1[ 10 ]; /* create array string1 */ 11 char *string2 = "Hello"; /* create a pointer to a string */ 12 char string3[ 10 ]; /* create array string3 */ 13 char string4[] = "Good Bye"; /* create a pointer to a string */ 14 15 copy1( string1, string2 ); 16 printf( "string1 = %s\n", string1 ); 17 18 copy2( string3, string4 ); 19 printf( "string3 = %s\n", string3 ); 20 21 return 0; /* indicates successful termination */ 22 23 } /* end main */ 24 Outline fig07_21.c (Part 1 of 2)
Outline Dizi sonlanma karakteri (\0) Eşitlik kullanarak char * s1[], * s2[]; for ( i = 0; (s1[i]=s2[i])!= \0 ; i++ ) { printf( "b[ %d ] = %d\n", i, s[ i ] ); } /* end for */ Pointer eşitliği üzerinden char * s1[], * s2[]; for ( i = 0; (*s1=*s2)!= \0 ; *s1++,*.s2++) { printf( "b[ %d ] = %d\n", i, s[ i ] ); } /* end for */
Fonksiyonlardan Dizi döndürme C de fonksiyon kendi içindeki diziyi doğrudan döndüremez. static kullanımı malloc kullanarak diziyi hafızada saklama Dizi referansı göndererek tekrar geri alma
Fonksiyonlardan Dizi döndürme (Diziyi göndererek tekrar geri alma) #include<stdio.h> /* Kendisine verilen iki diziyi birlestirip sonuclari ucuncu bir diziye atar */ int *dizileri_birlestir( int [], int, int [], int, int []); int main( void ) { // liste_1, 5 elemanli bir dizidir. int liste_1[5] = { 6, 7, 8, 9, 10 }; // liste_2, 7 elemanli bir dizidir. int liste_2[7] = {13, 7, 12, 9, 7, 1, 14 }; // sonuclarin toplanacagi toplam_sonuc dizisi int toplam_sonuc[13]; // sonucun dondurulmesi icin pointer tanimliyoruz int *ptr; int i; // fonksiyonu calistiriyoruz. ptr = dizileri_birlestir( liste_1, 5, liste_2, 7, toplam_sonuc ); // pointer uzerinden sonuclari yazdiriyoruz. for( i = 0; i < 12; i++ ) printf("%d ", *(ptr+i) ); printf("\n"); } return 0; http://www.cagataycebi.com/programming/c_programming/c_programming_10.html
Fonksiyonlardan Dizi döndürme (Diziyi göndererek tekrar geri alma-devam) int *dizileri_birlestir( int dizi_1[], int boyut_1, int dizi_2[], int boyut_2, int sonuc[] ) { int i, k; // Birinci dizinin degerleri ataniyor. for( i = 0; i < boyut_1; i++ ) sonuc[i] = dizi_1[i]; // Ikinci dizinin degerleri ataniyor. for( k = 0; k < boyut_2; i++, k++ ) { sonuc[i] = dizi_2[k]; } } // Geriye sonuc dizisi gonderiliyor. return sonuc;
Göstericilerin Dizileri Diziler pointer içerebilir. Örnek metin dizisi: char *suit[ 4 ] = { "Hearts", "Diamonds", "Clubs", "Spades" }; Strings ilk karakterleri gösteren pointer lerdir. char * suit in her elemanı char bir göstericidir manasındadır. String gerçekte suit içinde saklanmaz, sadece string pointer lar burada saklanır. suit[0] H e a r t s \0 suit[1] D i a m o n d s \0 suit[2] C l u b s \0 suit[3] S p a d e s \0 suit dizisi sabit uzunlukludur. Ancak stringler herhangi bir uzunlukta olabilir.
Gösterici Dizi Örnek Bir gösterici dizisindeki stringlerin uzunluğunu ikinci bir diziye aktarınız.
Gösterici Türünde Fonksiyonlar Bir fonksiyon tanımlanırken, parametreleri pointer olabileceği gibi, tipi de pointer olabilir. Bu, o fonksiyonun kendisini çağırana bir adres göndereceği anlamına gelir. Bu tür uygulamalar özellikle string uygulamalarında sık kullanılır.
Gösterici Türünde Fonksiyonlar Örnek: İki sayının toplamını bulan bir pointer türünde fonksiyon tasarlayınız.
Örnek Çözüm #include <stdio.h> int *topla(int,int); main(){ int a,b; int *p; a = 2; b = 4; p = topla(a,b); printf("toplam : %d (adresi %p)\n",*p,p); } int *topla(int x,int y) { int *ptr,toplam; toplam = x+y; ptr = &toplam; return ptr; }
Fonksiyon türünde göstericiler Fonksiyon tanımı void f(int); Fonksiyon türünde gösterici tanımı void (*pf1)(int) = &f; Fonksiyon türünde gösterici ile fonksiyon çağrılması int x = p(7)
Fonksiyon türünde göstericiler * Fonksiyon gösterici kullanımı Function un adresini içerir Dizinin ilk elemanının dizi adresi içermesine benzerdir. Fonksiyon ismi fonksiyonu tanımlayan kodun başlangıç adresini gösterir. Function pointer ler: Fonksiyonlara geçebilirler Dizilerde saklanabilir. Diğer fonksiyon göstericilere atanabilirler.
Fonksiyon Türünde Göstericiler Bütünleşik Örnek int f(int n) { } printf("değer %d",) return n*n; int main() { } int (*p)(int) = f; int x = p(7);
Kaynaklar https://www.youtube.com/watch?v=ynytggunele https://www.youtube.com/watch?v=cpjvucvac3g
Sorular