一、简介
前面介绍了整型、浮点型、布尔型、字符型等都是一些简单的数据类型,这些数据类型可以用来存放一些简单变量。
然而在实际应用中,常常需要处理一批数据,一个矩阵等,所以需要引入数组的概念。
数组,或称为数组数据类型。就是针对这类问题而构造的一种新的数据表达。
数组是具有相同类型的一组数据。
数组按照数目名、数据元素的类型和维数来进行描述。
当访问数组中的数据时,可以通过下标来指明。
二、数组具有以下属性
1.数组可以是一维、二维、多维或交错的。
2.数值数组元素的默认值设置为0或空。
3.数组的索引从0开始,具有n个元素的数组的索引是0~n-1。
4.数组元素可以是任何类型,包括数组类型。
三、一维数组
1.数组的声明
在C#中,声明一维数组的方式是在类型名称后添加一对方括号。
表达形式:
数据类型【】 数组名;
例:
int[] myArray;
数组的大小不是其类型的一部分,声明一个数组时,不用管数组长度如何。
2.数组对象的创建
声明数组并不实际创建,而是使用new关键字创建。
表达形式:
数组名 = new 数据类型【数组大小表达式】
例:
myArray = new int[5];
解释:
此数组包含myArray[0]~myArray[4],一共5个元素。
数组元素初始化时,为空字符串。
数组的Length属性,表示数组的总个数。
一维数组的长度,可以通过以下方式获得。
例:
int[] myArray1 = new int[8]; //初始长度为8
int n = myArray1.Length; //n=8
3.一维数组的初始化
C#在声明数组的同时,对其初始化提供了简捷的方法。
也就是简化书写形式:
数据类型[] 数组名 = new 数据类型[]{ 初始值表 };
例:
int[] myArray2 = new int[]{ 1, 2, 3, 4, 5 };
//这是一个长度5的整型数组。
例:声明字符串数组。
string[] stuName = new string[] {"john" , "Tom", "Machael"};
也可以直接省略new 数据类型[]
如:
int[] myArray2 = { 1, 2, 3, 4, 5 };
string[] stuName = {"john" , "Tom", "Machael"};
如果在声明一个数组变量时,为直接赋值,就不能省略new运算符。
错误案例:
int[] myArraycuo;
myArraycuo = {1, 2, 3, 4}; //报错。
4.一维数组的元素的访问
访问一维数组元素的方式:
数组名[下标]
例:
myArray[0];
如:
int[] myArray2 = { 1, 2, 3, 4, 5 };
int n = myArray[0]; //n = 1
int n = myArray[1]; //n = 2
int n = myArray[2]; //n = 3
int n = myArray[3]; //n = 4
int n = myArray[4]; //n = 5
int n = myArray[5]; //错误,超出数组长度。
数组元素访问的结果是变量,即由下标选定的数组元素。
下标可以是整型常量或整型表达式。
5.像访问变量一样直接给数组元素赋值。
例:
int[] a = new int[5]; //先定义一个数组变量
a[0] = 10; //往第1个元素里赋值10
a[4] = a[0]; //往第5个元素里赋值变量第一个元素的值,也就是10
这里由于是从零开始,所以索引号就变成了n-1;
6.使用循环语句向数组的每个元素赋值
例:
使用for循环向数组的每个元素赋值100
int[] myArray = new int[10];
for( int i = 0; i<10; i++){
myArray[i] = 100;
}
需要注意的是,往往不知道数组的具体长度,所以使用Length属性会更好。
例:
使用for循环向数组的每个元素赋值100
int[] myArray = new int[10];
for( int i = 0; i
myArray[i] = 100;
}
7.冒泡排序
定义一个包含10个元素的整型数组,并对其进行赋值和排序。
将每个元素从大到小进行排序输出。
冒泡排序的思想
假设有n个元素按递减的顺序排序,首先进行第1轮排序:
从数组的第1项开始,每一项都与下一项进行比较,将最小的排到最后。
例:
分析:
1)先创建一个无规律数组。
2)最外层的循环,是为了重复内部比较。
3)内层的循环,和里面的比较,可以逐步进行分析。
第一次进行比较:arr[0]
如果条件成立,就将两个数字互换。
10
8
3 < 15 ?成立,并进行互换。数组就成了{10,8,15,3,。。}
3 < 26 ? 成立,并进行互换。数组就成了{10,8,15,26,3。。}
3 < 11 ? 成立,并进行互换。数组就成了{10,8,15,26,11,3。。}
3 < 30 ? 成立,并进行互换。数组就成了{10,8,15,26,11,30,3}
4)内部的循环也就结束了,数组也就成为:
{10,8,15,26,11,30,3}
5)然后再进行外层的第二轮循环,重复上面的操作。
6)最终结果也就为:
{30,26,15,11,10,8,3}
8.值类型和引用类型
基本数据类型是值类型,数组和string是引用类型。
区别在于,值类型在栈上分配,而引用类型在堆上分配。
这里暂不考虑什么是栈什么是堆,只需要知道栈和堆都是从内存中两片不同的区域即可。
比如你声明的数组,整体会存放在内存中的某个区域。
9.例
运行结果,
14~17行为值类型的赋值。
int是一个值类型,变量i1和i2在栈上分配。
首先i1的值为100,然后把i1的值赋值给i2,这样i2的值也变成了100.
20~22行演示了引用类型的赋值。
根据结果可知,更改arr1的值的同时,arr2的值也会改变。
array是一种引用类型,
第20行代码首先是在栈上分配了一个arr1变量,然后在堆上初始化了一个有5个元素的数组对象,最后把数组对象在堆上的地址给了变量arr1.
第21行代码声明了一个数组变量arr2,并把arr1的值赋给了arr2.
前面说过,是把arr1上的其实是地址值,所以arr2的实际的值,也是arr1的地址值。
第22行代码改变了arr1的第一个元素的值,但地址值没有改变,所以arr1和arr2的值,依旧是指向该数组的地址值。
所以数组里的数如果被修改,那么arr1和arr2的数组都会改变。
10.例
如果希望arr2所得的是一个新的数组对象,除了新声明一个数组外,还可以使用CopyTo()方法进行复制。
CopyTo()有两个参数,第一个参数是要复制的数组,第二个参数是从第几个元素开始,从0开始。
运行结果
这一次arr2的值和arr1的值,不会因为arr1的改变而改变。
因为重新开辟了一个内存空间,所以是两个不同的地址值和数组。
11.例:
运行结果