C#數組 - C#入門基礎


C#中的數組

  • 數組概念
  • 數組是對象
  • 數組的聲明
  • 數組的實例化
  • 顯式的初始化 數組
    • 數組快捷語法
  • 隱式的初始化 數組
  • 知識點串起來組成例子

 

數組 是 由一個 變量名 表示的 同一組同類型數據元素

數組 一旦創建,大小就固定了;

C# 不像 javascript 一樣,C#是不支持動態數組的。

數組從 0 開始,范圍:0~n-1  (n是數量)

有兩種類型的數組:一維數組 和 多維數組

數組實例是從 System.Array類 繼承類型的對象。

 

數組是對象

數組是 引用類型;

數組的元素 的類型 既可以是引用類型也可以是值類型;分別稱為:引用類型數組 和 值類型數組。

 

數組的聲明

long[] secondArray;
int[,,] b;    // 三維數組,如果沒有逗號就是一維數組,一個逗號就是二維數組

錯誤的寫法: 
long b[];     // 錯誤,中括號在變量名后面,這是 C/C++的寫法,C#不適用

 

數組的實例化

 // 一維數組,聲明 a 數組、創建 a 數組實例,沒有初始化
int[] a = new int[2];
Student[] std = new Student[];

// 三維數組 初始化
int[,,] arr3 = new int[3, 5, 2];

注意:與對象創建表達式不同,數組的初始化沒有 圓括號,即使是引用類型數組的初始化

 

默認值:

創建數組實例后,其每個元素都有默認值,string 的為空字符串,int 的為 0 ,bool 的為 false,引用類型的為 null;

 

數組的初始化,顯式的初始化 數組

// 不必輸入多少維,也就是 :  = new int[1]{...}
int[] intArr = new int[] {1, 2, 4, 11, 84};

int[,] intArr2 = new int[,] {{10,1}, {2, 10}, {11, 9}};

 

數組快捷語法

int[] arr1 = new int[3] {1, 33, 1};
// 等價於
int[] arr1 = {1, 33, 1};


int[,] arr2 = new int[,] {{10,1}, {2, 10}};
// 等價於
int[,] arr2 = {{10,1}, {2, 10}};

 

數組的初始化,隱式的初始化 數組

上面我們一直都在數組的聲明開始處顯式指定數組類型,但是,和其他局部變量一樣,數組可以是隱式類型的:

int[] a = new int[]{1, 2};
// var的隱式推斷,因為可以從 {1,2} 推斷出數組時int類型
var a = new []{1, 2};

int[,] b = new int[,] {{10,1}, {2, 10}};
// 隱式
var b = new [,] {{10,1}, {2, 10}};

string[] c = new string[] {"hello", ", world", "!"};
// 隱式
var c = new [] {"hello", ", world", "!"};

 

上面知識點綜合串起來組成一個例子

// 聲明、創建 和 初始化 一個隱式類型的數組
var arr = new int[,] {{0, 1, 2}, {10, 11, 12}};

for(int i = 0; i < 2; i++){
    for(int j = 0; j < 3; j++){
        Console.WriteLine($"[{i},{j} is {arr[i, j]}");
    }
}

 

接下來,是深入數組

  • 交錯數組
  • foreach 循環數組
    • 迭代的變量是只讀的
    • foreach語句 與 多維數組
    • foreach語句 與 交錯數組
  • 數組協變
  • 數組的屬性和方法
  • clone 克隆數組
  • 比較各個數組的區別
  • 數組 與 ref返回 和 ref局部變量

 

交錯數組

 交錯數組,其實就是數組的數組。

與矩形數組不同,交錯數組的子數組的元素個數可以不同。

// 二維交錯數組
int[][] jagArr = new int[3][];    // 讀:jagArr是3個int數組的數組

jagArr[0] = new int[] {11, 34};
jagArr[1] = new int[] {41, 34, 99, 12, 7};
jagArr[2] = new int[] {11, 110, 781};

