32 - Call By Reference ve Call By Value
Fonksiyonlara veri geçirilirken iki method kullanılır: referans ile çağırma methodu ve değer ile çağırma methodu. Bu methodlar ayrıca pass-by-reference ve pass-by-value olarak da isimlendirilirler.
Call by value methodunda data fonksiyona geçirildiğinde geçirilen verinin bir kopyası oluşturulur. Çağrılan fonksiyon bu kopya ile çalışırken geri dönüşte çağıran fonksiyondaki asıl değişken, çağrılan fonksiyondaki yapılan işlemler nedeniyle oluşan değişikliklerden etkilenmez. Bu değişiklik sadece kopya üzerinde ve çağrılan fonksiyon içinde meydana gelir.
Öncelikle burada hem call_by_calue fonksiyonunun içindeki değişkenin ismi x hem de main fonksiyonunun içindeki değişken ismi x. Ancak ikisi birbirinden tamamen farklı. Çünkü her değişken tanımlandığı yerde geçerlidir. Sadece birbirleri arasında değer alışverişi olabilir. Aynı isimli fonksiyon tanımladığımızda iki fonksiyonda da aynı değişikliğin geçerli olmasını bekleyemeyiz. Örneği çalıştırdığımızda da bu görülüyor.
Burada call_by_value fonksiyonuna x değişkenini geçirdiğimizde bir kopyası oluştu ve fonksiyonun başlangıcına yerleştirildi gibi düşünebiliriz. Fonksiyonun başında bu değişkeni yazdırdığımızda maindeki ile aynı değeri görürüz çünkü henüz bir etki olmadı. Daha sonra 10 ekleyip tekrar yazdırdığımızda değişikliği göreceğiz. Bu konunun mantığı bu adımdan sonra ortaya çıkıyor. Burada değişikliği yaptık, fonksiyon sonlandı ve maine geri döneceğiz. Burada tekrar yazdırdığımızda hangi değeri göreceğimiz bu methodların farkını gösteriyor. Burada ilk değer olan 10 değerini göreceğiz. Çünkü call_by_value değişkeni içindeki değişiklik kopya değeri etkiledi ve geri döndüğümüzde main asıl değişken ile yoluna devam etmiş oldu.
Call by reference methodunda ise fonksiyona değerin kendisi değil adresi geçirilir. Adres call by value methodu ile çalışmaya devam eder. Ancak adresin içeriğinde bir değişiklik olursa mainde bu etkiyi görürüz. Çünkü call by value methoduna göre adresin kendisinde bir değişiklik olsa mainde etkilenmezdi. Şimdi ise adres kaybedilmediği sürece adresin içerisi değiştiğinde o adresi bilen her birim o değişikliği görebilecektir.
Bu örneği çalıştırdığınızda fonksiyon çağrıldıktan sonra değişikliğin maindeki değişkeni de etkilediğini görüyoruz. Burada fonksiyona bir adres gönderiyoruz ve fonksiyonun içinde o adresin içeriğini değiştiriyoruz. Fonksiyon bittiğinde maine dönüldüğünde yine o adresin içeriğini kontrol ediyoruz. Bu da bize bir veriyi bir fonksiyon ile güncellememize olanak sağlıyor.
Bu methodlardan hangisini kullanacağımız ise ihtiyaçlara göre belirlenmekte. Bir fonksiyonun geçirilen değişkeni etkilemesini istemiyorsak call by reference bizi hataya açık hale getirecektir. Çünkü hatayla değişkeni fonksiyon içinde güncellersek call by value fonksiyon dönüşünde asıl değeriyle devam ederek hatanın önüne geçmiş olur.
Bir diğer dikkat edilmesi gereken konu ise pointer kullandığımızda bu pointerın gerçekten geçerli bir değeri olup olmadığı kontrol edilmesidir. Ben burada çok basit bir kod parçası yazdığım için eklemedim ancak main fonksiyonu değiştiğinde ve benim farketmediğim bir şekilde b fonksiyonunun null değer alması durumunda program sonlanacaktır. Halbuki fonksiyonun başına şu satırları eklemek bir hata mesajı alıp durumu fark etmemizi sağlayacaktır.
Call by value methodunda data fonksiyona geçirildiğinde geçirilen verinin bir kopyası oluşturulur. Çağrılan fonksiyon bu kopya ile çalışırken geri dönüşte çağıran fonksiyondaki asıl değişken, çağrılan fonksiyondaki yapılan işlemler nedeniyle oluşan değişikliklerden etkilenmez. Bu değişiklik sadece kopya üzerinde ve çağrılan fonksiyon içinde meydana gelir.
#include <stdio.h>
void call_by_value(int x) {
printf("Fonksiyon icinde degisiklikten once x = %d \n", x);
x += 10;
printf("Fonksiyon icinde degisiklikten sonra x = %d \n", x);
}
int main()
{
int x = 10;
printf("Fonksiyon cagrilmadan once ana fonksiyonda x = %d \n", x);
call_by_value(x);
printf("Fonksiyon cagrildiktan sonra ana fonksiyonda x = %d \n", x);
return 0;
}
Öncelikle burada hem call_by_calue fonksiyonunun içindeki değişkenin ismi x hem de main fonksiyonunun içindeki değişken ismi x. Ancak ikisi birbirinden tamamen farklı. Çünkü her değişken tanımlandığı yerde geçerlidir. Sadece birbirleri arasında değer alışverişi olabilir. Aynı isimli fonksiyon tanımladığımızda iki fonksiyonda da aynı değişikliğin geçerli olmasını bekleyemeyiz. Örneği çalıştırdığımızda da bu görülüyor.
Burada call_by_value fonksiyonuna x değişkenini geçirdiğimizde bir kopyası oluştu ve fonksiyonun başlangıcına yerleştirildi gibi düşünebiliriz. Fonksiyonun başında bu değişkeni yazdırdığımızda maindeki ile aynı değeri görürüz çünkü henüz bir etki olmadı. Daha sonra 10 ekleyip tekrar yazdırdığımızda değişikliği göreceğiz. Bu konunun mantığı bu adımdan sonra ortaya çıkıyor. Burada değişikliği yaptık, fonksiyon sonlandı ve maine geri döneceğiz. Burada tekrar yazdırdığımızda hangi değeri göreceğimiz bu methodların farkını gösteriyor. Burada ilk değer olan 10 değerini göreceğiz. Çünkü call_by_value değişkeni içindeki değişiklik kopya değeri etkiledi ve geri döndüğümüzde main asıl değişken ile yoluna devam etmiş oldu.
Call by reference methodunda ise fonksiyona değerin kendisi değil adresi geçirilir. Adres call by value methodu ile çalışmaya devam eder. Ancak adresin içeriğinde bir değişiklik olursa mainde bu etkiyi görürüz. Çünkü call by value methoduna göre adresin kendisinde bir değişiklik olsa mainde etkilenmezdi. Şimdi ise adres kaybedilmediği sürece adresin içerisi değiştiğinde o adresi bilen her birim o değişikliği görebilecektir.
#include <stdio.h>
void call_by_reference(int *b) {
printf("Fonksiyon icinde degisiklikten once b = %d \n", *b);
(*b) += 10;
printf("Fonksiyon icinde degisiklikten sonra b = %d \n", *b);
}
int main() {
int b = 10;
printf("Fonksiyon cagrilmadan once ana fonksiyonda b = %d \n", b);
call_by_reference(&b);
printf("Fonksiyon cagrildiktan sonra ana fonksiyonda b = %d \n", b);
return 0;
}
Bu örneği çalıştırdığınızda fonksiyon çağrıldıktan sonra değişikliğin maindeki değişkeni de etkilediğini görüyoruz. Burada fonksiyona bir adres gönderiyoruz ve fonksiyonun içinde o adresin içeriğini değiştiriyoruz. Fonksiyon bittiğinde maine dönüldüğünde yine o adresin içeriğini kontrol ediyoruz. Bu da bize bir veriyi bir fonksiyon ile güncellememize olanak sağlıyor.
Bu methodlardan hangisini kullanacağımız ise ihtiyaçlara göre belirlenmekte. Bir fonksiyonun geçirilen değişkeni etkilemesini istemiyorsak call by reference bizi hataya açık hale getirecektir. Çünkü hatayla değişkeni fonksiyon içinde güncellersek call by value fonksiyon dönüşünde asıl değeriyle devam ederek hatanın önüne geçmiş olur.
Bir diğer dikkat edilmesi gereken konu ise pointer kullandığımızda bu pointerın gerçekten geçerli bir değeri olup olmadığı kontrol edilmesidir. Ben burada çok basit bir kod parçası yazdığım için eklemedim ancak main fonksiyonu değiştiğinde ve benim farketmediğim bir şekilde b fonksiyonunun null değer alması durumunda program sonlanacaktır. Halbuki fonksiyonun başına şu satırları eklemek bir hata mesajı alıp durumu fark etmemizi sağlayacaktır.
void call_by_reference(int *b) {
if (b == NULL)
{
printf("Hata!!!! \n");
return;
}
printf("Fonksiyon icinde degisiklikten once b = %d \n", *b);
(*b) += 10;
printf("Fonksiyon icinde degisiklikten sonra b = %d \n", *b);
}
Here all content so useful and helpful for beginner and experience both.This site is so amazing, This sites gives good knowledge of c-cpp-training ,This is very helpful for me.
YanıtlaSil