zoukankan      html  css  js  c++  java
  • C# 堆与栈

    一、在讲堆栈之前,我们先看看值类型和引用类型:

    1,我们看看值类型与引用类型的存储方式:

    引用类型:引用类型存储在堆中。类型实例化的时候,会在堆中开辟一部分空间存储类的实例。类对象的引用还是存储在栈中。

    值类型:值类型总是分配在它声明的地方,做为局部变量时,存储在栈上;类对象的字段时,则跟随此类存储在堆中。

    什么是堆什么是栈我们后面解释。

                       图1-1

    2,我们再看看引用类型与值类型的区别:

    ①引用类型和值类型都继承自Systerm.Object类。不同之处,几乎所有的引用类型都是直接从Systerm.Object继承,而值类型则是继承Systerm.Object的子类Systerm.ValueType类。

    ②我们在给引用类型的变量赋值的时候,其实只是赋值了对象的引用;而给值类型变量赋值的时候是创建了一个副本(副本不明白?说通俗点,就是克隆了一个变量)。

    文字不够形象?我们上代码看看

                                           图1-2

     3,我们再看看引用类型和值类型的内存分配情况(我们对着代码与图看)

                                          图1-3

                                       图1-4

     看了图1-3和图1-4之后,你们可能问我了:你是怎么知道变量在栈中的地址的。嘿嘿,等下教你用c#玩指针

    从上面两张图我们可以看出:

    ①栈的结构是后进先出,也就是说:变量j的生命周期在变量s之前结束,变量s的生命周期在变量i之前结束,

    ②栈地址从高往底分配

    ③类型的引用也存储在栈中

    二、对于堆和栈的详细介绍,我们往下看。

    1,有人老是搞不明白堆和栈的叫法。我来解释下:

    堆:在c里面叫堆,在c#里面其实叫托管堆。为什么叫托管堆,我们往下看。

    栈:就是堆栈,因为和堆一起叫着别扭,就简称栈了。

    2,托管堆:

    托管堆不同于堆,它是由CLR(公共语言运行库(Common Language Runtime))管理,当堆中满了之后,会自动清理堆中的垃圾。所以,做为.net开发,我们不需要关心内存释放的问题。

    3,有人老是搞不清楚内存堆栈与数据结构堆栈,我们来看看什么是内存堆栈,什么是数据结构堆栈

    ①数据结构堆栈:是一种后进先出的数据结构,它是一个概念,图4-1中可以看出,栈是一种后进先出的数据结构。

    ②内存堆栈:存在内存中的两个存储区(堆区,栈区)。

          栈区:存放函数的参数、局部变量、返回数据等值,由编译器自动释放

          堆区:存放着引用类型的对象,由CLR释放

     三、最后我们用c#玩一玩指针

    1,首先右键项目-->属性-->生成-->勾选允许不安全代码

    2,在写不安全代码的时候需要加上unsafe

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //标记类
    unsafe public class Student
    {
        //标记字段
        unsafe int* pAge;
        //标记方法
        unsafe void getType(int* a)
        {
            //标记代码段
            unsafe
            {
                int* pAbc;      //声明指针语法
            }
        }
    }

      

    3,指针的语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    unsafe
    {
        int* pWidth, pHeight;
        double* pResult;
        byte*[] pByte;
        //&:表示“取地址”,并把一个值数据类型转换为指针,例如,int转换为*int。这个运算称为【寻址运算符】
        //*:表示“获取地址内容”,把一个指针转换为一个值数据类型(例如:*float转换为float)。这个运算符被
            //称为“间接寻址运算符”(有时称“取消引用运算符”)
        int a = 10;//声明一个值类型,给它赋值10
        int* pA, pB;//声明2个指针
        pA = &a;//取出值类型a的地址,赋值给指针pA
        pB = pA;//把指针pA的地址赋值给pB
        *pB = 20;//获取pB指向的地址内容,并赋值20
        Console.WriteLine(a);//输出20
    }

      

    4,将指针强制转化为整数类型(只能转化为uing、long、ulong类型)

    1
    2
    3
    4
    5
    6
    7
    int a = 10;
    int* pA, pB;
    pA = &a;
    uint address = (uint)pA;//将指针地址强制转换为整数类型
    pB = (int*)address;//将整数类型强制转换为指针
    *pB = 20;//指针指向a
    Console.WriteLine(a);//输出20

      

    5,指针类型的强制装换

    1
    2
    3
    4
    5
    int b = 10;
    int* pIa;
    double* pDa;
    pIa = &b;
    pDa = (double*)pIa;//将int*强制转换成double*

      

    6,void指针(不指向任何数据类型的指针)

    1
    2
    3
    4
    int c = 10;
    int* pAA;
    pAA = &c;
    void* pVa = (void*)pAA;//转换viod指针

      

    7,指针算数的运算(不允许对void指针进行运算)

    1
    2
    3
    4
    int d = 10;
    int* pId;//如果地址为100000
    pId = &d;
    pId++;//结果:100004(int类型的大小为4个字节)

      

    8,结构指针:指针成员访问运算符

    ①指针不能只想任何引用类型
    ②结构里面不能包含引用类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    MyStruct* pStruct;
    MyStruct ms = new MyStruct();
    pStruct = &ms;
    //--取地址内容赋值为10
    (*pStruct).X = 10;
    pStruct->X = 10;
    //--取地址赋值给pIs
    int* pIs1 = &(ms.X);
    int* pIs2 = &(pStruct->X);
    //结构
    struct MyStruct
    {
            public int X = 1;
            public int Y = 2;
    }

      

    9,类成员指针

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Person p = new Person();
    fixed (int* pIp1 = &(p.X), pIp2 = &(p.Y))
    {
    }//pIp1和pIp2的生命周期
    //类
    class Person
    {
         public int X;
         public int Y;
    }

      

    10,有趣的实验

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    unsafe
    {
    //有趣的问题:为什么b的值改变了
    //回答:因为i的地址指向了b
    int a = 10;
    int b = 20;
    int* i;
    i = &a;//将a的地址赋值给指针i
    i -= 1;//将i的地址-1(相当于向下移动4个字节(int类型的大小为4个字节))
    *i = 30;//取出i指针指向的内容赋值为30
    Console.WriteLine(b);//输出30
    }

      

  • 相关阅读:
    pat 甲级 1065. A+B and C (64bit) (20)
    pat 甲级 1064. Complete Binary Search Tree (30)
    pat 甲级 1010. Radix (25)
    pat 甲级 1009. Product of Polynomials (25)
    pat 甲级 1056. Mice and Rice (25)
    pat 甲级 1078. Hashing (25)
    pat 甲级 1080. Graduate Admission (30)
    pat 甲级 团体天梯 L3-004. 肿瘤诊断
    pat 甲级 1099. Build A Binary Search Tree (30)
    Codeforce 672B. Different is Good
  • 原文地址:https://www.cnblogs.com/summer2008/p/13723380.html
Copyright © 2011-2022 走看看