b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

【每日一题】引用类型和值类型的存储方式

电脑杂谈  发布时间:2021-05-07 09:02:08  来源:网络整理

一、在讨论堆栈之前,让我们看一下值类型和引用类型

c#堆和栈和内存的关系

1,让我们看一下值类型和引用类型的存储方法:

引用类型:引用类型存储在堆中。实例化类型时,将在堆中创建一部分空间来存储类的实例。对类对象的引用仍存储在堆栈中。

值类型:值类型总是分配在声明它的地方,当它用作局部变量时,它存储在堆栈中;当它是类对象的字段时,它将存储在该类之后的堆中。

什么是堆,什么是栈将在后面解释。

c#堆和栈和内存的关系

图1-1

2,让我们看一下引用类型和值类型之间的区别:

①引用类型和值类型均从Systerm.Object类继承。区别在于几乎所有引用类型都直接继承自Systerm.Object,而值类型是Systerm.Object,Systerm.ValueType的子类。

②当我们给引用类型的变量赋值时,实际上只是给对象分配了一个引用。然后,当我们将值分配给值类型的变量时,我们会创建一个副本(不理解该副本吗?更简单地说,我们会克隆一个变量)。

文字不够生动?让我们看一下代码

c#堆和栈和内存的关系

图1-2

3,让我们看一下引用类型和值类型的内存分配(我们看一下代码和图片)

c#堆和栈和内存的关系

图1-3

c#堆和栈和内存的关系

图1-4

在阅读完图1-3和图1-4之后,您可能会问我:您如何知道堆栈中变量的地址?嘿,等我教你用c#玩指针

从以上两张图片中,我们可以看到:

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

②堆栈地址从高到低分配

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

二、要详细了解堆和堆栈,让我们往下看。

1,有些人总是不理解堆和栈的名称。让我解释一下:

堆:在c中称为堆,但实际上在c#中称为托管堆。为什么将其称为托管堆,让我们往下看。

堆栈:它是堆栈,因为它与堆一起被称为笨拙,所以简称为堆栈。

2,托管堆:

托管堆与堆不同。它由CLR(公共语言运行时)管理。当堆满时,它将自动清理堆中的垃圾。因此,作为.net开发,我们不需要关心内存释放。

3,有些人总是对内存堆栈和数据结构堆栈感到困惑,让我们看一下什么是内存堆栈以及什么是数据结构堆栈

①数据结构栈:它是后进先出的数据结构。这是一个概念。如图4-1所示,堆栈是后进先出的数据结构。

②内存堆栈:内存中有两个存储区域(堆区域,堆栈区域)。

堆栈区域:存储函数参数,局部变量,返回数据和其他值,这些参数由编译器自动释放

堆区域:存储由CLR发布的引用类型对象

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

1,首先,右键单击项目->属性->生成->检查以允许使用不安全的代码

c#堆和栈和内存的关系

2,编写不安全代码时需要添加不安全

    //标记类
    unsafe public class Student
    {
        //标记字段
        unsafe int* pAge;
        //标记方法
        unsafe void getType(int* a)
        {
            //标记代码段
            unsafe
            {
                int* pAbc;      //声明指针语法
            }
        }
    }

3,指针的语法

            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类型)

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

5。强制替换指针类型

int b = 10;
int* pIa;
double* pDa;
pIa = &b;
pDa = (double*)pIa;//将int*强制转换成double*

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

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

7,指针算术运算(不允许对void指针进行操作)

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

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

①指针不能只想到任何引用类型

②结构不能包含引用类型

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,类成员指针

Person p = new Person();
fixed (int* pIp1 = &(p.X), pIp2 = &(p.Y))
{
}//pIp1和pIp2的生命周期
//类
class Person
{
     public int X;
     public int Y;
}

10,有趣的实验

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
}


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-373651-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...