C、C++、java中函數的參數:傳值 or 傳引用


概要:

     教C語言課的過程中,發現很多學生對函數調用中的參數傳遞問題很容易糊塗。跟師弟交流的過程中,也發現大家對這個問題理解不夠透徹。因此,結合本人自己的理解,將函數調用中的傳值與傳引用進行分析總結。

 

一、函數調用中傳遞參數的類型

      傳值(pass by value):即形參接收實參傳遞過來的值,如果是自定義類型,要調用拷貝構造函數。函數處理的是形參的值。

      傳引用(pass by reference):引用表示與原對象完全相同,是同一個對象。若函數的形參是引用,則實參與形參間不存在參數傳遞,且函數內對形參的修改就是修改實參,因為它們是引用關系,是同一個對象。

 

   1、C語言中,傳遞的參數類型只有1個:傳值,包括傳遞普通數值和指針。

   2、C++中,傳遞的參數類型有2個:傳值、傳引用

   3、java中,傳遞的類型只有1個:傳值。

         java中傳的值包括:基本數據類型和對象,其中對象當做指針看待

  三種語言的處理方法相同: 不管傳遞的是普通變量還是指針,都是傳值。對於指針,看函數修改的是指針的值,還是指針所指對象的值就可以了。

 

二、程序示例

1、C++:傳遞的是基本數據類型,包括普通數值、指針和引用

基本數據類型的傳參測試
#include <iostream>
using namespace std;

void swap(int a,int b);
void swapPoint(int *pa, int *pb);
void swapData(int *pa,int *pb);
void swapReference(int &a, int &b);

int main()
{
    int a = 10;
    int b = 20;

    cout<<"main函數中, a=  "<<a<<"  b= "<<b<<endl;

    swap(a,b);
    swapPoint(&a,&b);
    swapData(&a,&b);
    swapReference(a,b);

    cout<<"main函數中, a=  "<<a<<"  b= "<<b<<endl;
    return 1;
}

void swap(int a,int b)
{
    int tmp;
    tmp = a;
    a = b;
    b = tmp;

    cout<<"swap函數中, a=  "<<a<<"  b= "<<b<<endl;
}

void swapPoint(int *pa, int *pb)
{
    int *tmp;
    tmp = pa;
    pa = pb;
    pb = tmp;
    
    cout<<"swapPoint函數中, a=  "<<*pa<<"  b= "<<*pb<<endl;
}

void swapData(int *pa,int *pb)
{
    int tmp;
    tmp = *pa;
    *pa = *pb;
    *pb = tmp;
    
    cout<<"swapData函數中, a=  "<<*pa<<"  b= "<<*pb<<endl;
}

void swapReference(int &a, int &b)
{
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
    
    cout<<"swapReference函數中, a=  "<<a<<"  b= "<<b<<endl;
}

分析:

       void swap(int a,int b)函數,形參a、b分別接受實參傳遞的值,函數處理的是形參a、b,實現交換形參a、b的值

       void swapPoint(int *pa, int *pb)函數,交換的是指針的值,即交換的是形參的指向關系

       void swapData(int *pa,int *pb)函數,交換的是指針所指向的對象,即交換的是實參

2、C++:傳遞的是自定義類型:結構體或者類

類的傳參測試
class Test
{
public:
    int a;

    Test()
    {
        cout<<"Test() 無參構造函數!"<<endl;
    }

    Test(int data)
    {
        a = data;
        cout<<"Test(int data) 有參構造函數!"<<endl;
    }

    Test(const Test &tmp)
    {
        a = tmp.a;
        cout<<"拷貝構造函數!!"<<endl;        
    }
};

void swapClass(Test a, Test b)
{
    Test tmp;

    tmp = a;
    a= b;
    b = tmp;
}

void swapClassReference(Test &a, Test &b)
{
    Test tmp;
    
    tmp = a;
    a= b;
    b = tmp;
}

void swapClassPoint(Test *pa, Test *pb)
{
    Test tmp;
    
    tmp = *pa;
    *pa= *pb;
    *pb = tmp;
}

int main()
{
    Test a(10);
    Test b = 20;

    swapClass(a,b);
//    swapClassReference(a,b);
    swapClassPoint(&a,&b);

    cout<<a.a<<"    "<<b.a<<endl;

    return 1;
}

分析:swapClassReference(Test &a, Test &b)函數,由於是引用,不會出現拷貝構造函數的調用。形參就是實參

        swapClass(Test a, Test b)函數,會調用拷貝構造函數,給a,b分配存儲空間。函數處理的是新定義的形參變量a、b

3、java中的參數傳遞:傳值

     java中出現對象時,把當做指針看待。例如定義了一個類Test,接下來有定義Test tmp ; //類似於c++的指針,沒有調用構造函數

        若Test testc = new Test(); //調用默認構造函數

java中傳參測試
public class Test 
{
    public int data;
    public String name;
    
    public Test()
    {
        System.out.println("調用了無參的構造方法Test() ");
    }
    public Test(int data,String name)
    {
        this.data = data;
        this.name = name;
        System.out.println("調用了有參的構造方法Test(int data,String name) ");
    }
    
    public Test(Test src)
    {
        data = src.data;
        name = src.name;
        System.out.println("調用了拷貝的構造方法Test(Test src) ");
    }
    
    public String toString()
    {
        return "data= "+data+", name= "+name;
    }
    public static void swap(Test a, Test b)
    {
        Test tmp ; //類似於c++的指針,沒有調用構造函數
        tmp = a;
        a = b;
        b = tmp;
    }
    
    public static void modify(Test a)
    {
        a.data += 100;
        a.name +=" is modified!";
    }
    public static void main(String[] args)
    {
        Test testA = new Test(2,"testA");
        Test testB = new Test(5,"testB");
                
        Test.swap(testA, testB);
        Test.modify(testA);
                
        System.out.println("testA: "+testA.toString());
        System.out.println("testB: "+testB.toString());
    }
}

分析:

      主函數中的swap(Test a, Test b)方法,可以證明java中傳遞的值,而不是引用

                    modify(Test a)方法中,之所以可以修改屬性的值,是因為修改的是指針所指的對象。

    總之,java中出現對象時,把當做指針看待

 

三、總結

    1、 C++中傳值(特別是對於自定義類型),會帶來拷貝構造函數執行的開銷,所以執行效率低一點。

              傳引用和傳指針,不執行拷貝構造函數,效率會高

   2、  當用按值傳遞方式傳遞或返回一個對象時,編譯器會自動調用拷貝構造函數!

 

   3、 當指針作為形參時,最好畫出指針所指向的對象。然后分析修改的是指針的值,還是指針所指的對象。

 

(完)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM