码迷,mamicode.com
首页 > 其他好文 > 详细

学习系列之数据类型

时间:2017-09-03 16:40:35      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:style   总结   示意图   精度   code   else   出栈   堆内存   代码   

一、数据类型初探

     电脑是由什么来存储所使用的数据? 这个问题用一句话比较笼统的概括,那就是:电脑使用内存来记忆计算时所使用的数据。在现实生活中的数据各种各样,整数、小数、字符串、字符等等,它们都类型是不一样的,所以你要想在计算机中使用这些类型,就必须在内存中为它申请一块合适的空间。

    数据类型总结起来有以下几点:

  (1)C程序是一组函数和数据类型,C++程序是一组函数和类,而C#程序是一组类型声明;

  (2)类型是一种模板:模板本身不是数据结构,但它详细说明了由该模板构造的对象的特征;

  (3)C#提供了16种预定义类型:13种简单类型(数值类型:int,float,double,decimal等;非数值类型:bool,char),3种非简单类型(object,string,dynamic);

            所有的预定义类型都直接映射到底层的.NET类型。C#的类型名称其实就是.NET类型的别名,所以使用.NET的类型名称也符合C#语法,不过并不鼓励这样做。在C#程序中,应当尽量使用C#类型名称而不是.NET类型名称;

     (4)除了上面提到的16种预定义类型外,还可以创建自己的用户定义类型,一共有6种用户定义类型可以由用户自己创建,它们是:类(Class)、结构体(Struct)、数组(Array)、枚举(Enum)、委托(Delegate)和接口(Interface);

技术分享

 

二 数据类型详解

1、整型

 技术分享

2、浮点类型 技术分享 

    float数据类型用于较小的浮点数,因为它要求的精度较低。

    double数据类型比float数据类型大,提供的精度也大一倍(15位)。

    如果在代码中没有对某个非整数值(如12.3)硬编码,则编译器一般假定该变量是double。

    如果想指定该值为float,可以在其后加上字符F(或f),如:

    float f = 12.3F;

 3、decimal类型

技术分享

    decimal类型专门用于进行财务计算,使用decimal类型提供的28位的方式取决于用户。

    要把数字指定为decimal类型,可以在数字的后面加上字符M或(m),如:

    decimal d=12.30M;

  4、bool(布尔)类型

技术分享 

 5、char字符类型

技术分享 

     char类型的字变量是用单引号括起来的。     如‘A‘

     如果把字符把在"A"(双引号)内,编译器会把它看作是字符串,从而产生错误。

 6、引用类型(Object类型和字符串类型)

技术分享 

三 数据类型存储双雄:栈和堆

3.1 栈

  (1)栈是一个内存数组,是一个LIFO(Last In First Out,后进先出)的数据结构。

技术分享

 

  (2)栈存储几种类型的数据:某些类型变量的值(主要是值类型);程序当前的执行环境;传递给方法的参数;

  (3)栈具有几种显著的特征:数据只能从栈顶插入和删除;将数据放到栈顶叫做入栈;将数据从栈顶移除叫做出栈

3.2 堆

  (1)堆是一块内存区域,在堆里可以分配大块的内存用于存储某类型(主要是引用类型)的数据对象;与栈不同,堆里的内存能够以任意的顺序插入或移除;

       (2)堆中的数据不能显示地删除,CLR中的自动GC(Garbage Collector,垃圾收集器)会自动清除无主(判断程序代码是否将不再访问某数据项的时候)的堆内存对象。因此,我们可以骄傲地说:妈妈再也不用担心我的垃圾了

技术分享

 四、值类型和引用类型:屌丝和高富帅

  (1)值类型:只需要一段单独的内存,用于存储实际的数据;TIP:对于值类型,数据存放在栈里;(byte,int,long,float,double,struct,enum等)

 技术分享

  (2)引用类型:需要两段内存,第一段存储实际的数据,它总是位于堆中;第二段是一个引用,指向数据在堆中的存放位置;TIP:对于引用类型,实际数据存放在堆里,而引用存放在栈里。(object,string,dynamic,class,interface,delegate,array)

 技术分享

  (3)引用类型对象的数据始终存放在堆里,无论它们是值类型还是引用类型。

 技术分享

