2015年7月5日 星期日

參數的傳遞



C 語言在函數間傳遞參數,有 call by value、call by pointer 兩種方式,而 C++ 則多了 call by reference。以下舉例說明這三種方式的差異。

1.call by value - 參數以值傳遞,函式可以存取參數,但不會改變主程式的變數內容。下面的 test() 函式,將於自動產生 int x = a; 之後才進入函式,所以無論test() 中的 x 值如何改變,都不會影響主程式的 a,即使主程式把 int a 改名為 int x,兩者仍是各自獨立的

void test(int x) { 
    x=100; 

}

int main() { 
    int a = 5;
    test(a);
}

2.call by pointer - 參數以變數的"位址值"傳遞(事實上還是傳值),函式可以存取指標參數,不會改變叫用程式的指標本身,但透過*存取指標所指向的空間,可改變指向空間的內容

test1() 於自動產生 int* y = a; 之後進入函式,接著宣告了一個名為 newptr 的 int 指標,然後把參數 y 指標的內容設為 newptr,但返回主程式之後,a 指標的位址並不受影響,*a 的值仍指向 5 而非 100。call by pointer 其實仍是以值的方式來傳遞,只是傳的是個位址值(指標)

#include <iostream>
using namespace std;

void test1(int* y) {
    int* newptr=new int(100);
    y = newptr;
    cout << y << ":" << *y << endl;
}

int main() { 
    int* a=new int(5);
    test1(a);
    cout << a << ":" << *a << endl;
    return 0; 
}

而 test2() 於自動產生 int* y = a; 之後進入函式,此時 *y 與 *a 是指向同一位置,所以執行 *y=50; 就等於改變了 *a,而 y=NULL 則對 a 並無影響

#include <iostream>
using namespace std;

void test2(int* y) {
    *y=50;
    y=NULL;
}

int main() { 
    int* a=new int(5);
    test2(a);
    cout << a << ":" << *a << endl;
    return 0;
}

這也是 call by pointer 又被稱為 call by address 的原因,在還沒有 reference 之前,函式都是使用此方式來修改"指標參數所指向的內容"。

3.call by reference - reference 的符號是 &,此方式直接把主程式的變數交給函式使用,中間沒有隱含自動產生 int x = a; 或 int* y = a; 這類的步驟。以 call by reference 傳遞的參數,若無 const 修飾,函式中對參數內容的任何改變,就等於直接在改變主程式所對應的變數內容

#include <iostream>
using namespace std;

void test3(int (&x)[3], int& y) { //(&x)必需括號,因為[]比&優先權高 
    x[0]=4;
    x[1]=5;
    x[2]=6;
    y=0; 
}

int main() { 
    int a[] = {1,2,3}; 
    int b=100;

    test3(a,b);

    cout << a[0] << " " << a[1] << " " << a[2] << endl;
    cout << b << endl;
    return 0; 
}

由於 call by reference 傳遞快速(尤其是在傳遞物件時),函式中的程式碼亦比較簡明,所以常被程式設計師採用,若要保持 call by value 的安全性避免函式更動到主程式的變數內容,可在參數前加上 const 常數修飾字即可。

沒有留言:

張貼留言