| 
                
             | 
        
        
            
                
                    
                        | 
                            Değer İle Çağırma - Referans İle Çağırma Kavramları | 
                        
                             | 
                                
                     
                    
                        
                            
	
    
		
            | Gönderiliyor lütfen bekleyin... |   
        
	 
    
 
                         | 
                     
                 
             | 
        
        
            
                
                 Bu yazımızda, 
  "değer ile çağırma" ve "referans ile çağırma" kavramlarının 
  anlamlarına ve uygulamada ne şekilde karşımıza çıkacaklarına değineceğiz. Değer 
  ile çağırma ve referans ile çağırma terimlerinin İngilizce karşılıkları sırasıyla 
  "Call by Value" ve "Call by Reference"dır. Peki bu terimler 
  ne anlama gelmektedir? Örneğin bu terimler ile parametre değişkenlerinin fonksiyonlara 
  aktarımı sırasında karşılaşırız. int türden bir parametre alan bir fonksiyona, 
  çağrımdan önce tanımladığımız int türden bir değişkeni parametre değişkeni olarak 
  geçtiğimiz zaman, fonksiyonun parametre değişkeni için geçici bir nesne yaratılır 
  ve bizim fonksiyona göndermiş olduğumuz değişkenin değeri bu geçici nesneye 
  aktarılır. Dolayısıyla fonksiyonun parametresinin değeri ile bizim fonksiyona 
  geçtiğimiz değişkenin değeri aynı olur. Ancak bu iki nesne aynı nesne değildir. 
  Bellekte bu noktada iki tane birbirinden farklı ancak aynı değere sahip nesne 
  bulunmaktadır. Bu durum "değer ile çağırma" olarak bilinir. Bir örnekle 
  bu durumu açıklayalım :
  
	
		
    int IslemYap(int 
      parametre) 
      { 
          return parametre * parametre; 
      } 
      //... 
      int sonuc, degisken = 5; 
      sonuc = IslemYap(degisken);  | 
	 
 
