在C语言中,数组是比较简单,也使用比较多的一种基础的数据结构。常用的有一维数组,二维数组等。但是在C#中,使用最多的是List,Dictionary等一些集合类,因为用他们来操作同类型的数据,比数组更加方便。当然,C#的数组Array也通过实现一些接口,提供了访问和操作数据的一些便捷方法。而在C语言中,都是比较不容易实现或者使用不方便。这也就是C#作为一门面向对象的语言的好处,虽然由此带来的性能损失,尤其在做算法相关的问题的时候。但退一步讲,在如今硬件资源比较丰富的情况下,日常场景中,这种性能损失还是可以接受的。


  接下来就聊聊C#种数组的那些事儿。

  1.数组基本概念:

      学习C#数组,首先需要明确一点,C#的数组是引用类型,即使数据基类型是值类型。作为引用类型,自然就会有类型对象指针,同步索引块,开销字段(overhead)等。

  2.C#数组分类:

      C#支持多维数组,也支持交错数组。并且他们都可以是非0基的。所谓非0基,是指数组第一个元素的索引不是从0开始。相应的,.Net CLR本身支持非0基数组,但是CLS规范规定所有数组都应该是0基数组,主要是为了兼容性和跨平台性,毕竟.Net家族除了C#还有VB,F#,C++(托管的)等语言。
      概念解释:
      一维0基数组:它又称为SZ数组(Single-dimension,Zero-based)或者向量。它的性能是最好的,因为编译器可以为他生成特殊的IL指令,实现JIT编译时候的优化,诸如以下指令(newarr,ldelem,ldelema,ldlen,stelem)。

          使用如下:

int[] nums=new int[];

      多维数组:又称矩形数组。从行列的角度来考虑的话,它的每一行的列数都必须时相等的。

          使用如下:

int[,] nums=new int[,];

      交错数组:用行列的角度来考虑的画,它的每一行的列数可以不相同。

int[][] nums=new int[][];
for(int i=;i<;i++)
{
nums[i]=new int[];//交错数组,各数组长度可不一样
}

         交错数组这个定义方式,非常类似于C语言中的动态多维数组,在C语言中,我们常用以下方法来开辟动态的二维数组

int i;
int** nums=(int**) malloc(sizeof(int*)*);
for(i=;i<;i++)
{
nums[i]=(int*)malloc(sizeof(int)*);//这儿10是个实例,更具需求设置
}

         二者的定义的确有相似的地方,但应该注意到他们在本质上时不同的。

  3.数组索引:

      数组的索引是数组的一个很核心的概念,因为我们对数组的访问一般都是通过索引来实现的,但对索引的不当处理,可能导致程序终止。

      在C语言中,数组的索引控制都需要程序员来实现。如果发生索引超出数组范围,导致越界访问内存数据,甚至修改内存数据,这些都是不可察觉的,但无疑它为系统的奔溃留下了伏笔;

      在C#中,由于CLR要保证数据的安全,CLR在运行代码的时候,如果检测到数组索引超出范围,会立即抛出System.IndexOutOfRangeException异常,从而终止错误的继续。当然也可以使用unsafe关键字,来忽略CLR的这种默认行为。

      C#支持非0基数组,意味着数组可以的索引可以从非0的数开始,可以使用Arrary.CreatInstance()方法来创建下限非零数组。

  4.数组元素初始化:

     C#中为数组的初试化提供了一些甜蜜的语法糖。通常我们用以下几种方式来初始化一个数组。
      

int[] age=new int[]{,,};//大括号中的数据项称为数组初始化器(arrar,initializer)
var age=new int[]{,,}
var age=new [] {,,};//隐式类型推断

     C#的隐式类型推断为创建一个数组提供了良好的支持。

  5.数组转型:

      类型转换是编程种很常见的一件事儿,我们把数组的类型转换又称为数组协变性(array convariance),在数组的转型的时候,需要满足以下几点条件:
      ①数组维数相同
      ②基类型存在隐式或显式类型转化
      需要注意以下几点:

        CLR不允许值类型数组转型为其他任何类型数组,但可以通过Array.Copy()变通实现。
        Array.Copy():支持装箱,拆箱,以及加宽基元类型(比如int到double的转变),但它是浅拷贝,即如果数组基类型是引用类型,则只复制其引用。
        System.Buffer.BliockCopy() 支持基元类型,但不具有转型能力
        System.Array.ConstrainnedCopy() 不支持装箱、拆箱和向下类型转化(父类到子类的转换),但它是可靠的,数据安全的,要么成功复制一个数组,要么不会修改目标数组的任何数据

  6.数组接口:

      数组实现了一些常用的接口,相当于给数组插上了访问的翅膀。
      System.Array数组基类实现了ICollection,IEnumerable,IList的非泛型版本,因为多维数组和非0基数组的原因,没有实现泛型版本(原因我也不太清楚)
      CLR单独为一维0基数组实现了泛型版本接口,包括其基类型,但是System.ValueType和Object除外

  7.数组做参数:

      在使用中,不可避免的要把数组作为一个参数来使用,那么在使用的时候,需要注意以下几点
      ①作为方法实参时传递的是引用;
      ②如果需要返回一个数组类型的字段,建议使用Array.Copy(),返回一个从该字段复制的数组,这么做是为了保证OOP的开放封闭原则,因为通常字段是私有的,不能被外部方法修改的和使用的;
      ③对于返回数组的方法,如果数组元素个数为0,仍不建议返回一个null,而是应该返回一个空的数组,这么做的目的在于对于方法返回参数的使用这来说,免去了null判断,防止产生空引用异常的错误。

  8.数组原理:

      实际在CLR内部只支持两种类型数组:一维0基数组 和 下限未知的一维或多维数组;
      一维0基数组:可以使用特殊的IL指令(newarr,ldelem,ldelema,ldlen,stelem),让编译器产生优化代码。比如索引检查发生的时刻提前,循环判断的提前的。
      下限未知的一维或多维数组:每次数组访问前验证索引有效性

  一些使用C#数组的建议:

  ①用交错数组代替矩形数组
  ②Unsafe关键字访问数组时可关闭索引上下限检查,支持常见的值类型和值类型结构(在fixed语句中)

  ③可以在线程栈上分配数组,利用stackalloc语句,类似于C语言alloca语句 ,条件是必须为一维0基数组,数组基类型为值类型

