محمد حسن پزشکیان
عاشق امنیت و نفوذ ، رد تیم و دوستدار بزن بکش :)

تفاوت بین Call By Refrence و Call By Value چیست؟

در این مطلب میخوایم اول به بررسی تفاوت بین Argument و Parameter بپردازیم بعد تفاوت بین Call By Refrence و Call By Value رو در زبان های برنامه نویسی بررسی کنیم

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران

تفاوت بین آرگومان (Argument) و پارامتر (Parameter) چیست؟

در زبان های برنامه نویسی اگر ما بخوایم یه تابعی رو صدا بزنیم و مقادیری رو بهش بفرستیم چند تا اصطلاح داریم :

def sum(p,o):
sum=p+o
return sum

a=int(input("1st Num: "))
b=int(input("2nd Num: "))
print(sum(a,b))

در اینجا اگر دقت کنید وقتی که ما میخوایم یه تابعی رو صدا بزنیم یه مقادیری رو بهش اصطلاحا پاس میدیم (Pass) و در اینجا دوتا اصطلاح هست ، مقادیر a و b ای که ما میخوایم پاس بدیم و در حال فرستاده شدنه میشه ارگومان ، و مقادیری که داخل تابع دریافت میشه و روش پردازش انجام میشه ، پارامتر نام میگیره ، یعنی p و o در خط 1 پارامتر هستن و a و b در خط 7 ارگومان هستن (این مفهوم در تمامی زبان های برنامه نویسی وجود داره)

تفاوت بین Call By Refrence و Call By Value چیست؟

در زبان های برنامه نویسی ما یه مفهوم داریم ، و اونم اینه که ارگومانی که ما پاس میدیم به تابع ، وقتی تابع اون پارامتر رو میگیره و روش عملیات انجام میده داخل خودش، روی مقادیر اون پارامتر تغییری اعمال کنه و ارگومانم عوض بشه به این نوع پاس دادن میگن call by refrence و اگر مقادیر ارگومان و پارامتر متفاوت باشن میشه call by value ، به زبانی دیگر : اگر ما موقعی که میخوایم مقادیر رو پاس بدیم به تابع ، از مقادیر کپی بگیریم و کپی اونو بدیم به تابع ، این روش میشه  call by value ولی اگر بیاییم به تابع آدرس مقادیر اصلی رو بدیم ، چون تابع متغییر هارو از مقادیر اصلی میخونه ، هر تغییری توی تابع روی متغییرا ایجاد بشه مستقیما روی مقادیر اصلی اثر میزاره و این روش میشه call by refrence

پس اگر خود متغیرو پاس بدیم میشه call by value اگر ادرساشونو پاس بدیم میشه call by reference

تفاوت بین Call By Refrence و Call By Value چیست؟

در زبان ++c

مثلا ما به صورت پیشفرض مقادیر رو به صورت Call by Value انتقال میدیم :

#include <iostream>
using namespace std;

int sum (int x){
    x = 10 + x;
    return(x);
    }
int main()
{
  int x = 5;
    cout << "The result of 10 + " << x << " is " << sum(x) << endl;
    cout << "Value of x is still " << x;
  cin.ignore();
}
--------------------------------------------
The result of 10 + 5 is 15
Value of x is still 5

مثلا اینجا ما یه برنامه داریم که متغییر x رو ک عدد 5 رو پیشفرض در خودش داره و میاییم و به تابع sum پاسش میدیم و با عدد 10 جمع میکنه که میشه 15 ، بعد پارس دادنش دوباره با مقدار x رو چاپ میکنیم و باز میشه 5 ، یعنی مقدار x ای که داخل تابع sum شده 15 یه مقدار کاملا جداییه از x خارج ، درواقع دوتا x داریم که در هر Local Variable حساب میشن و مقادیرشون در تابع های خودشون متفاوته

در زبان پایتون

روش کار ما Call by refrence هست و چون ما شئ داریم ، این شئ ها به دو دسته تقسیم میشن :

Mutable objects یا اشئای قابل تغییر : اگر شئ قابل تغییر باشه ، مقداری که تغییر میکنه خارج از تابع هم قابل دسترسه (list, dict, set)

Immutable objects یا اشیای غیر قابل تغییر: اگر شئ غیر قابل تغییر باشن پس مقداری که تغییر میکنه خارج از تابع قابل دسترس نیست (int, float, complex, string, tuple)

مثال از اشیاء قابل تغییر :

def add_more(list):
    list.append(50)
    print("Inside Function", list)
 

