很久沒有寫博了,今天一個同學在問結構變量的問題,問結構到底是傳遞值還是傳遞引用。查過MSDN的都知道,結構默認是傳遞值的,因此在方法內部,結構的值會被復制一份。但是對於結構數組,如果值還是要被復制一份,這個內存占用是不是很多了呢?
一般來說,數組參數傳遞的是引用,那么數組的元素呢?它是被復制的還是被引用的?如果結構數組的元素象結構變量那樣也是復制的,那么對於方法調用的內存占用問題,就得好好考慮下了。
MSDN看了半天,也討論了半天,感覺還是沒有動手實驗最有說服力,我們先定義一個結構體:
struct Point { public int X; public int Y; public Point(int x, int y) { this.X = x; this.Y = y; } }
定義2個方法,分別以傳值和傳引用的方式來調用結構變量:
static void TestStruc(Point p) { p.X++; p.Y++; } static void TestStruc2(ref Point p) { p.X++; p.Y++; }
調用代碼:
Point p = new Point(1, 2); TestStruc(p); Console.WriteLine("call by value Point X={0},Y={1}", p.X, p.Y); TestStruc2(ref p); Console.WriteLine("call by ref Point X={0},Y={1}", p.X, p.Y);
調用結果符合預期,以引用傳遞的結構變量,它的值被改變了:
Struct Pont(X,Y) Test: call by value Point X=1,Y=2 call by ref Point X=2,Y=3
下面,試試結構數組,看有何不同:
static void TestStrucArray2(ref Point[] arr) { Point p = arr[0]; p.X++; p.Y++; }
調用代碼:
Point[] arr = new Point[2]; arr[0] = new Point(1, 2); arr[1] = new Point(3, 4); TestStrucArray(arr); Console.WriteLine("call by value Point[0]: X={0},Y={1}", arr[0].X, arr[0].Y);
結果:
call by value Point[0]: X=1,Y=2
方法內部對結果數組元素的改變無效,難道結構數組被復制了?
驚出一身冷汗!
改成引用參數的方式來試試,避免復制結構數組:
static void TestStrucArray2(ref Point[] arr) { Point p = arr[0]; p.X++; p.Y++; }
結果:
call by value Point[0]: X=1,Y=2 call by ref Point[0]: X=1,Y=2
引用方式數組還是被復制了?看來哪里有問題阿。
去掉用一個結構變量來引用結構數組的成員,直接操作結構數組的元素,來看看調用結果:
static void TestStrucArray3( Point[] arr) { //Point p = arr[0]; arr[0].X++; arr[0].Y++; } static void TestStrucArray4(ref Point[] arr) { arr[0].X++; arr[0].Y++; }
調用代碼:
TestStrucArray4(ref arr); Console.WriteLine("call by ref Point[0] not use var : X={0},Y={1}", arr[0].X, arr[0].Y); arr[0].X = 1; arr[0].Y = 2; TestStrucArray3( arr); Console.WriteLine("call by var Point[0] not use var : X={0},Y={1}", arr[0].X, arr[0].Y);
結果:
call by ref Point[0] not use var : X=2,Y=3 call by var Point[0] not use var : X=2,Y=3
直接操作結構數組的元素,元素的值被改變了,證明結構數組沒有復制數組元素的值,依然是對數組的引用,上面的問題虛驚一場。
我們對比下前后不同的代碼,發現TestStrucArray2 僅僅多了一行代碼:
static void TestStrucArray2(ref Point[] arr) { Point p = arr[0]; p.X++; p.Y++; }
這說明,定義一個結構變量,讓另外一個結構變量的值賦值給它,等於是復制這個結構變量的值。
往往有時候,我們為了敲代碼方便,少寫幾個字,便定義一個臨時變量去引用原來的變量,而這種行為,對於操作結構變量,無疑是一個最大的坑,這個坑,你遇到過嗎?