程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 更多關於編程 >> C#中按引用傳遞與按值傳遞的區別,以及ref與out關鍵字的用法詳解

C#中按引用傳遞與按值傳遞的區別,以及ref與out關鍵字的用法詳解

編輯:更多關於編程
    以下是對C#中按引用傳遞與按值傳遞的區別,以及ref與out關鍵字的用法進行了詳細的分析介紹,需要的朋友可以過來參考下   復制代碼 代碼如下:
    /給三個整數從小到大排序並求和及其平均值
    //其中,三個待求整數及其排序的結果由引用參數傳遞;其和由輸出參數傳遞;平均值由返回值返回。
    //在Main()方法中實現三個待求整數的輸入及結果的輸出
    //目的:定義方法;調用方法;;理解形參和實參的引用傳遞關系;熟悉引用參數和輸出參數的使用。
    using System;
    class Class1
     {
       //x,y,z是形參,按值傳遞
       static void Sort(int x, int y, int z)
        {
          int temp=0;
          if(x>y)
           {
             temp=x;
             x=y;
             y=temp;
           }
          if(y>z)
           {
             temp=z;
             z=y;
             if(x>temp)
              {
                y=x;
                x=temp;
              }
             else
              {
                y=temp;
              }
           }
           Console.WriteLine("The sorted list is {0},{1},{2}",x,y,z);
           x=x+y+z;
        }

       //i,j,k,total是形參,按引用傳遞(ref參數,out參數,都是按引用傳遞的方式)
       static double Average(ref int i, ref int j, ref int k, out int total)
        {
          double l = 0;
          total = i+j+k;
          i=total;
          l=(double)(total/3.0);
          return l;
        }

       static void Main()
        {
          //a,b,c是實參,將要賦值給形參i,j,k,total;
          int a, b, c;

          //聲明out參數result,可以不用初始化它
          int result;

          Console.Write("Please enter the first number a =");
          a = Convert.ToInt32(Console.ReadLine());
          Console.Write("Please enter the second number b =");
          b = Convert.ToInt32(Console.ReadLine());
          Console.Write("Please enter the third number c =");
          c = Convert.ToInt32(Console.ReadLine());     

          Sort(a,b,c);

          //Sort(int x, int y, int z)函數中,形參x,y,z是按值傳遞的,所以即使函數中有x=x+y+z;函數      //執行後實參a值不變。
          Console.WriteLine("The original value of /"a/" is {0}, it hadn't been changed in spite "+"of manipulating the Sort() method, because it is transmitted by a Value para /"x/"!",a);

          //Average(ref int i, ref int j, ref int k, out int total)函數中,形參a,b,c,result都是        //按引用傳遞的,執行後實參a值改變。
          Console.WriteLine("The average result is {0}",Average(ref a,ref b,ref c, out result));
          //ref參數在調用方法前必須幾經初始化。
          //而out參數在調用方法前可以沒有初始化,他們都以引用傳遞方式傳遞

          Console.WriteLine("The value of /"a/" has been changed due to the Average() method"    +" is manipulated, and it is transmitted by a ref para /"ref i/"! now it is {0}!",a);

          Console.ReadLine();
        }
     }


    問題與解答:

    1,值傳遞時,為什麼被調用的方法中的形參值的改變不會影響到相應的實參?
    答:因為按值傳遞時,系統首先為被調用的方法的形參分配內存空間,然後把實參中的值按位置一一對應“復制”給形參。形參中存儲的值只是一份實參的拷貝,因此被調用方法中形參值的任何改變都不會影響到相應的形參。

    2,值傳遞和引用傳遞有什麼不同,什麼是值參數,它以什麼方式傳遞?
    答:值 傳遞時,系統首先為被調用方法的形參分配內存空間,並將實參的值按位置一一對應地復制給形參,此後,被調用方法中形參值得任何改變都不會影響到相應的實 參; 而引用傳遞時,系統不是將實參本身的值復制後傳遞給形參,而是將其引用值(即地址值)傳遞給形參,因此,形參所引用的該地址上的變量與傳遞的實參相同,方 法體內相應形參值得任何改變都將影響到作為引用傳遞的實參。

    3,什麼是形參,什麼是實參?
    答:
    形參:
    在定義函數中指定的參數就是形參,在未出現函數調用時,他們並不占內存中的存儲單元,只有在發生函數調用時,函數中的形參才被分配內存單元。在調用結束後,形參所占的內存單元也被釋放。

    實參:實參可以是常量、變量和表達式,但要求有確定的值。在調用時將實參的值賦給形參。在內存中,實參單元和形參單元是不同的單元。在調用函數時,給形參分配存儲單元,並將實參對應的值傳遞給形參,調用結束後,形參單元被釋放,實參單元仍保留原值。

    理解:
    實參就是送進去方法中的東西~~行參就是把送進來的東西在方法中進行拷貝加工,加工完後方法就返回一個東西--返回值。

    值傳遞的時候,實參是不變的~形參是隨著計算而變化的~~
    指針/引用傳遞的時候~~行參怎麼變~實參就怎麼變.... 

    參數的傳遞分為:1.值方式參數傳遞,2.引用方式參數傳遞。
    1)按值傳遞(不能改變實參)
    實參是變量,表達式等數值。

    函數調用的時候,實參和形參存在於內存中2快不同的區域,實參先自己復制一份拷貝,再把拷貝傳給形參。由於是傳遞的是拷貝,所以實參不會受形參的影響,實參值不會被改變。

    2)按地址傳遞(可以改變實參)
    實參是指針/引用。

    函數調用的時候,指針傳給你,形參和實參指針都一樣,對形參的任何操作就等於對實參的操做。實參的值就可以被改變。

    對參數的影響:
    2種數據類型:值類型+引用類型
    2種傳參方式:值傳參+引用傳參(ref與out關鍵字);

    以上的四種參數的組合 除了值傳參方式傳遞值類型數據,其他的組合方式對參數的操作都會影響參數,都會改變!

    值類型:簡單類型(int,float,double,long,char,bool)+結構+枚舉
    存儲結構:數據存放在棧中(棧:先進後出;單入口,單出口);效率高
    賦值方式:傳的是值

    引用類型:除去簡單類型(int,float,double)+結構+枚舉以外的類型都是引用數據類型。如string;object;類;數組;委托;接口...
    存儲結構:棧中存地址;堆中放數據;
    賦值方式:傳的是數據的地址。

    形參:全稱為"形式參數"是在定義函數名和函數體的時候使用的參數,目的是用來接收調用該函數時傳入的參數.
    實參:全稱為"實際參數"是在調用時傳遞個該函數的參數.

    形參和實參的類型必須要一致,或者要符合隱含轉換規則,
    當形參和實參不是指針類型時(即不是按引用傳遞,而是按值傳遞時),
    在該函數運行時,形參和實參是不同的變量,
    他們在內存中位於不同的位置,形參將實
    參的內容復制一份,在該函數運行結束的時候形參被釋放,
    而實參內容不會改變.

    而如果函數的參數是指針類型變量(按引用傳遞),在調用該函數的過程
    中,傳給函數的是實參的地址,在函數體內部使用的也是
    實參的地址,即使用的就是實參本身.所以在函數體內部
    可以改變實參的值.

    按引用傳遞最大的用途是實現“操作符”重載!

    ref參數與out參數的區別在於:ref參數在調用方法前必須幾經初始化。而out參數在調用方法前可以沒有初始化,他們都以引用傳遞方式傳遞

    C++有了“引用傳遞”後,“形參的改變不影響實參”被判無效。因為傳遞給函數的並不是一個值,而是變量自身。在函數中定義的形參雖然還是局部變 量,但卻是一個引用。雖然這個引用的作用域僅限於函數內部,但是由於它與實參就是同一回事,所以對它的操作完全等同於對實參的操作。比如你叫“黑旋風”去 買魚,或者叫“鐵牛”去買魚,去的都是同一個人。

    C++為什麼要有“引用傳遞”這回事?一種說法是只有引用才能達到操作符重載的目的,這個以後再談。但是,撇開這個不談,形參是不是引用,直接影響 了程序執行的效率。前面提到過,函數調用時要用實參的值去初始化形參,初始化的過程包含了定義一個變量、然後給它賦一個值兩個過程,如果這個變量並不是內 部變量,而是一個類對象,那麼,定義一個類對象可能很復雜,而初始化這個對象一樣會很復雜。而引用只是給對象取一個別名,不涉及定義與初始化,離開作用域 時也不用釋放。

    相比之下,用指針傳遞可以避免類對象的定義、初始化與釋放。只需要付出指針變量的定義、初始化與釋放的代價。但是,指針的殺傷力太大。即使是熟練的程序員,也不能保證絕不出現“野指針”,野針的代價幾乎無一例外是程序崩潰。

    引用也不是吃素的,如果說指針傳遞是“幫你配了一把我家的鑰匙”,那麼引用傳遞就是直接把我家的財產都交給了你。有時,我們使用引用傳遞僅僅是為了 效率,而不希望實參被修改,那就要記得把形參標記為const,如“UINT GetLength(const CString&)”。

    順便說一句,指針傳遞也可以這樣做。把形參定義為指向const對象的指針(而不是const指針),可以降低殺傷力,保護實參所對應的內存。如果 是普通的值傳遞,那麼有沒有const對函數外部並不影響。但是,我個人認為,有時候加上const也是一件好事。如果程序的邏輯並不需要改變參數,而實 際上誤寫了代碼,加上const可以讓編譯器幫我們找出BUG。

    1. 上一頁:
    2. 下一頁:
    Copyright © 程式師世界 All Rights Reserved