mylist = [10,20,30,40]
 
add_more(mylist)
print("Outside Function:", mylist)
----------------------------------
Inside Function [10, 20, 30, 40, 50]
Outside Function: [10, 20, 30, 40, 50]

در اینجا ما یه لیست داریم که قابل تغییره ، و وقتی ما یه عضو جدید (در اینجا 50) رو اضافه میکنیم به این لیست داخل لیست درون و تابع و بیرون تابع اضافه میشه (درواقع call by refrence کردیم)

ولی اشیاء غیر قابل تغییر :

string = "Hi"
 
def test(string):
  string = "hello"
  print("Inside Function:", string)

test(string)
print("Outside Function:", string)
---------------------------------
Inside Function: hello
Outside Function: Hi

در اینجا چون رشته غیر قابل تغییر هست پس ما دو مقدار متفاوت در داخل و خارج تابع داریم (انگار call by value کردیم)

call by refrence در ++c

نکته : توی cpp هم میشه این کارو انجام داد ، اما با پوینتر ها ما میتونیم یه call refrence درست کنیم به وسیله پاس دادن پوینتر بعنوان ارگومان به تابع ، بجای فرستادن خود ارگومان

قبلش کمی درباره پوینتر ها توضیح بدم : پوینتر متغییره که میتونه موقعیت مکانی یا مقدار یه متغییر دیگرو در خودش بگیره ، اگر متغییری اینطوریه نوشته بشه :

 x = &y; 

یعنی مکان متغیرy باید ریخته بشه توی x ولی اگر

 x = *y; 

اینطوری باشه باید مقدار خود متغیر y ریخته بشه تو x

حالا من به دو طریق با پوینتر ها call by refrence میکنم تو cpp :

#include <iostream> 
using namespace std; 
void swap(int& x, int& y)
{
     int temp;
     temp =  x;
      x =  y;
      y = temp;
}
int main ()
{
    int i, j;
    i = 5;
    j = 10;
    cout << "Before swap i is: " << i << " and j is: " << j <<endl;    
    swap(i,j);
    cout << "After swap i is: " << i << " and j is: " << j;
    cin.ignore();
    return 0;
 } 
-------------------------------------------
Before swap i is: 5 and j is: 10
After swap i is: 10 and j is: 5
#include <iostream> 
using namespace std; 
void swap(int *x, int *y)
{
     int temp;
     temp = *x;
     *x = *y;
     *y = temp;
}
int main ()
{
    int i, j;
    i = 5;
    j = 10;
    cout << "Before swap i is: " << i << " and j is: " << j <<endl;    
    swap(&i,&j);
    cout << "After swap i is: " << i << " and j is: " << j;
    cin.ignore();
    return 0;
 } 
--------------------------------
Before swap i is: 5 and j is: 10
After swap i is: 10 and j is: 5

خیلی درگیر کدش نمیخوام بشم ولی جفتشون یه کارو میکنن ولی به طور خلاصه علامت & قبل اسم متغییرا یعنی قراره تو یه پوینتر بگیری بجای مقدار ارگومان ، جفتشون اول میان i  و j رو پاس میدن به void و x میشه i و y میشه j ، پس x = 5 و y = 10 بعد که داخل تابع void ما کارمونو انجام میدیم ، اول temp میشه مساوی x یعنی temp=5 بعد x=y میشه یعنی مقدار y ریخته میشه تو x که جفتشون میشن 10 ، بعد y=temp میشه که مقدار temp یا همون 5 ریخته میشه تو y که در نهایت y میشه 5 ، یعنی الان x=10 و y=5 شده و از اونجایی ک x=i و y=j بوده پس مقادیرشون بعد رفتن تو تابع توسط پوینترا جابجا شده

مبحث تقریبا سختیه ، یکم کد بزنید و بهش فکر کنید ، اگر سوال داشتید در خدمتم :)


محمد حسن پزشکیان
محمد حسن پزشکیان

عاشق امنیت و نفوذ ، رد تیم و دوستدار بزن بکش :)

کارشناس تست نفوذ سنجی ، علاقه مند به امنیت تهاجمی و رد تیمینگ | عضو انجمن بین المللی ورزش های رزمی کشور آلمان و دارای احکام بین المللی و داخلی کمربند مشکی در سبک های کیوکوشین ، هاپکیدو ، کیک بوکسینگ و چند تام قهرمانی کشوری

17 شهریور 1400 این مطلب را ارسال کرده

نظرات