五 、 数据类型转换

数据类型在一定的条件下是可以相互转换的,如将int型数据转换成double型数据。C#允许使用两种转换方式:隐式转换和显式转换。

1、隐式转换

隐式转换:从类型A到类型B的转换可以在所有情况下进行,执行转换的规则非常简单,可以让编译器执行转换。

隐式转换不需要做任何工作,也不需要另外编写代码。如将int型数据转换成double型数据:

int a = 10;double b = a;//隐式转换

隐式转换规则是:任何类型A,只要其取值范围完全包含在类型B的取值范围内,就可以隐式转换为类型B。基于这个转换规则,C#的隐式转换不会导致数据丢失。需要注意的是我们最常用的简单类型bool和string没有隐式转换。

2、显式转换

显式转换:从类型A到类型B的转换只能在某些情况下进行,转换规则比较复杂,应进行某种类型的额外处理。显式转换又叫强制类型转换,显式转换需要用户明确的指定转换类型。如将double类型数据转换成int类型数据:        

 double c = 10.5;
 int d = (int)c;//显示转换

 

提醒:

(1)、显式转换可能会导致错误。进行这种转换时编译器将对转换进行溢出检测。如果有溢出说明转换失败,就表明源类型不是一个合法的目标类型。无法进行类型转换。

(2)、强制类型转换会造成数据丢失,如上面的例子中,最终得到的d值为10。

3、通过方法进行类型转换

(1)、使用ToString()方法。所有类型都继承了Object基类,所以都有ToString()这个方法(转化成字符串的方法)。

(2)、通过int.Parse()方法转换,参数类型只支持string类型。注意:使用该方法转换时string的值不能为为NULL,不然无法通过转换;另外string类型参数也只能是各种整型,不能是浮点型,不然也无法通过转换 (例如int.Parse("2.0")就无法通过转换)。

            int i;
            i = int.Parse("100");

(3)、通过int.TryParse()方法转换,该转换方法与int.Parse()转换方法类似,不同点在于int.Parse()方法无法转换成功的情况该方法能正常执行并返回0。也就是说int.TryParse()方法比int.Parse()方法多了一个异常处理,如果出现异常则返回false,并且将输出参数返回0。          

 int i;
 string s = null;
 int.TryParse(s,out i);

 

(4)、通过Convert类进行转换,Convert类中提供了很多转换的方法。使用这些方法的前提是能将需要转换的对象转换成相应的类型,如果不能转换则会报格式不对的错误。注意:使用Convert.ToInt32(double value)时,如果 value 为两个整数中间的数字,则返回二者中的偶数;即 4.5 转换为 4,而 5.5 转换为 6。

(5)、实现自己的转换,通过继承接口IConventible或者TypeConventer类,从而实现自己的转换。

六  值传递

  (一)定义:

     值类型在复制的时候,传递就是这个值得本身,例如:A同学的笔记复印了一份,给B同学,B同学任意修改笔记的内容,A同学都不会受到影响。

 技术分享

(二)例子:

            int n1 = 10;
            int n2 = n1;
            n2 = 20;
            Console.WriteLine(n1);
            Console.WriteLine(n2);
            Console.ReadKey(); //  输出结果:n1=10;  n2=20;      

分析:变量n1在栈区开辟一块空间,其地址为0x000000e4a99fe094 ,并且为其赋初值10;

          变量n2在栈区也开辟了一块空间,其地址为0x000000e4a99fe090,并n1值赋给了 n2,n2:10

          变量n2的值被重新赋值20,n2:20

(三)内存代码:

            &n1    0x000000e4a99fe094    n1: 0
            &n1    0x000000e4a99fe094    n1: 10
            &n2    0x000000e4a99fe090    n2: 0
            &n2    0x000000e4a99fe090    n2: 10
            &n2    0x000000e4a99fe090     n2: 20

