- Puan
- 28
- Yaş
- 118
╔════════════════════════════════════════════════════════════════════╗
║ C PROGRAMLAMA DİLİ EĞİTİM SERİSİ #9 ║
║ POINTERLAR (İŞARETÇİLER) ║
║ (Mala Anlatır Gibi) ║
╚════════════════════════════════════════════════════════════════════╝
Bu noktaya kadar geldiysek artık C'nin gerçekten C olmaya başladığı yere geldik.
Birçok kişi:
"Dizileri öğrendim."
"Fonksiyonları öğrendim."
"Stringleri öğrendim."
der.
Sonra Pointer konusuna gelir.
Ve beyninden duman çıkmaya başlar.
Aslında Pointer konusu zor değildir.
Yanlış anlatıldığı için zor görünür.
Bugün Pointer mantığını kafana çivi gibi çakacağız.
════════════════════════════════════════════════════════════════════
▓▓▓ BİLGİSAYARDA HER ŞEYİN ADRESİ VARDIR
Evini düşün.
Bir arkadaşın sana gelmek istiyor.
Sadece:
"Türkiye'deyim"
dersen bulamaz.
Adres gerekir.
Örnek:
Ankara
Çankaya
Sokak
No
Bilgisayar da aynı şekilde çalışır.
Bellekte duran her verinin bir adresi vardır.
Örnek:
int sayi = 10;
Bellekte:
Adres Değer
1000 10
gibi tutulabilir.
Gerçekte adresler farklıdır.
Ama mantık budur.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER NEDİR?
Pointer:
Bir değişkenin değerini değil
adresini tutan değişkendir.
Tekrar okuyalım.
Normal değişken:
10
saklar.
Pointer:
10'un bulunduğu adresi saklar.
════════════════════════════════════════════════════════════════════
▓▓▓ & OPERATÖRÜ
Bir değişkenin adresini öğrenmek için:
&
kullanılır.
Örnek:
#include <stdio.h>
int main()
{
int sayi = 10;
printf("%p", &sayi);
return 0;
}
ÇIKTI
0x61ff08
Buna benzer bir şey görürsün.
Çünkü adresler sistemden sisteme değişir.
════════════════════════════════════════════════════════════════════
▓▓▓ İLK POINTER
int sayi = 10;
int *ptr;
Buradaki:
ptr
bir pointerdır.
Çünkü başında:
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER'A ADRES ATAMA
int sayi = 10;
int *ptr;
ptr = &sayi;
Artık:
ptr
sayi değişkeninin adresini tutuyor.
Şema:
sayi = 10
Adres = 1000
ptr = 1000
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER'I YAZDIRMA
#include <stdio.h>
int main()
{
int sayi = 10;
int *ptr;
ptr = &sayi;
printf("%p", ptr);
return 0;
}
ÇIKTI
0x61ff08
Adres yazdırılır.
════════════════════════════════════════════════════════════════════
▓▓▓ * OPERATÖRÜNÜN İKİ ANLAMI
Yeni başlayanların en çok karıştırdığı konu.
Birinci anlam:
int *ptr;
Pointer tanımlamak.
İkinci anlam:
*ptr
Adresteki değere ulaşmak.
Aynı sembol.
Farklı görev.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER İLE DEĞERE ULAŞMA
#include <stdio.h>
int main()
{
int sayi = 10;
int *ptr;
ptr = &sayi;
printf("%d", *ptr);
return 0;
}
ÇIKTI
10
Neden?
Çünkü:
ptr
sayi'nin adresini tutuyor.
*ptr
ise o adresteki değeri getiriyor.
════════════════════════════════════════════════════════════════════
▓▓▓ OLAYI TAM OTURTALIM
int sayi = 50;
int *ptr = &sayi;
Bellek:
Adres Değer
1000 50
ptr içinde:
1000
saklanıyor.
Şimdi:
*ptr
dediğimiz zaman:
"Git 1000 adresine bak"
demiş oluyoruz.
Sonuç:
50
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER İLE DEĞER DEĞİŞTİRME
#include <stdio.h>
int main()
{
int sayi = 10;
int *ptr = &sayi;
*ptr = 99;
printf("%d", sayi);
return 0;
}
ÇIKTI
99
Neden?
Çünkü:
*ptr
doğrudan sayi değişkenini değiştirdi.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER'IN GÜCÜ
Normalde:
sayi = 50;
değişkenine erişmek gerekir.
Pointer sayesinde:
*ptr = 50;
diyerek de değiştirebiliriz.
Bu özellik:
işletim sistemlerinde
oyun motorlarında
sürücülerde
gömülü sistemlerde
çok kullanılır.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER VE FONKSİYONLAR
Örnek:
void degistir(int x)
{
x = 100;
}
int main()
{
int sayi = 5;
degistir(sayi);
printf("%d", sayi);
}
ÇIKTI
5
Birçok kişi:
100
bekler.
Ama sonuç:
5
olur.
Çünkü fonksiyon değişkenin kopyasını aldı.
════════════════════════════════════════════════════════════════════
▓▓▓ GERÇEK DEĞERİ DEĞİŞTİRMEK
İşte pointer burada devreye girer.
#include <stdio.h>
void degistir(int *x)
{
*x = 100;
}
int main()
{
int sayi = 5;
degistir(&sayi);
printf("%d", sayi);
return 0;
}
ÇIKTI
100
Artık gerçek değişken değişti.
════════════════════════════════════════════════════════════════════
▓▓▓ ADIM ADIM İNCELEYELİM
degistir(&sayi);
Burada adres gönderiyoruz.
Fonksiyon:
int *x
ile adresi alıyor.
Sonra:
*x = 100;
diyor.
Yani:
"Gönderilen adresteki değeri 100 yap."
Sonuç:
sayi = 100
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER VE DİZİLER
Hatırlayalım:
int sayilar[3] = {10,20,30};
Bellekte yan yana tutulurlar.
Şöyle düşünebiliriz:
Adres Değer
1000 10
1004 20
1008 30
Diziler pointerlarla çok yakın ilişkilidir.
════════════════════════════════════════════════════════════════════
▓▓▓ DİZİ ADI ASLINDA ADRESTİR
Örnek:
int sayilar[3] = {10,20,30};
sayilar
aslında ilk elemanın adresidir.
Yani:
sayilar
ile
&sayilar[0]
aynı şeyi temsil eder.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER ARİTMETİĞİ
Örnek:
int sayilar[3] = {10,20,30};
int *ptr = sayilar;
printf("%d\n", *ptr);
ÇIKTI
10
Şimdi:
ptr++;
yapalım.
Artık:
ptr
ikinci elemana geçti.
printf("%d\n", *ptr);
ÇIKTI
20
Bir kez daha:
ptr++;
ÇIKTI
30
════════════════════════════════════════════════════════════════════
▓▓▓ NULL POINTER
Bazen pointer henüz bir adres göstermiyordur.
Bu durumda:
int *ptr = NULL;
kullanılır.
NULL:
"Hiçbir yeri göstermiyorum."
anlamına gelir.
════════════════════════════════════════════════════════════════════
▓▓▓ EN TEHLİKELİ HATALARDAN BİRİ
int *ptr;
printf("%d", *ptr);
Çok tehlikelidir.
Çünkü:
ptr
nereye işaret ediyor bilmiyoruz.
Rastgele bir adres olabilir.
Program çökebilir.
════════════════════════════════════════════════════════════════════
▓▓▓ GÜVENLİ KULLANIM
int *ptr = NULL;
if(ptr != NULL)
{
printf("%d", *ptr);
}
Bu daha güvenlidir.
════════════════════════════════════════════════════════════════════
▓▓▓ MİNİ PROJE #1
İKİ SAYIYI POINTER İLE TAKAS ETME
#include <stdio.h>
void takas(int *a, int *b)
{
int gecici;
gecici = *a;
*a = *b;
*b = gecici;
}
int main()
{
int x = 10;
int y = 20;
takas(&x,&y);
printf("%d %d", x, y);
return 0;
}
ÇIKTI
20 10
════════════════════════════════════════════════════════════════════
▓▓▓ MİNİ PROJE #2
POINTER İLE DİZİ TOPLAMI
#include <stdio.h>
int main()
{
int sayilar[5] = {1,2,3,4,5};
int *ptr = sayilar;
int toplam = 0;
for(int i=0; i<5; i++)
{
toplam += *(ptr+i);
}
printf("%d", toplam);
return 0;
}
ÇIKTI
15
════════════════════════════════════════════════════════════════════
▓▓▓ MİNİ PROJE #3
POINTER İLE EN BÜYÜK SAYI
int sayilar[5] = {5,10,80,25,40};
int *ptr = sayilar;
int enBuyuk = *ptr;
for(int i=1; i<5; i++)
{
if(*(ptr+i) > enBuyuk)
{
enBuyuk = *(ptr+i);
}
}
printf("%d", enBuyuk);
ÇIKTI
80
════════════════════════════════════════════════════════════════════
⚠ YENİ BAŞLAYANLARIN HATALARI
HATA #1
int ptr;
Pointer sanmak.
Doğrusu:
int *ptr;
════════════════════════════════════════════════════════════════════
HATA #2
ptr = sayi;
Adres yerine değer atamak.
Doğrusu:
ptr = &sayi;
════════════════════════════════════════════════════════════════════
HATA #3
printf("%d", ptr);
Değeri beklemek.
Bu adres yazdırır.
Değer için:
printf("%d", *ptr);
kullanılır.
════════════════════════════════════════════════════════════════════
HATA #4
NULL olmayan pointer kontrolü yapmadan kullanmak.
Bu program çökmesine neden olabilir.
════════════════════════════════════════════════════════════════════
✓ BÖLÜM ÖZETİ
Bu bölümde:
✓ Bellek adresleri
✓ Pointer nedir
✓ & operatörü
✓ * operatörü
✓ Pointer tanımlama
✓ Pointer ile değer okuma
✓ Pointer ile değer değiştirme
✓ Fonksiyonlara adres gönderme
✓ Pointer ve diziler
✓ Pointer aritmetiği
✓ NULL pointer
✓ Gerçek hayat kullanım alanları
konularını öğrendik.
Bir sonraki bölümde DİNAMİK BELLEK YÖNETİMİ (malloc, calloc, realloc, free) konusuna geçeceğiz. Bu konu pointer bilgisini gerçek güce dönüştüren aşamadır.
║ C PROGRAMLAMA DİLİ EĞİTİM SERİSİ #9 ║
║ POINTERLAR (İŞARETÇİLER) ║
║ (Mala Anlatır Gibi) ║
╚════════════════════════════════════════════════════════════════════╝
Bu noktaya kadar geldiysek artık C'nin gerçekten C olmaya başladığı yere geldik.
Birçok kişi:
"Dizileri öğrendim."
"Fonksiyonları öğrendim."
"Stringleri öğrendim."
der.
Sonra Pointer konusuna gelir.
Ve beyninden duman çıkmaya başlar.
Aslında Pointer konusu zor değildir.
Yanlış anlatıldığı için zor görünür.
Bugün Pointer mantığını kafana çivi gibi çakacağız.
════════════════════════════════════════════════════════════════════
▓▓▓ BİLGİSAYARDA HER ŞEYİN ADRESİ VARDIR
Evini düşün.
Bir arkadaşın sana gelmek istiyor.
Sadece:
"Türkiye'deyim"
dersen bulamaz.
Adres gerekir.
Örnek:
Ankara
Çankaya
Sokak
No
Bilgisayar da aynı şekilde çalışır.
Bellekte duran her verinin bir adresi vardır.
Örnek:
int sayi = 10;
Bellekte:
Adres Değer
1000 10
gibi tutulabilir.
Gerçekte adresler farklıdır.
Ama mantık budur.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER NEDİR?
Pointer:
Bir değişkenin değerini değil
adresini tutan değişkendir.
Tekrar okuyalım.
Normal değişken:
10
saklar.
Pointer:
10'un bulunduğu adresi saklar.
════════════════════════════════════════════════════════════════════
▓▓▓ & OPERATÖRÜ
Bir değişkenin adresini öğrenmek için:
&
kullanılır.
Örnek:
#include <stdio.h>
int main()
{
int sayi = 10;
printf("%p", &sayi);
return 0;
}
ÇIKTI
0x61ff08
Buna benzer bir şey görürsün.
Çünkü adresler sistemden sisteme değişir.
════════════════════════════════════════════════════════════════════
▓▓▓ İLK POINTER
int sayi = 10;
int *ptr;
Buradaki:
ptr
bir pointerdır.
Çünkü başında:
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER'A ADRES ATAMA
int sayi = 10;
int *ptr;
ptr = &sayi;
Artık:
ptr
sayi değişkeninin adresini tutuyor.
Şema:
sayi = 10
Adres = 1000
ptr = 1000
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER'I YAZDIRMA
#include <stdio.h>
int main()
{
int sayi = 10;
int *ptr;
ptr = &sayi;
printf("%p", ptr);
return 0;
}
ÇIKTI
0x61ff08
Adres yazdırılır.
════════════════════════════════════════════════════════════════════
▓▓▓ * OPERATÖRÜNÜN İKİ ANLAMI
Yeni başlayanların en çok karıştırdığı konu.
Birinci anlam:
int *ptr;
Pointer tanımlamak.
İkinci anlam:
*ptr
Adresteki değere ulaşmak.
Aynı sembol.
Farklı görev.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER İLE DEĞERE ULAŞMA
#include <stdio.h>
int main()
{
int sayi = 10;
int *ptr;
ptr = &sayi;
printf("%d", *ptr);
return 0;
}
ÇIKTI
10
Neden?
Çünkü:
ptr
sayi'nin adresini tutuyor.
*ptr
ise o adresteki değeri getiriyor.
════════════════════════════════════════════════════════════════════
▓▓▓ OLAYI TAM OTURTALIM
int sayi = 50;
int *ptr = &sayi;
Bellek:
Adres Değer
1000 50
ptr içinde:
1000
saklanıyor.
Şimdi:
*ptr
dediğimiz zaman:
"Git 1000 adresine bak"
demiş oluyoruz.
Sonuç:
50
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER İLE DEĞER DEĞİŞTİRME
#include <stdio.h>
int main()
{
int sayi = 10;
int *ptr = &sayi;
*ptr = 99;
printf("%d", sayi);
return 0;
}
ÇIKTI
99
Neden?
Çünkü:
*ptr
doğrudan sayi değişkenini değiştirdi.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER'IN GÜCÜ
Normalde:
sayi = 50;
değişkenine erişmek gerekir.
Pointer sayesinde:
*ptr = 50;
diyerek de değiştirebiliriz.
Bu özellik:
işletim sistemlerinde
oyun motorlarında
sürücülerde
gömülü sistemlerde
çok kullanılır.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER VE FONKSİYONLAR
Örnek:
void degistir(int x)
{
x = 100;
}
int main()
{
int sayi = 5;
degistir(sayi);
printf("%d", sayi);
}
ÇIKTI
5
Birçok kişi:
100
bekler.
Ama sonuç:
5
olur.
Çünkü fonksiyon değişkenin kopyasını aldı.
════════════════════════════════════════════════════════════════════
▓▓▓ GERÇEK DEĞERİ DEĞİŞTİRMEK
İşte pointer burada devreye girer.
#include <stdio.h>
void degistir(int *x)
{
*x = 100;
}
int main()
{
int sayi = 5;
degistir(&sayi);
printf("%d", sayi);
return 0;
}
ÇIKTI
100
Artık gerçek değişken değişti.
════════════════════════════════════════════════════════════════════
▓▓▓ ADIM ADIM İNCELEYELİM
degistir(&sayi);
Burada adres gönderiyoruz.
Fonksiyon:
int *x
ile adresi alıyor.
Sonra:
*x = 100;
diyor.
Yani:
"Gönderilen adresteki değeri 100 yap."
Sonuç:
sayi = 100
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER VE DİZİLER
Hatırlayalım:
int sayilar[3] = {10,20,30};
Bellekte yan yana tutulurlar.
Şöyle düşünebiliriz:
Adres Değer
1000 10
1004 20
1008 30
Diziler pointerlarla çok yakın ilişkilidir.
════════════════════════════════════════════════════════════════════
▓▓▓ DİZİ ADI ASLINDA ADRESTİR
Örnek:
int sayilar[3] = {10,20,30};
sayilar
aslında ilk elemanın adresidir.
Yani:
sayilar
ile
&sayilar[0]
aynı şeyi temsil eder.
════════════════════════════════════════════════════════════════════
▓▓▓ POINTER ARİTMETİĞİ
Örnek:
int sayilar[3] = {10,20,30};
int *ptr = sayilar;
printf("%d\n", *ptr);
ÇIKTI
10
Şimdi:
ptr++;
yapalım.
Artık:
ptr
ikinci elemana geçti.
printf("%d\n", *ptr);
ÇIKTI
20
Bir kez daha:
ptr++;
ÇIKTI
30
════════════════════════════════════════════════════════════════════
▓▓▓ NULL POINTER
Bazen pointer henüz bir adres göstermiyordur.
Bu durumda:
int *ptr = NULL;
kullanılır.
NULL:
"Hiçbir yeri göstermiyorum."
anlamına gelir.
════════════════════════════════════════════════════════════════════
▓▓▓ EN TEHLİKELİ HATALARDAN BİRİ
int *ptr;
printf("%d", *ptr);
Çok tehlikelidir.
Çünkü:
ptr
nereye işaret ediyor bilmiyoruz.
Rastgele bir adres olabilir.
Program çökebilir.
════════════════════════════════════════════════════════════════════
▓▓▓ GÜVENLİ KULLANIM
int *ptr = NULL;
if(ptr != NULL)
{
printf("%d", *ptr);
}
Bu daha güvenlidir.
════════════════════════════════════════════════════════════════════
▓▓▓ MİNİ PROJE #1
İKİ SAYIYI POINTER İLE TAKAS ETME
#include <stdio.h>
void takas(int *a, int *b)
{
int gecici;
gecici = *a;
*a = *b;
*b = gecici;
}
int main()
{
int x = 10;
int y = 20;
takas(&x,&y);
printf("%d %d", x, y);
return 0;
}
ÇIKTI
20 10
════════════════════════════════════════════════════════════════════
▓▓▓ MİNİ PROJE #2
POINTER İLE DİZİ TOPLAMI
#include <stdio.h>
int main()
{
int sayilar[5] = {1,2,3,4,5};
int *ptr = sayilar;
int toplam = 0;
for(int i=0; i<5; i++)
{
toplam += *(ptr+i);
}
printf("%d", toplam);
return 0;
}
ÇIKTI
15
════════════════════════════════════════════════════════════════════
▓▓▓ MİNİ PROJE #3
POINTER İLE EN BÜYÜK SAYI
int sayilar[5] = {5,10,80,25,40};
int *ptr = sayilar;
int enBuyuk = *ptr;
for(int i=1; i<5; i++)
{
if(*(ptr+i) > enBuyuk)
{
enBuyuk = *(ptr+i);
}
}
printf("%d", enBuyuk);
ÇIKTI
80
════════════════════════════════════════════════════════════════════
⚠ YENİ BAŞLAYANLARIN HATALARI
HATA #1
int ptr;
Pointer sanmak.
Doğrusu:
int *ptr;
════════════════════════════════════════════════════════════════════
HATA #2
ptr = sayi;
Adres yerine değer atamak.
Doğrusu:
ptr = &sayi;
════════════════════════════════════════════════════════════════════
HATA #3
printf("%d", ptr);
Değeri beklemek.
Bu adres yazdırır.
Değer için:
printf("%d", *ptr);
kullanılır.
════════════════════════════════════════════════════════════════════
HATA #4
NULL olmayan pointer kontrolü yapmadan kullanmak.
Bu program çökmesine neden olabilir.
════════════════════════════════════════════════════════════════════
✓ BÖLÜM ÖZETİ
Bu bölümde:
✓ Bellek adresleri
✓ Pointer nedir
✓ & operatörü
✓ * operatörü
✓ Pointer tanımlama
✓ Pointer ile değer okuma
✓ Pointer ile değer değiştirme
✓ Fonksiyonlara adres gönderme
✓ Pointer ve diziler
✓ Pointer aritmetiği
✓ NULL pointer
✓ Gerçek hayat kullanım alanları
konularını öğrendik.
Bir sonraki bölümde DİNAMİK BELLEK YÖNETİMİ (malloc, calloc, realloc, free) konusuna geçeceğiz. Bu konu pointer bilgisini gerçek güce dönüştüren aşamadır.