Örnekte tanımladığımız 
  fonksiyon int türden bir parametre alıyor. Fonksiyon, bu parametrenin karesini 
  alarak bu değere geri dönüyor. Örneğin devamında, "sonuc" ve "degisken" 
  isimlerinde int türden iki nesne tanımlıyoruz. Daha sonra "degisken" 
  nesnesini, IslemYap() fonksiyonuna parametre olarak geçerek geri dönen değeri 
  "sonuc" nesnemize atıyoruz. Fonksiyonu çağırdığımız noktada, fonksiyonun 
  parametresi için int türden geçici bir nesne yaratılır. Bu nesneye "degisken" 
  nesnesinin değeri, yani 5 değeri atanır. Fonksiyon içerisindeki işlemler bu 
  geçici nesne üzerinde yapılır. Fonksiyon return ifadesi ile son bulduktan sonra 
  bu geçici nesne de yok edilir. Peki fonksiyonu şu şekilde yazmış olsaydık ne 
  ile karşılaşacaktık?
  
	
		
    void IslemYap(int 
      parametre) 
      { 
          parametre *= 2; 
      }  
      int main() 
        { 
            int degisken = 5; 
            printf("ilk 
        deger :%d\n",degisken);  
            IslemYap(°isken); 
            printf("cagridan sonraki deger :%d\n",degisken);     return 0; 
        }
  
     | 
	 
 
Burada IslemYap() 
  fonksiyonunda, fonksiyonun parametre degiskeninin değeri değiştirilmiştir. Fonksiyon 
  herhangi bir değer geri döndürmemektedir. Böyle bir fonksiyonun yazılmasındaki 
  amaç, büyük ihtimalle parametre değişkeninin değeri değiştirmektir. Kod içerisinde, 
  fonksiyonu değeri 5 olan bir değişken ile çağırıyoruz. Değişkenin değerinin, 
  fonksiyonun yaptığı işe göre 10 olmasını bekliyoruz. Ancak ikinci printf() çağrısı 
  ile de ekrana 5 yazılıyor. Bunun nedenini şöyle açıklayabiliriz : Fonksiyonun 
  parmetre değişkeni olan nesne, fonksiyon çağrıldığında derleyici tarafından 
  tanımlandığı türde yaratılır. Bu nesneye, fonksiyon çağrılmasında kullanılan 
  nesnenin değeri aktarılır. Bu noktada bizim fonksiyonumuzun parametre değişkeninin 
  değeri 5’tir. Fonksiyon bloğu içerisinde bu geçici nesnenin değeri "parametre 
  *= 2;" ifadesi ile 10 yapılır. Fonksiyonun bloğu sonlandığında bu geçici 
  nesne de yok edilir. Yani değeri 10 olan nesnemiz artık yoktur. Bizim fonksiyonumuzu 
  çağırırken kullandığımız nesnenin değeri ise hala 5’tir. Çünkü biz bu fonksiyonu, 
  "call by value" yöntemine göre yani "değer ile çağırma" 
  yöntemine göre tanımlamışız. Bu durumu şekille ifade edelim :
  
       
  
Yukarıdaki şekillerde 
  yazdığımız kodda tanımlanan nesnelerin bellekteki temsili görünümlerini görüyoruz. 
  degisken isimli nesnenin bellekte 1000 adresinde ayrıldığını varsayalım. (Buradaki 
  adres değerleri tamamen örnek olarak verilmiştir.) Fonksiyonun ana bloğuna girildiğinde 
  parametre değişkeni için 3000 adresinin ayrıldığını düşünelim. Bu durumda fonksiyon 
  içerisinde paremetre değişkeni üzerinde yapılan değişikliklerden belleğin 3000 
  adres bölümü etkilenecektir. degisken isimli nesnenin bulunduğu 1000 adres değerine 
  sahip bölge bu değişiklikten etkilenmeyecektir. Fonksiyon sonlandığında parametre 
  değişkeni için ayrılan bölge de boşaltılacağı için değişiklikler sonucunda elde 
  ettiğimiz değeri de kaybetmiş olacağız. 
  
Bir nesnenin değerini, 
  bir fonksiyon içerisinde değiştirmek istiyorsak; bu fonksiyona nesnenin değerini 
  değil, referansını göndermeliyiz. Başka bir deyişle, fonksiyonumuz bu nesnenin 
  bellekteki konumuna giderek yapacağı değişiklikleri orada yapmalıdır. Aksi takdirde 
  hiçbir nesnenin değerini fonksiyon içerisinde değiştiremeyiz. Sadece bu nesnenin 
  değerini kullanarak, geçici nesneler üzerinde işlem yapabiliriz. Yukarıda yapmak 
  istediğimiz işlemi şöyle bir kod yazarak gerçekleştirebiliriz :
  
   
    void IslemYap(int 
      *parametre) 
      { 
         *parametre *= 2; 
      }  
      int main() 
        { 
            int degisken = 5;     printf("ilk 
        deger :%d\n",degisken);  
            IslemYap(°isken); 
            printf("cagridan sonraki deger :%d\n",degisken);      return 0; 
        }
  
     | 
   
 
IslemYap() fonksiyonunun 
  bu hali, parametre değişkeni olarak int türden bir adres almaktadır. Bu adresteki 
  değere (*parametre) ifadesi ile erişiyoruz ve 2 ile çarpıp fonksiyonu sonlandırıyoruz. 
  Şimdi fonksiyonu çağırırken parametre değişkeni olarak degisken nesnesini değil, 
  bu nesnenin adresini gönderiyoruz. Dolayısıyla fonksiyon içerisindeki değişiklikler 
  bu adres üzerinde gerçekleiyor. Fonksiyondan çıkıldığında ise bu adres bölgesi 
  henüz boşaltılmadığı için degisken isimli nesneye ulaştığımızda 10 değerini 
  elde ediyoruz. Bu şekilde çağırma "Call by Reference", yani "referans 
  ile çağırma" olarak bilinir. Bu çağırmada fonksiyona parametre değişkeni 
  olarak nesnenin değeri değil, kendisi gönderilmiş olur. Bu değeri elbette fonksiyondan 
  return ifadesi ile geri döndürerek de elde edip çağırdığımız yerde bir değişkene 
  atayabilirdik. Ancak bir fonksiyondan birden fazla sayıda değer elde etmek istiyorsak 
  bu işlem için referans ile çağırma yöntemini tercih etmemiz gerekir. return 
  ifadesi ile fonksiyondan ancak bir değeri geri döndürebiliriz. Örneğin bir fonksiyondan 
  bize bir sayının hem karesini hem de küpünü göndermesini istiyorsak return ifadesine 
  hangi değeri yazacağız? Bu işlem için fonksiyona parametre değişkeni olarak 
  iki adres gönderirsek, elde ettiğimiz değerleri bu adres bölgelerine yazıp fonksiyon 
  çağrısından sonra bu bölgelere erişebiliriz :
  
   
     
      void KareVeKupAl(int 
        sayi,int *kare, int *kup) 
        { 
            *kare = sayi * sayi; 
            *kup = sayi * sayi * sayi; 
        }
  
      int main() 
        { 
            int *karesi, *kubu; 
            int sayi = 5;
  
           karesi = 
        (int *)malloc(sizeof(int)); 
            kubu = (int *)malloc(sizeof(int));
  
           printf("Sayi 
        :%d\n",sayi); 
            KareVeKupAl(sayi,karesi,kubu); 
            printf("Karesi :%d\n",*karesi); 
            printf("Kubu :%d\n",*kubu);
  
           return 0; 
        }
  
     | 
   
 
KareVeKupAl fonksiyonu 
  parametre değişkeni olarak, karesi ve küpü alınacak sayısı, daha sonra elde 
  ettiği değerleri yazacağı adresleri alıyor. Fonksiyonu çağırırken karesini almak 
  istediğimiz sayıyı ve elde edilen değerleri saklamak istediğimiz ve çağrıdan 
  önce tahsis ettiğimiz güvenli adres bölgelerini gönderiyoruz. Fonksiyon çağrısından 
  sonra bu adres bölgelerine erişerek fonksiyondan elde edilen değerleri yazdırıyoruz. 
  Bu şekilde birden fazla sayıda değer döndürmesi gereken fonksiyonların bu şekilde 
  yazılması gerekir. (Ya da bir yapı tanımlayarak geri dönüş değerlerini yapının 
  elemanlarında tutabilirsiniz.)
  
Diziler üzerinde 
  birtakım işlemler yapan fonksiyonlar yazmak istediğimizi düşünelim. Örneğin 
  ilk olarak int türden bir dizinin tüm elemanlarının değerlerini birer artıran 
  bir fonksiyon yazalım. Bunu değer ile çağırma yöntemine göre yazamayız. Diziler 
  her zaman fonksiyonlara referansları ile aktarılır. Bunun yerine dizinin başlangıç 
  adresini ve uzunluğunu parametre değişkeni olarak alıp, fonksiyon içerisinde 
  dizi elemanları üzerinde dolaşarak doğrudan elemanlara erişir ve değerleri güncelleriz. 
  Bu fonksiyonu yazalım :
  
   
    void IslemYap(int 
      *dizi,int uzunluk) 
      { 
          int i;      for (i = 
        0; i < uzunluk; ++i) 
               dizi[i]++; 
        }
      int main() 
        { 
            int i; 
            int dizi[] = {1,2,3,4,5};
  
           printf("dizinin 
        ilk hali :\n"); 
            for (i = 0; i < 5; ++i)  
               printf("%d~",dizi[i]); 
  
           IslemYap(dizi,5);
  
           printf("\ndizinin 
        fonksiyon cagrildiktan sonraki hali :\n"); 
            for (i = 0; i < 5; ++i)  
               printf("%d~",dizi[i]); 
  
           return 0; 
        }
  
     | 
   
 
Bu fonksiyonda, 
  parametre değişkeni olarak int türden bir adres ve bir de uzunluk bilgisi alıyoruz. 
  Fonksiyon bloğu içerisinde bu adresten itibaren uzunluk değeri kadar adım adım 
  ilerliyor ve ilgili adreslerdeki değerleri birer artırıyoruz. Örneğin dizi isminde 
  5 elemanlı bir dizi tanımladık ve fonksiyona bu dizinin başlangıç adresini gönderdik. 
  Hatırlayacağınız üzere C dilinde dizi isimleri, dizilerin başlangıç adreslerini 
  belirtir. Fonksiyondan çıkıldıktan sonra artık dizimizin elemanlarının değerleri 
  birer artırılmış durumdadır. 
  
Bu yazımızda değer 
  ile çağırma ve referans ile çağırma kavramlarına ve ne zaman hangi yöntemi kullanmamız 
  gerektiği konusuna değindik. Sonraki yazılarımızda görüşmek dileğiyle mutlu 
  günler dilerim. 
  
                
                Makale: 
                Değer İle Çağırma - Referans İle Çağırma Kavramları C ve Sistem Programlama Çiğdem Çavdaroğlu 
             | 
        
        
            | 
             | 
        
        
            | 
                 
             | 
        
        
            
                
                
                    
                        - 
                            
                        
 
                        - 
                            
Eklenen Son 10  
                         
                        - 
                            
Bu Konuda Geçmiş 10 
                         
                     
                    
                        
                            Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
                         
                        
                            Son Eklenen 10 Makale Yükleniyor
                         
                        
                            Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
                         
                     
                 
                
                
             | 
        
        
            | 
                
             |