交錯數組不能在一個步驟中完成:即不能一個語句搞定  創建、聲明、實例化;

上述中,jagArr 第一個中括號為3,但是第二個中括號不能有數字;

下面是矩形數組 和 交錯數組 的 結構:

一維數組:有特定性能優化指令。矩形數組沒有,並且不在相同級別進行優化。

一維數組(可被優化)的交錯數組 比 矩形數組(不能被優化) 更高效;

矩形數組復雜度低,因為它被作為一個單元而不是數組的數組,交較之 交錯數組 復雜度高;

 

foreach 語句循環數組

foreach 語句除了可以循環數組,其實它還可以循環其他集合類型;

foreach 的迭代變量是 臨時 的,也是只讀的;

int[] arr1 = {10, 11, 12, 13};
foreach(int item in arr1){
    Console.WriteLine($"Item Value: {item}");   // item 這個臨時的變量是只讀的,無法修改它
}

 

迭代變量是只讀的

因為foreach語句迭代的變量是只讀的,所以我們不能改變它;

但是,對於 值類型 和 引用類型的數組,使用foreach語句去 迭代 出來的臨時變量,是有區別的;

 

對於值類型的數組:

int[] arr = {1, 2, 3};
foreach(int itme in arr){
    item++;        // 編譯錯誤,不得改變變量值
}

 

對於引用類型的數組:

我們仍然不能改變迭代變量,但是迭代變量只是保存了數據的引用,而不是數據本身(如果不懂此處,請學習有關 引用類型 和 值類型 的具體內存指向),因此,雖然不能改變引用,但我們可以通過迭代變量改變數據:

class AClass{
    public int MyField = 0;
}

AClass[] aclass = new AClass[4];

for(int i = 0; i < 4; i++){
    aclass[i] = new AClass();
    aclass[i].MyField= i;
}

foreach(AClass item in aclass){
    item.MyField += 10;        // 改變數據,是可以的
}

foreach(AClass item in aclass){
    Console.WriteLine($"{item.MyField}");
}

 

foreach語句 和 多維數組

在多維數組中,元素的處理次序是最右邊的索引號最先遞增。當索引從0到長度減1時,開始遞增它左邊的索引,右邊的索引被重置成0。(這句話有點拗口,看下面例子即可)

// 例子:矩形數組
int total = 0;
int[,] arr = {{10, 11}, {12, 13}};

foreach(var element in arr){
    total += element;
    Console.WriteLine($"Element: {element}, Current Total: {total}");
}

// 輸出:
Element: 10, Current Total: 10;
Element: 11, Current Total: 21;
Element: 12, Current Total: 33;
Element: 13, Current Total: 46;

 

foreach語句 和 交錯數組

交錯數組是數組的數組,所以我們必須為交錯數組中的每一個維度使用獨立的foreach語句。

例:

int total = 0;
int[][] arr = new int[2][];
arr[0] = new int[]{10, 11};
arr[1] = new int[]{12, 13, 14}

foreach(int[] array in arr){
    Console.WriteLine("開始新的數組");
    foreach(int item in array){
        total += item;
        Console.WriteLine($"  Item: {item}, Current Total: {total}");
    }
}

// 輸出:
開始新的數組
  Item: 10, Current Total: 10
  Item: 11, Current Total: 21
開始新的數組
  Item: 12, Current Total: 33
  Item: 13, Current Total: 46
  Item: 14, Current Total: 60

 

數組協變

在某些情況下,即使某個對象不是數組的基類型,也可以把它賦值給數組元素。這種情況叫作 數組協變(array covariance)。在下面的情況下可以使用數組協變。

  • 數組是引用類型的數組。
  • 在賦值的對象類型和數組基類型之間有隱式轉換或顯式轉換。

例如,如下代碼聲明了兩個類,A和B,其中B類繼承自A類。最后一行展示了把類型B的對象賦值給類型4的數組元素而產生的協變:

