前文:
数组
数组是一个存储相同类型元素的固定大小的顺序集合,是用来存储数据的集合,通常认为数组是一个同一类型变量的集合。
声明数组变量并不是声明 number0、number1、…、number99 一个个单独的变量,而是声明一个就像 numbers 这样的变量,然后使用 numbers[0]、numbers[1] … numbers[99] 来表示一个个单独的变量。数组中某个指定的元素是通过索引来访问的。
所有的数组都是由连续的内存位置组成的。最低的地址对应第一个元素,最高的地址对应最后一个元素。
声明
语法:
datatype[] arrayName;
datatype
用于指定被存储在数组中的元素的类型。[ ]
指定数组的秩(维度)。秩指定数组的大小。arrayName
指定数组的名称。
初始化
声明一个数组不会在内存中初始化数组。当初始化数组变量时,可以赋值给数组,数组是一个 引用类型,所以需要使用 new
关键字来创建数组的实例:
double[] balance = new double[10];
赋值
单独赋值:
double[] balance = new double[10];
balance[0] = 4500.0;
声明时顺带赋值:
double[] balance = { 2340.0, 4523.69, 3421.0};
初始化时顺带赋值:
int [] marks = new int[5] { 99, 98, 92, 97, 95};
初始化时赋值还可以省略数组大小:
int [] marks = new int[] { 99, 98, 92, 97, 95};
也可以赋值一个数组变量到另一个目标数组变量中。在这种情况下,目标和源会指向相同的内存位置:
int [] marks = new int[] { 99, 98, 92, 97, 95};
int[] score = marks;
// marks 和 score 数组内容一致,都指向同一个内存地址
创建一个数组时,C# 编译器会根据数组类型隐式初始化每个数组元素为一个默认值,例如,int
数组的所有元素都会被初始化为 0
。
访问数组元素
元素是通过带索引的数组名称来访问的,这是通过把元素的索引放置在数组名称后的方括号中来实现的,例如:
double salary = balance[9];
实例:
using System;
namespace ArrayApplication
{
class MyArray
{
static void Main(string[] args)
{
int [] n = new int[10]; // n 是一个带有 10 个整数的数组
int i,j;
// 初始化数组 n 中的元素
for ( i = 0; i < 10; i++ )
{
n[ i ] = i + 100;
}
// 输出每个数组元素的值
for (j = 0; j < 10; j++ )
{
Console.WriteLine($"Element[{j}] = {n[j]}");
}
Console.ReadKey();
}
}
}
输出:
如同在 C#基础-4-循环与封装 一文中循环部分,访问数据元素还可以使用 foreach
语句来遍历数组:
using System;
namespace ArrayApplication
{
class MyArray
{
static void Main(string[] args)
{
int [] n = new int[10]; // n 是一个带有 10 个整数的数组
// 初始化数组 n 中的元素
for ( int i = 0; i < 10; i++ )
{
n[i] = i + 100;
}
// 输出每个数组元素的值
foreach (int j in n)
{
int i = j-100;
Console.WriteLine($"Element[{i}] = {j}");
}
Console.ReadKey();
}
}
}
输出:
Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109
多维数组
C# 支持多维数组,多维数组又称为矩形数组。例如:
string [,] names; // 二维
int [ , , ] num; // 三维
二维数组:
一个二维数组可以被认为是一个带有 x 行和 y 列的表格。下面是一个二维数组,包含 3 行和 4 列:
图源自菜鸟教程。
因此,数组中的每个元素是使用形式为 a[ i , j ]
的元素名称来标识的,其中 a 是数组名称,i 和 j 是唯一标识 a 中每个元素的下标。
初始化数组:
多维数组可以通过在括号内为每行指定值来进行初始化,下面是一个带有 3 行 4 列的数组:
int [,] a = new int [3,4] {
{0, 1, 2, 3} , // 初始化索引号为 0 的行
{4, 5, 6, 7} , // 初始化索引号为 1 的行
{8, 9, 10, 11} // 初始化索引号为 2 的行
};
访问数组元素:
例如:
int val = a[2,3];
实例:
using System;
namespace ArrayApplication
{
class MyArray
{
static void Main(string[] args)
{
// 一个带有 5 行 2 列的数组
int[,] a = new int[5, 2] { {0,0}, {1,2}, {2,4}, {3,6}, {4,8} };
int i, j;
// 输出数组中每个元素的值
for (i = 0; i < 5; i++)
{
for (j = 0; j < 2; j++)
{
Console.WriteLine($"a[{i},{j}] = { a[i,j] }");
}
}
Console.ReadKey();
}
}
}
输出:
交错数组
交错数组是数组的数组,且是一维数组。
声明一个带有 int
值的交错数组 scores
,如下所示:
int [][] scores;
示例声明一个数组不会在内存中创建的数组:
int[][] scores = new int[5][];
for (int i = 0; i < scores.Length; i++)
{
scores[i] = new int[4];
}
初始化一个交错数组:
int[][] scores = new int[2][]{ new int[]{92,93,94}, new int[]{85,66,87,88} };
其中,scores
是一个由两个整型数组组成的数组,scores[0]
是一个带有 3 个整数的数组,scores[1]
是一个带有 4 个整数的数组。
实例:
using System;
namespace ArrayApplication
{
class MyArray
{
static void Main(string[] args)
{
// 一个由 5 个整型数组组成的交错数组
int[][] a = new int[][]{ new int[]{0,0}, new int[]{1,2}, new int[]{2,4}, new int[]{3,6}, new int[]{4,8} };
int i, j;
// 输出数组中每个元素的值
for (i = 0; i < 5; i++)
{
for (j = 0; j < 2; j++)
{
Console.WriteLine($"a[{i}][{j}] = { a[i][j] }");
}
}
Console.ReadKey();
}
}
}
输出:
a[0][0] = 0
a[0][1] = 0
a[1][0] = 1
a[1][1] = 2
a[2][0] = 2
a[2][1] = 4
a[3][0] = 3
a[3][1] = 6
a[4][0] = 4
a[4][1] = 8
交错数组与二维数组的区别,可以直观的理解为交错数组每一行的长度是可以不一样的。
如果说二维数组像是唐诗,那么交错数组就是宋词,每一句的长短没有限制:
// 声明一个交错数组 a,a 中有三个元素,分别是 a[0],a[1],a[2] 每个元素都是一个数组
int[][] a = new int[3][];
// 以下是声明交错数组的每一个元素,每个数组的长度可以不同
a[0] = new int[] { 1,2,3 };
a[1] = new int[] { 4,5,6,7,8 };
a[2] = new int[] { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
传递数组给函数
在 C# 中,可以传递数组作为函数的参数,通过指定不带索引的数组名称来给函数传递一个指向数组的指针:
using System;
namespace ArrayApplication
{
class MyArray
{
// 将数组 balance 当作参数传给 arr,将数组长度 5 传给 size
double GetAverage(int[] arr, int size)
{
int i;
double avg;
int sum = 0;
// 计算数组中元素的和
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
// 计算平均值
avg = (double)sum / size;
// 返回平均值
return avg;
}
static void Main(string[] args)
{
// 实例化类 MyArray,命名为 app
MyArray app = new MyArray();
// 一个带有 5 个元素的 int 数组
int [] balance = new int[]{1000, 2, 3, 17, 50};
double avg;
// 传递数组的指针作为参数
avg = app.GetAverage(balance, 5 ) ;
// 输出返回值
Console.WriteLine($"平均值是:{avg}");
Console.ReadKey();
}
}
}
输出:
参数数组
有时,当声明一个方法时,不能确定要传递给函数作为参数的参数数目,C# 参数数组解决了这个问题,参数数组通常用于传递 未知数量的参数 给函数,就要用到 params
关键字:
在使用数组作为形参时,C# 提供了 params
关键字,使调用数组为形参的方法时,既可以传递数组实参,也可以传递一组数组元素。params
的使用格式为:
public 返回类型 方法名称( params 类型名称[] 数组名称 )
实例:
using System;
namespace ArrayApplication
{
class ParamArray
{
public int AddElements(params int[] arr)
{
int sum = 0;
foreach (int i in arr)
{
sum += i;
}
return sum;
}
}
class TestClass
{
static void Main(string[] args)
{
ParamArray app = new ParamArray();
int sum = app.AddElements(512, 720, 250, 567, 889);
Console.WriteLine($"总和是: {sum}");
Console.ReadKey();
}
}
}
输出:
总和是: 2938
Array类
Array
类是 C# 中所有数组的基类,它是在 System
命名空间中定义。特性:
- 类型安全:数组只能存储指定类型的元素,类型在声明时确定。
- 固定长度:数组的长度在创建后不可更改。
- 索引访问:数组中的元素通过索引访问,索引从 0 开始。
- 多维支持:C# 支持一维、多维和交错数组(数组的数组)。
常用属性
属性名 | 说明 |
---|---|
Length | 获取数组中元素的总个数 |
Rank | 获取数组的维数 |
IsFixedSize | 判断数组的大小是否固定 |
IsReadOnly | 判断数组是否为只读 |
IsSynchronized | 判断数组是否线程安全 |
SyncRoot | 获取用于同步数组访问的对象,通常用于多线程操作 |
示例:
int[] arr = {1, 2, 3};
int length = arr.Length;
// 输出:1
int[,] matrix = new int[2, 3];
int rank = matrix.Rank;
// 输出:2
int[] arr = {1, 2, 3};
bool fixedSize = arr.IsFixedSize;
// 输出:true
int[] arr = {1, 2, 3};
bool readOnly = arr.IsReadOnly;
// 输出:false
int[] arr = {1, 2, 3};
bool sync = arr.IsSynchronized;
// 输出:false
int[] arr = {1, 2, 3};
object syncRoot = arr.SyncRoot;
// 输出:syncRoot
常用方法
以下内容来自模型:QwQ-32B,生成时间:2025 03-11 13:54
方法 | 用途 | 示例 |
---|---|---|
Array.Sort() |
排序数组 | Array.Sort(numbers); |
Array.Reverse() |
反转数组元素 | Array.Reverse(numbers); |
Array.BinarySearch() |
在已排序数组中查找元素 | Array.BinarySearch(sorted, 5); |
Array.Copy() |
复制数组元素到另一个数组 | Array.Copy(src, dest, 3); |
Array.Clear() |
清空数组指定范围的元素 | Array.Clear(arr, 0, 2); |
Array.Exists() |
判断是否存在满足条件的元素 | Array.Exists(arr, x => x > 5); |
Array.Find() |
查找第一个满足条件的元素 | Array.Find(arr, x => x % 2 ==0); |
Array.FindAll() |
查找所有满足条件的元素 | Array.FindAll(arr, x => x > 3); |
Array.IndexOf() |
查找元素首次出现的索引 | Array.IndexOf(arr, "Bob"); |
Array.Resize() |
调整数组大小 | Array.Resize(ref arr, 10); |
1、Array.Sort()
作用:对数组进行排序(默认升序)。
int[] numbers = { 5, 2, 8, 1, 9 };
Array.Sort(numbers); // 排序后:1, 2, 5, 8, 9
// 自定义排序(例如降序)
Array.Sort(numbers, (x, y) => y.CompareTo(x)); // 排序后:9, 8, 5, 2, 1
2、Array.Reverse()
作用:反转数组元素的顺序。
int[] numbers = { 1, 2, 3, 4 };
Array.Reverse(numbers); // 反转后:4, 3, 2, 1
3、Array.BinarySearch()
作用:在已排序的数组中查找元素(二分查找,效率高)。
int[] sortedNumbers = { 1, 3, 5, 7, 9 };
int index = Array.BinarySearch(sortedNumbers, 5); // 返回索引 2
// 查找不存在的元素返回负数
index = Array.BinarySearch(sortedNumbers, 4); // 返回 -3(插入位置的补码)
4、Array.Copy()
作用:将一个数组的元素复制到另一个数组。
int[] source = { 10, 20, 30, 40, 50 };
int[] destination = new int[3];
Array.Copy(source, destination, 3); // 复制前 3 个元素
// destination 现在是 { 10, 20, 30 }
5、Array.Clear()
作用:将数组的指定范围的元素设为默认值(如 0
、null
等)。
int[] numbers = { 1, 2, 3, 4, 5 };
Array.Clear(numbers, 1, 3); // 清空索引 1 到 3 的元素(包含索引 1 和 3)
// numbers 现在是 { 1, 0, 0, 0, 5 }
6、Array.Exists()
作用:判断数组中是否存在满足条件的元素。
int[] numbers = { 2, 4, 6, 8 };
bool hasEven = Array.Exists(numbers, x => x % 2 == 0); // 返回 true
bool hasOdd = Array.Exists(numbers, x => x % 2 != 0); // 返回 false
7、Array.Find()
和 Array.FindAll()
作用:查找单个或多个满足条件的元素。
int[] numbers = { 1, 2, 3, 4, 5, 6 };
// 查找第一个偶数
int firstEven = Array.Find(numbers, x => x % 2 == 0); // 返回 2
// 查找所有偶数
int[] evens = Array.FindAll(numbers, x => x % 2 == 0); // 返回 [2,4,6]
8、Array.IndexOf()
和 Array.LastIndexOf()
作用:查找元素首次或最后一次出现的索引。
string[] names = { "Alice", "Bob", "Alice", "Charlie" };
int firstIndex = Array.IndexOf(names, "Alice"); // 返回 0
int lastIndex = Array.LastIndexOf(names, "Alice"); // 返回 2
9、Array.Resize()
作用:调整数组的大小(需重新分配内存)。
int[] numbers = { 1, 2, 3 };
Array.Resize(ref numbers, 5); // 扩展到 5 个元素,新增元素为 0
// numbers 现在是 { 1, 2, 3, 0, 0 }
10、Array.ConvertAll()
作用:将数组元素转换为另一种类型。
int[] numbers = { 1, 2, 3 };
string[] strings = Array.ConvertAll(numbers, x => x.ToString());
// strings 现在是 { "1", "2", "3" }
关键点:
Array
类方法通常是静态的,通过Array.方法名()
调用。- 数组是固定大小的,
Array.Resize
需要重新分配内存。 - 排序和查找(如
Sort
、BinarySearch
)要求数组已排序才能高效工作。 - 泛型方法:如
List<T>
的Sort
是实例方法,而Array
的Sort
是静态方法。
通过这些方法,可以高效地对数组进行操作,满足排序、查找、转换等需求。