内容均来自于Jeffrey Richter的《CLR Via C#》第四版一书,以及个人总结和心得。学习深入了解C#,建议从这本书开始学习。

[.net]数组的更多相关文章

  1. javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈

    Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...

  2. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  3. 编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议75~78)

    建议75:集合中的元素必须做到compareTo和equals同步 实现了Comparable接口的元素就可以排序,compareTo方法是Comparable接口要求必须实现的,它与equals方法 ...

  4. 了解PHP中的Array数组和foreach

    1. 了解数组 PHP 中的数组实际上是一个有序映射.映射是一种把 values 关联到 keys 的类型.详细的解释可参见:PHP.net中的Array数组    . 2.例子:一般的数组 这里,我 ...

  5. JavaScript权威指南 - 数组

    JavaScript数组是一种特殊类型的对象. JavaScript数组元素可以为任意类型,最大容纳232-1个元素. JavaScript数组是动态的,有新元素添加时,自动更新length属性. J ...

  6. JavaScript常见的五种数组去重的方式

    ▓▓▓▓▓▓ 大致介绍 JavaScript的数组去重问题在许多面试中都会遇到,现在做个总结 先来建立一个数组 var arr = [1,2,3,3,2,'我','我',34,'我的',NaN,NaN ...

  7. js:给定两个数组,如何判断他们的相对应下标的元素类型是一样的

    题目: 给Array对象原型上添加一个sameStructureAs方法,该方法接收一个任意类型的参数,要求返回当前数组与传入参数数组(假定是)相对应下标的元素类型是否一致. 假设已经写好了Array ...

  8. javascript数组查重方法总结

    文章参考地址:http://blog.csdn.net/chengxuyuan20100425/article/details/8497277 题目 对下列数组去重: var arr = ['aa', ...

  9. 掌握javascript中的最基础数据结构-----数组

    这是一篇<数据结构与算法javascript描述>的读书笔记.主要梳理了关于数组的知识.部分内容及源码来自原作. 书中第一章介绍了如何配置javascript运行环境:javascript ...

  10. 小兔JS教程(四)-- 彻底攻略JS数组

    在开始本章之前,先给出上一节的答案,参考答案地址: http://www.xiaotublog.com/demo.html?path=homework/03/index2 1.JS数组的三大特性 在J ...

随机推荐

  1. nginx安装及基础配置(含jdk安装及配置)

    0.jdk安装配置 #下载相应的jdk软件包,然后解压安装,我这里包名称为:jdk-7u25-linux-x64.tar.gz tar -xzf jdk-7u25-linux-x64.tar.gz m ...

  2. 【SQL模板】四.插入/更新 列模板TSQL

    ---Name: 插入/更新 列模板.sql ---Purpose: 用于更新 数据库中 列 的脚本模板 ---Author: xx ---Time: 2015-12-18 10:26:06 ---R ...

  3. C#中发送邮件,包含Html代码 CDO.Message

    C#代码: /// <summary> /// 发送邮件 /// </summary> /// <param name="context">&l ...

  4. asp.net core web 本地iis开发

    发布后打开没有问题,直接配置到本地iis时,会提示如下错误 HTTP Error 502.5 - Process Failure

  5. 将Win7笔记本设置成WiFi热点(无线路由器)

    查看是否能启动WiFi网卡: S1:运行cmd命令,打开命令提示符窗口(以管理员身份运行). S2:在命令行输入:netsh wlan show drivers. 若“支持的承载网络”后为“是”,则可 ...

  6. 抽象 abstract 和 接口 interface。 java 的 堆 和 栈。 参数传递(基本类型和普通对象的区别)

    package com.test; import com.test.Pro; //protected 修饰的成员只能在本包中和 继承该类的方法中使用 public abstract class Tes ...

  7. part1:9-windows与Linux文件共享

    1.winSCP 它是一个windows环境下使用SSH的开源图形化SFTP客户端.同时支持SCP协议.它主要功能就是在本地与远程计算机间安全的复制文件. 前提:Linux与windows能相互pin ...

  8. windows10创意者完整镜像下载

    今天给大家分享一个windwos10创意者的完整镜像. 在官网,我们看到的是直接下载安装,但是在没有网的时候我们就无法了 而且在很多的时候我们在下载安装windows10的时候回遇到很多无法估量的问题 ...

  9. DevExpress VCL 13.1.2 发布

    DevExpress VCL 的2013 第一个公开版发布, 基本上就是一些维护,没有大的变化,也没有FM 的支持. What's New in DevExpress VCL 13.1.2   Rel ...

  10. 643. Maximum Average Subarray I

    static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...