class A {...}
class B: A {...}

A[] AArray1 = new A[3];
A[] AArray2 = new A[3];

// 普通:將A類型的對象賦值給A類型的數組
AArray1[0] = new A();
AArray1[1] = new A();
AArray[2] = new A();

// 協變:將B類型的對象賦值給A類型的數組
AArray2[0] = new B();
AArray2[1] = new B();
AArray2[2] = new B();

 

 注意:值類型數組沒有協變!!

 

數組繼承來的有用成員

因為數組時繼承至 System.Array 類的,這就相當於數組繼承了里面的一些屬性和方法,包括:

 

 例子:

public static void PrintArray(int[] a){
    foreach(var x in a){
        Console.WriteLine($"{x} ");
    }
    Console.WriteLine("");
}

int[] arr = new int[] {15, 20, 5, 25, 10};
PrintArray(arr);

Array.Sort(arr);
PrintArray(arr);

Array.Reverse(arr);
PrintArray(arr);

Console.WriteLine();
Console.WriteLine($"Rank = {arr.Rank}, Length = {arr.Length}");
Console.WriteLine($"GetLength(0) = {arr.GetLength(0)}");
Console.WriteLine($"GetType() = {arr.GetTeype()}");

// 輸出:
15 20 5 25 10
5 10 15 20 25
25 20 15 10 5

Rank = 1, Length = 5
GetLength(0)  = 5
GetType() = System.Int32[]

 

Clone() 克隆數組

這是對數組的 復制,也就是說,它只創建了數組本身的克隆。

如果是引用類型數組,它不會復制元素引用的對象。

對於值類型數組和引用類型數組而言,這有不同的結果。

  • 克隆 值類型 數組 會產生兩個獨立數組。
  • 克隆 引用類型 數組 會產生指向相同對象的兩個數組。

Clone方法返回object類型的引用,它必須被強制轉換成數組類型。

 

值類型的例子分析:

int[] intArr1 = {1, 2, 3};   // 步驟 1
int[] intArr2 = (int[])intArr1.Clone();        // 步驟 2

intArr2[0] = 100; intArr2[1] = 200; intArr2[2]  300;    // 步驟 3

 

引用類型的例子分析:

class A{
    public int Value = 5;
}

A[] AArray1 = new A[3]{new A(), new A(), new A()};    // 步驟1
A[] AArray2 = (A[])AArray1.Clone();    // 步驟2

AArray2[0].Value = 100;
AArray2[1].Value = 200;
AArray2[2].Value = 300;    // 步驟 3

 

比較各個數組的區別

 

數組 與 ref返回 和 ref局部變量

請先回顧下ref,不清楚這個ref關鍵字的請先復習下 ref 關鍵字的概念和用法;

利用ref返回功能,可以把一個引用作為返回值傳到方法體外,而利用ref局部變量,你可以在調用域內使用這個引用。例如,下面的代碼定義了一個叫作 PointerToHighestPositive 的方法。這個方法接受一個數組作為參數,並且返回對該數組元素的引用,而不是元素中的int 值。然后,在調用域,你可以通過ref局部變量給這個元素賦值。

public static ref int PointerToHighestPositive(int[] numbers)
{
    int highest = 0;
    int indexOfHighest = 0;

    for (int i = 0; i < numbers.Length; i++)
    {
        if (numbers[i] > highest)
        {
            indexOfHighest = i;
            highest = numbers[indexOfHighest];
        }
    }
    return ref numbers[indexOfHighest];
}

static void Main()
{
    int[] scores = { 5, 80 };
    Console.WriteLine($"之前:{scores[0]}, {scores[1]}");
    ref int locationOfHighest = ref PointerToHighestPositive(scores);

    locationOfHighest = 0;
    Console.WriteLine($"之后:{scores[0]}, {scores[1]}");
}

// 輸出
之前:5, 80
之后:5, 0


免責聲明!

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



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