C'de İşaretçiler: C Programlamada İşaretçi Nedir? Türler
C'de İşaretçi Nedir?
The Işaretçi C'de, başka bir değişkenin adresini saklayan bir değişkendir. Bir işaretçi, başka bir işaretçi işlevine başvurmak için de kullanılabilir. Bir işaretçi artırılabilir/azaltılabilir, yani sonraki/önceki hafıza konumunu işaret etmek için. İşaretçinin amacı bellek alanından tasarruf etmek ve daha hızlı yürütme süresi elde etmektir.
C'de İşaretçiler Nasıl Kullanılır
Eğer int türünde bir v değişkeni bildirirsek, v aslında bir değer depolayacaktır.
v şimdi sıfıra eşit.
Bununla birlikte, her değişkenin değerin yanı sıra kendi adresi de vardır (veya daha basit bir ifadeyle, bellekte bulunduğu yere). Adres, değişken adının önüne ve işareti (&) konularak alınabilir.
Bir değişkenin adresini ekrana yazdırırsanız, tamamen rastgele bir sayı gibi görünecektir (üstelik, çalıştırmadan çalıştırmaya farklılık gösterebilir).
Bunu C örneğinde pointer ile pratikte deneyelim.
Bu programın çıktısı -480613588'dir.
Şimdi işaretçi nedir? Bir işaretçi, bir değeri saklamak yerine bir değişkenin adresini saklar.
İşaretçi Değişkeni
Dahili *y = &v;
DEĞİŞKEN | İŞARET |
---|---|
A değer içinde depolanmış adlı depolama/bellek adresi | A değişken o işaret depolama/bellek adresi bir diğeri değişken |
Bir İşaretçi Bildirmek
Değişkenler gibi işaretçiler de C programlama programınızda kullanılmadan önce bildirilmeleri gerekir. İşaretçiler, C'nin adlandırma kurallarına uydukları sürece istediğiniz şekilde adlandırılabilir. Bir işaretçi bildirimi aşağıdaki biçime sahiptir.
data_type * pointer_variable_name;
Burada,
- veri tipi C'nin değişken türlerinin işaretçinin temel türüdür ve işaretçinin işaret ettiği değişkenin türünü belirtir.
- Dolaylı bir işleç olan yıldız işareti (*: çarpma işleminde kullanılan yıldız işaretinin aynısı) bir işaretçiyi tanımlar.
Bu C işaretçileri eğitiminde bazı geçerli işaretçi bildirimlerini görelim:
int *ptr_thing; /* pointer to an integer */ int *ptr1,thing;/* ptr1 is a pointer to type integer and thing is an integer variable */ double *ptr2; /* pointer to a double */ float *ptr3; /* pointer to a float */ char *ch1 ; /* pointer to a character */ float *ptr, variable;/*ptr is a pointer to type float and variable is an ordinary float variable */
Bir işaretçiyi başlat
Bir işaretçi bildirdikten sonra, onu değişken adresli standart değişkenler gibi başlatırız. C programlamasındaki işaretçiler başlatılmazsa ve bir programda kullanılırsa, sonuçlar tahmin edilemez ve potansiyel olarak feci olabilir.
Bir değişkenin adresini almak için, adresine ihtiyacımız olan değişkenin adından önce yerleştirilen ve işareti (&) operatörünü kullanırız. İşaretçi başlatma aşağıdaki sözdizimiyle yapılır.
İşaretçi Söz Dizimi
pointer = &variable;
İşaretçi gösterimi için basit bir program aşağıda verilmiştir:
#include <stdio.h> int main() { int a=10; //variable declaration int *p; //pointer variable declaration p=&a; //store address of variable a in pointer p printf("Address stored in a variable p is:%x\n",p); //accessing the address printf("Value stored in a variable p is:%d\n",*p); //accessing the value return 0; }
Çıktı:
Address stored in a variable p is:60ff08 Value stored in a variable p is:10
Kullanım | anlam |
---|---|
* | 2 amaca hizmet eder
|
& | Yalnızca 1 amaca hizmet eder
|
C'de İşaretçi Türleri
Aşağıda farklı olanlar yer almaktadır C'de İşaretçi Türleri:
Boş işaretçisi
Pointer bildirimi sırasında null değer atayarak null pointer oluşturabiliriz. Bu yöntem, işaretçiye atanmış herhangi bir adresiniz olmadığında kullanışlıdır. Boş gösterici her zaman 0 değerini içerir.
Aşağıdaki program, null işaretçisinin kullanımını göstermektedir:
#include <stdio.h> int main() { int *p = NULL; //null pointer printf(“The value inside variable p is:\n%x”,p); return 0; }
Çıktı:
The value inside variable p is: 0
Geçersiz İşaretçi
In C programlamavoid işaretçisine genel işaretçi de denir. Herhangi bir standart veri tipi yoktur. Bir void işaretçisi void anahtar sözcüğü kullanılarak oluşturulur. Herhangi bir değişkenin adresini saklamak için kullanılabilir.
Aşağıdaki program, boş bir işaretçinin kullanımını göstermektedir:
#include <stdio.h> int main() { void *p = NULL; //void pointer printf("The size of pointer is:%d\n",sizeof(p)); return 0; }
Çıktı:
The size of pointer is:4
Vahşi işaretçi
Bir işaretçinin, herhangi bir şeye başlatılmıyorsa, vahşi bir işaretçi olduğu söylenir. Bu tür C işaretçileri verimli değildir çünkü programımızda sorunlara neden olabilecek bazı bilinmeyen bellek konumlarına işaret edebilir ve programın çökmesine neden olabilir. Vahşi işaretçilerle çalışırken her zaman dikkatli olunmalıdır.
Aşağıdaki program vahşi işaretçinin kullanımını göstermektedir:
#include <stdio.h> int main() { int *p; //wild pointer printf("\n%d",*p); return 0; }
Çıktı:
timeout: the monitored command dumped core sh: line 1: 95298 Segmentation fault timeout 10s main
'C'deki diğer işaretçi türleri aşağıdaki gibidir:
- Sarkan işaretçi
- Karmaşık işaretçi
- Yakın işaretçi
- Uzak işaretçi
- Büyük işaretçi
Doğrudan ve Dolaylı Erişim İşaretçileri
C'de değişken içeriğe erişmenin ve bunları değiştirmenin iki eşdeğer yolu vardır.
- Doğrudan erişim: doğrudan değişken adını kullanırız
- Dolaylı erişim: değişkene bir işaretçi kullanırız
Bunu aşağıdaki program yardımıyla anlayalım.
#include <stdio.h> /* Declare and initialize an int variable */ int var = 1; /* Declare a pointer to int */ int *ptr; int main( void ) { /* Initialize ptr to point to var */ ptr = &var; /* Access var directly and indirectly */ printf("\nDirect access, var = %d", var); printf("\nIndirect access, var = %d", *ptr); /* Display the address of var two ways */ printf("\n\nThe address of var = %d", &var); printf("\nThe address of var = %d\n", ptr); /*change the content of var through the pointer*/ *ptr=48; printf("\nIndirect access, var = %d", *ptr); return 0;}
Programı hatasız derledikten sonra sonuç:
Direct access, var = 1 Indirect access, var = 1 The address of var = 4202496 The address of var = 4202496 Indirect access, var = 48
C'de İşaretçi Aritmetiği
İşaretçi işlemleri aşağıdaki şekilde özetlenmiştir
Öncelikli çalışma (öncelik)
C işaretçileriyle çalışırken aşağıdaki öncelik kurallarına uymalıyız:
- * ve & operatörleri, tekli operatörlerle aynı önceliğe sahiptir (olumsuzlama!, artırma++, azaltma–).
- Aynı ifadede *, &,!, ++, – tekli operatörleri sağdan sola doğru değerlendirilir.
Bir P işaretçisi bir X değişkenine işaret ediyorsa, X'in yazılabildiği her yerde * P kullanılabilir.
Aşağıdaki ifadeler eşdeğerdir:
int X =10 int *P = &Y; For the above code, below expressions are true
ifade | Eşdeğer İfade |
---|---|
Y=*P+1
*P=*P+10 *P+=2 +****P (*P)++ |
Y=X+1
X=X+10 X+=2 ++X X ++ |
İkinci durumda, parantezlere ihtiyaç vardır: tekli operatörler * ve ++ sağdan sola doğru değerlendirildiğinden, parantezler olmadan P'nin işaret ettiği nesne değil, P işaretçisi artırılır.
Aşağıdaki tablo, C işaretçileriyle uğraşırken kullanılabilecek aritmetik ve temel işlemleri göstermektedir.
Çalışma | açıklama |
---|---|
Atama | int *P1,*P2 P1=P2; P1 ve P2 aynı tamsayı değişkenine işaret eder |
Arttırma ve azaltma | Dahili *P1; P1++;P1– ; |
Ofset ekleme (Sabit) | Bu, işaretçinin bir tablodaki N öğeyi taşımasına olanak tanır. İşaretçi, değişken türünün bayt (lar) sayısının N katı kadar artırılacak veya azaltılacaktır. P1+5; |
Örneklerle C İşaretçileri ve Dizileri
Geleneksel olarak dizi elemanlarına indeksini kullanarak erişiriz, ancak bu yöntem işaretçiler kullanılarak ortadan kaldırılabilir. İşaretçiler her dizi öğesine erişmeyi kolaylaştırır.
#include <stdio.h> int main() { int a[5]={1,2,3,4,5}; //array initialization int *p; //pointer declaration /*the ptr points to the first element of the array*/ p=a; /*We can also type simply ptr==&a[0] */ printf("Printing the array elements using pointer\n"); for(int i=0;i<5;i++) //loop for traversing array elements { printf("\n%x",*p); //printing array elements p++; //incrementing to the next element, you can also write p=p+1 } return 0; }
Çıktı:
1 2 3 4 5
Bir işaretçiye belirli bir sayı eklemek, işaretçi konumunu bir toplama işlemiyle elde edilen değere taşıyacaktır. p'nin şu anda bellek konumu 0'ı işaret eden bir işaretçi olduğunu varsayalım, aşağıdaki toplama işlemini gerçekleştirirsek, p+1, bu şekilde yürütülecektir:
p şu anda 0 eklendikten sonra 1 konumunu gösterdiğinden, değer 1 olacak ve dolayısıyla işaretçi 1 bellek konumunu gösterecektir.
Örneklerle C İşaretçileri ve Dizeleri
Bir dize, '\ 0' boş karakteriyle biten bir karakter nesneleri dizisidir. İşaretçileri kullanarak dizeleri işleyebiliriz. C örneğindeki bu işaretçi bu bölümü açıklamaktadır
#include <stdio.h> #include <string.h> int main() { char str[]="Hello Guru99!"; char *p; p=str; printf("First character is:%c\n",*p); p =p+1; printf("Next character is:%c\n",*p); printf("Printing all the characters in a string\n"); p=str; //reset the pointer for(int i=0;i<strlen(str);i++) { printf("%c\n",*p); p++; } return 0; }
Çıktı:
First character is:H Next character is:e Printing all the characters in a string H e l l o G u r u 9 9 !
Dizeleri işlemenin bir başka yolu da aşağıdaki programdaki gibi bir dizi işaretçi kullanmaktır:
#include <stdio.h> int main(){ char *materials[ ] = { "iron", "copper", "gold"}; printf("Please remember these materials :\n"); int i ; for (i = 0; i < 3; i++) { printf("%s\n", materials[ i ]);} return 0;}
Çıktı:
Please remember these materials: iron copper gold
C'de İşaretçilerin Avantajları
- İşaretçiler bellek konumlarına erişim için kullanışlıdır.
- İşaretçiler bir dizi yapısının öğelerine erişmenin etkili bir yolunu sağlar.
- İşaretçiler, dinamik bellek ayırmanın yanı sıra serbest bırakma için de kullanılır.
- İşaretçiler, bağlantılı liste, grafik, ağaç vb. gibi karmaşık veri yapıları oluşturmak için kullanılır.
C'de İşaretçilerin Dezavantajları
- İşaretçileri anlamak biraz karmaşıktır.
- İşaretçiler, bölümlendirme hataları gibi çeşitli hatalara yol açabilir veya hiç gerekli olmayan bir bellek konumuna erişebilir.
- Bir işaretçiye yanlış bir değer sağlanırsa hafıza bozulmasına neden olabilir.
- İşaretçiler ayrıca bellek sızıntısından da sorumludur.
- İşaretçiler değişkenlerinkinden nispeten daha yavaştır.
- Programcılar işaretçilerle çalışmayı çok zor buluyor; bu nedenle bir işaretçiyi dikkatli bir şekilde değiştirmek programcının sorumluluğundadır.
ÖZET
- İşaretçi, verilerin depolandığı bir bellek konumundan başka bir şey değildir.
- Bellek konumuna erişmek için bir işaretçi kullanılır.
- Boş işaretçi, vahşi işaretçi, geçersiz işaretçi ve diğer işaretçi türleri gibi çeşitli işaretçi türleri vardır.
- Öğelere daha verimli erişmek için işaretçiler dizi ve dizeyle birlikte kullanılabilir.
- Bir işlevi dinamik olarak çağırmak için işlev işaretçileri oluşturabiliriz.
- İşaretçi aritmetiği olarak bilinen bir işaretçi üzerinde aritmetik işlemler yapılabilir.
- İşaretçiler ayrıca bir dizi işaretçinin tanımlanması durumunda farklı işlevlerin çağrılmasını kolaylaştıran işlevlere de işaret edebilir.
- Farklı değişken veri türleriyle ilgilenmek istediğinizde typecast void işaretçisini kullanabilirsiniz.