c++ 中的函數調用中的參數傳遞

概述

初學 \(c++\),一直搞不懂其參數傳遞方式。故找到一篇不錯的文章:劉志華的深刻探討C++語言中參數傳遞問題。親自實踐一遍,並做此記錄,以加深印象。
 c++


 

主要內容

本文主要分爲五個小部分,下面依次做總結。
 數組

簡單變量做參數

簡單變量做參數的傳遞方式是按值傳遞,在這種傳遞方式下,在函數體中對形參的修改不會影響實際參數的值,由於它們使用各自的存儲空間。函數

下面即是一個簡單變量做參數的實例。調用 swap 參數同時把 \(x\) 的值傳送給形參 \(a\),把 \(y\) 的值傳送給形參 \(b\),在函數體中對形參 \(a\)\(b\) 的操做是與對應的實參 \(x\)\(y\) 無關的,由於它們使用各自的存儲空間。spa

void swap(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}
int main()
{
    int x=45, y = 12;
    swap(x, y)
    cout<<"x="<<x<<' '<<"y="<<y<<endl;
    return 0;
}

輸出結果是:\(x=45,\, y=12\). 可見在這種傳遞方式下,在函數體中對形參的修改不會影響實際參數的值。指針

 

指針做參數

指針自己是一個變量,特殊之處在於它的值是一個地址,於是能夠經過指針來間接訪問另一個內存地址。當函數的形式是指針時,它的實際參數的值必須是一個地址。因爲指針做形參,所以對應的形參的實參共用同一個內存單元,形參值的改變將影響實參值。下面繼續看一個實例。code

void swap(int* a, int* b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
int main()
{
    int x = 45;
    int y = 12;
    swap(&x, &y);

    cout<<"x="<<x<<' '<<"y="<<y<<endl;

    return 0;
}

輸出結果是:\(x=12,\, y=45\). 可見在這種傳遞方式下,在函數體中對形參的修改將影響實際參數的值。內存

 

引用做參數

因爲引用做形參,所以對應的形參和實參就是同一個內存單元,形參值的改變也將影響實參值。字符串

void swap(int& a, int& b)
{
    int temp = a;
    a = b;
    b = temp;
}
int main()
{
    int x = 45;
    int y = 12;
    swap(x, y);

    cout<<"x="<<x<<' '<<"y="<<y<<endl;

    return 0;
}

輸出結果是:\(x=12,\, y=45\). 可見在這種傳遞方式下,在函數體中對形參的修改將影響實際參數的值。class

引用傳送的好處是不須要爲形參分配新的存儲空間,從而節省存儲,另外就是如實例這樣,可以使對形參的操做反映到實參上。有時,既爲了使形參共享實參的存儲空間,又不但願經過形參改變實參的值,則應當把該形參說明爲常量引用,如:變量

void swap(const int& a, const int& b)

在這種狀況下,只能讀取引用參數 \(a\)\(b\) 的值,不可以修改它們的值,由於它們是對應實參的別名,從而杜絕了對實參的有意或無心的破壞。

 

數組做參數

看下面一個實例。

int sum(int a[], int n)
{
    int f = 1;
    for (int i=0; i<n; i++)
    {
        f *=a[i];
    }
    return f;
}
int main()
{
    const int N = 6;
    int b[N] = {1,2,3,4,5,6};

    int x = sum(b, 6);
    int y = sum(&b[2], 4);
    int z = sum(b+3, 3);

    cout<<"x="<<x<<' '<<"y="<<y<<' '<<"z="<<z<<endl;

    return 0;
}

輸出結果是:\(x=720,\, y=360,\,z=120\).
該函數包含一個主函數和一個 sum 函數,其功能是求出一維整型數組全部元素之積並返回。

  • 在主函數第一次調用 sum 函數時,把數組 \(b\) 的首地址傳送給 \(a\),把數組 \(b\) 的長度 \(6\) 傳送給 \(n\). 執行函數體對數組 \(a\) 的操做實際上就是對主函數中數組 \(b\) 的操做,由於它們同時指向數組 \(b\) 的存儲空間;
  • 第二次調用 sum 函數是把數組 \(b\)\(b[2]\) 元素的地址傳送給 \(a\), 把整數 \(4\) 傳送給 \(n\). 執行函數體對數組 \(a[n]\) 的操做其實是對數組 \(b[2]\)\(b[5]\) 之間元素的操做;
  • 第三次調用 sum 函數是把數組 \(b\)\(b[3]\) 元素的地址傳送給 \(a\), 把整數 \(3\) 傳送給 \(n\), 執行函數體對數組 \(a[n]\) 的操做其實是對數組 \(b[3]\)\(b[5]\) 之間元素的操做。

 

字符串做參數

看下面一個實例。

char* sss(char *sp, char* dp)
{
    if (*sp == '\0')
    {
        *dp = '\0';
        return dp;
    }
    int i=0; // i 是記錄 dp 中字符個數
    int j;
    for (char* p=sp; *p; p++)
    {
        //掃描 sp 所指字符串中的每一個字符位置
        for (j=0; j<i; j++)
        {
            if (*p == dp[j])
                break;  // 當 *p 與 dp[0] 至 dp[i-1] 之間的任一元素相同則比較過程結束
        }
        if (j >= i)
                dp[i++] = *p; // 若 dp 數組的前 i 個元素不等於 *p, 則把 *p 寫入 dp[i] 元素中
    }
    dp[i] = '\0'; // 寫入字符串結束符
    return dp;
}
int main()
{
    char a[15] = "abcdeabcde";
    char b[15];

    char* c1 = sss(a, b);
    cout<<"c1="<<c1<<' '<<"a="<<a<<' '<<"b="<<b<<endl;

    char* c2 = sss(a+4, b);
    cout<<"c2="<<c2<<' '<<"a="<<a<<' '<<"b="<<b<<endl;

    return 0;
}

sss 函數的功能是把 sp 所指向的字符串去掉重複字符後拷貝到 dp 所指向的字符數組中,並返回 dp 指針。在主函數中第一次調用 sss 函數時,分別以 \(a\)\(b\) 做爲實參,第二次調用時分別以 \(a+4\) (即 \(a[4]\) 的地址)和 \(b\) 做爲實參。該程序運行結果是:
\(c1=abcde\,\,a=abcdeabcde\,\, b=abcde\)
 
\(c2=eabcd\,\,a=abcdeabcde\,\, b=eabcd\)

相關文章
相關標籤/搜索