1. 程式人生 > >【C++】函式的形參

【C++】函式的形參

前言

       這些天又在複習C++,溫故知新,每次看書都會發現一些之前被自己忽視掉的知識點,所以,學習是不能止步的!

      作為一種程式語言,C++最重要的兩個部分就是函式和變數,這兩者之間進行溝通便是通過引數傳遞,而引數傳遞有很多需要注意的細節,今天就來講講引數傳遞的問題。

      總的來說,引數傳遞的過程,就是初始化函式形參的過程。

按值傳遞

      按值傳遞是最直接也是最容易理解的引數傳遞方式,其形式如下;

void fun(int x,int y){...表示式;}    //定義;
fun(a,b);                           //呼叫

      當進行呼叫的時候,將引數的值通過拷貝賦值給形參,形參的值在函式體內進行各種計算時,並不影響函式外實參的值,形參值的改變與實參無關;

      傳值過程是這樣的;

int y = b; int x = a;

     下面這個例子就說明了這點;

#include<iostream>

using namespace std;
void swap(int, int);
void main()
{
    int a(5), b(10);
	
    swap(a, b);
    cout <<"a="<< a << " , "<<"b=" << b << endl;
    system("pause");
    return;
}

void swap(int x, int y)
{
    int temp;
    temp = x; x = y; y = temp;
    cout << "按值傳參" << endl;
    cout <<"x="<< x << " , " <<"y="<< y<<endl;
}

        雖然a與b的值被傳遞進入了swap(),在swap內,形參的值進行交換,但是外部a與b的值並沒有交換。

        注:形參的建立是自右往左的,也就是先建立y,再建立x,而函式結束時,刪除的順序與之相反。

按地址傳遞(指標形參)

      按地址傳遞是用變數的地址初始化形參,這時候的形參是一個指標,其形式如下;

void fun(int* x,int* y){...表示式;}    //定義;
fun(&a,&b);                           //呼叫;

      在傳參過程中,形參初始化的操作如下;

int *y = &b; int *x= &a;

       這時候重新定義swap()函式,會發現a,b的值被修改了,因為,函式通過指標修改了指標指向的物件的值,這就修改了a,b本身。

#include<iostream>

using namespace std;
void swap1(int*, int*);
void main()
{
    int a(5), b(10);
    swap1(&a, &b);
    cout <<"a="<< a << " , "<<"b=" << b << endl;
    system("pause");
    return;
}

void swap1(int* x, int* y)
{
    int temp;
    temp = *x; *x = *y; *y = temp;
    cout << "按地址傳參" << endl;
    cout << "*x=" << *x << " , " << "*y=" << *y << endl;
}

按引用傳遞

      眾所周知,對於引用的操作就是對物件本身的操作,引用是被引用物件本身的一個“別名”,按引用傳遞引數與引用類似,形參成為了實參的一個“別名”,它的形式如下;

void fun(int &x,int &y){...表示式;}    //定義;
fun(a,b);                           //呼叫;

       形參初始化的操作如下;

int &y = b; int &x= a;

       可以想見,當按引用傳值時,在函式中修改形參的值時,實參的值也被修改了,事實也正是如此。

#include<iostream>

using namespace std;
void swap2(int&, int&);
void main()
{
    int a(5), b(10);
	
    swap2(a, b);
    cout <<"a="<< a << " , "<<"b=" << b << endl;

    system("pause");
    return;
}
void swap2(int& x, int& y)
{
     int temp;
     temp = x; x = y; y = temp;
     cout << "按引用傳參" << endl;
     cout << "x=" << x << " , " << "y=" << y << endl;
}

優勢

避免進行拷貝操作

      雖然在我們的例子中都用的是簡單的int型別,但是在實際使用中,常常需要傳遞很大的容器物件,或者是大的類型別物件,這些時候需要呼叫拷貝建構函式進行傳參,效率低下,通過引用可以很好的避免這一點,大大地節約計算時間和計算資源。

用於返回資訊

我們知道,一個函式一次只能返回一個值,當需要通過函式知道多個變數的資訊是,僅僅有返回值是不夠的,引用形參為我們提供了很好的渠道,通過引用可以獲得函式計算後的各個值,甚至不需要接收函式的返回值。

陣列形參

      與普通變數一樣,陣列也可以作為函式的形參。但是在《【C++】細說C++中的陣列之“靜態”陣列》中我們提到過,陣列是不允許被拷貝的,因此我們不能以傳值的形式使用陣列形參,所以改換成傳地址的方式向函式傳遞陣列實參的資訊。

      當且僅當用於函式頭或者函式原型時,int *arr與int arr[]是含義相同的,他們都意味著arr是一個指標。所以下面三者是等價的;

int* multi(int a[],int m);
int* multi(int *a,int m);
int* multi(int a[10],int m);

       將陣列作為形參時,其實是將陣列首元素的地址,包含元素的種類,以及元素的數目提交給了函式,有了這些資訊後,函式就可以使用陣列的資訊了。但是,也有一些問題需要注意,當我們有一個數組時,可以獲得陣列的大小(利用sizeof()函式),但是當它轉化成指標後,我們沒法獲得它的大小,所以常常顯示地向函式傳遞陣列的大小;

#include<iostream>
using namespace std;
 
int* multi(int a[], int, int);
void main()
{
    int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    
    int *arr1 = multi(arr,10,10);
    cout << arr1[3]<<endl;
    system("pause");
    return;
}
int* multi(int a[],int len,int m)
{
    
    for (int i = 0; i < len;i++)
    {
        a[i] *= m;
    }
    return a;
}

陣列引用形參

      變數可以定義成陣列的引用,形參也同樣可以,   

int* multi(int (&a)[10],int m);
//注:&a兩端的括號不能少,因為[]的優先順序更高;C++也不允許引用的陣列。其次,必須給定陣列的大小,這在一定程度上限制了函式的使用。

多維陣列作為形參

      與陣列一樣,多維陣列也可以作為形參傳遞給函式,與一維陣列一樣,傳遞的也是陣列首元素的地址。因為處理的是陣列的陣列,所以首元素本身是一個數組,指標指向的是一個數組,因此第二維的陣列的大小不能被省略。

int* multi(int (*a)[10],int m);

//注:*a兩端的括號不能掉,因為[]的優先順序更高如果失去了括號,那麼int *a[10]表示的是包含十個int型別指標的陣列。而前者表示a是一個指標,指向含有十個元素的陣列。

帶預設值的形參

      很多情況下都要用到預設值的形參,例如OpenCV中的很多函式都使用了預設形參,這樣使得函式更加靈活好用。
當函式提供了形參的預設值,形參就不是必須要從實參獲得值,那麼在函式呼叫時,也不是必須提供與形引數一致的實參。
       形參與實參匹配是從左到右的,第一個形參與第一個實參匹配,第二個形參與第二個實參匹配。因此,指定預設值的形參必須放在形參列表的最右側,或者說,在帶預設值的形參的右邊,不允許出現無預設值的形參;

int add(int x = 10, int y = 20){...表示式;}

add();
add(a);
add(a, b);

float f1(float a,float b=1,float c,float d=0);    //錯誤
float f1(float a,float b,float c=1,float d=0);    //正確

      這裡也只是簡單的列舉了一下C++中形參和引數傳遞的內容,還有很多複雜的內容需要在專案實踐中去了解,但是萬變不離其宗,這些東西是我們必須掌握的。

已完。。