由此可以看出:n1和n2在栈上的内存地址并不一样,所以在改变任意其中的而一个值,另一个并不受其影响

(四) 内存示意图:

 技术分享

七 、引用传递

(一)定义:

      引用类型在复制的时候,传递的是对这个对象的引用

(二)例子:         

  Person p1 = new Person();
  p1.Name = "张三";
  Person p2 = p1;
  p2.Name="李四";
  Console.WriteLine(p1.Name);
  Console.WriteLine(p2.Name);//   输出结果:李四 李四

分析:

      变量p1在栈中开辟一块空间,地址为:0x00000095e5efdfd ,并且在堆中也有一块空间,存放的是new Person();这个对象,其内存空间地址为:0x0000000000000000,并且为p1.name赋值张三

     变量p2在栈中也开辟一块空间,地址为:0x00000095e5efdfc8  ,此时,把p1对象赋值给p2对象,即p2也指向new Person()开辟的这块空间,其内存空间地址为:0x0000000000000000,随后,我们把p2.name赋值为 李四,那么由于p1.name也指向这块空间,所以,p1.name=”李四”

(四)内存代码:                        

 &p1  0x00000095e5efdfd   p1: 0x0000000000000000
 &p2  0x00000095e5efdfc8   p2: 0x0000000000000000

(五)内存示意图:

技术分享

 八  特殊的引用类型

  例子:      

            string s1 = "张三";
            string s2 = s1;
            s2 = "李四";
            Console.WriteLine(s1)
            Console.WriteLine(s2);

结果:s1=张三 s2=李四  string虽然为引用类型,但是string具有不可变性

九 、方法的参数类型

(一) 两类参数的定义:

实参:具有实际意义的参数,一般在调用方法时,在方法的括号里面传递的参数为实参

形参:在方法声明时,方法名后面括号里面的参数为形参,一般(值传递)形参是接收实参传过来的值

(二)  out参数:

1、定义:

       在一个方法需要返回多个参数的时候,一般在参数列表里面声明out类型的参数,以便输出多个返回值。其中,out参数只负责把结果输出,不负责输入参数。一般out声明的变量需要在方法体内部赋值

2、例子:

class Program
    {
        static void Main(string[] args)
        {
            int[] ShuZi = { 1,2,3,4,5,6};
            int max1;
            int min1;
            int sum1;
            JiSuan(ShuZi,out max1,out min1,out sum1);
            Console.WriteLine("数组的最大值为:{0},数组的最小值为:{1},数组的和为:{2}",max1,min1,sum1);
            Console.ReadKey();
        }
        public static void JiSuan(int []number,out int max,out int  min,out int sum)
        {
            max = number[0];
            min = number[0];
            sum = 0;
            for (int i = 0; i < 6; i++)
            {
                sum += number[i];
                if (number[i] > max)
                {
                    max = number[i];
                }
                else
                {
                min=number[i];
                }
            }
        }
    }

 

输出结果为:最大值:6,最小值:1,和为21

(二)ref参数

1、定义:

      即可以传入值,又可以传出值,双向性

(二)例子;

  

class Program
    {
        static void Main(string[] args)
        {
            int n1=10;
            int n2=20;
            Console.WriteLine("两个数字交换之前的值为n1={0},n2={1}",n1,n2);
            JiaoHuan(ref n1, ref n2);
            Console.WriteLine("两个数字交换之后的值为n1={0},n2={1}", n1, n2);
            Console.ReadKey();
        }
        public static void JiaoHuan( ref int n1,ref int n2)
        {
            int temp = n1;
            n1 = n2;
            n2 = temp;
        }
}

结果为:

   两个数字交换之前的值为n1=10,n2=20

   两个数字交换之后的值为n1=20,n2=10 

 

参考资料:《c#图解教程》

学习系列之数据类型

标签:style   总结   示意图   精度   code   else   出栈   堆内存   代码   

原文地址:http://www.cnblogs.com/wyh19941210/p/7469846.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!