当前位置: 首页 > news >正文

【从零开始入门unity游戏开发之——C#篇04】栈(Stack)和堆(Heap),值类型和引用类型,以及特殊的引用类型string

文章目录

  • 知识回顾
  • 一、栈(Stack)和堆(Heap)
    • 1、什么是栈和堆
    • 2、为什么要分栈和堆
    • 3、栈和堆的区别
    • 4、总结
  • 二、值类型和引用类型
    • 1、那么值类型和引用类型到底有什么区别呢?
      • 值类型
      • 引用类型
    • 2、总结
  • 三、特殊的引用类型string
    • 1、为什么说string是特殊的引用类型?
    • 2、理解字符串(string)引用类型
    • 3、如何证明呢?
      • 使用 `GetHashCode` 方法
      • 通过断点调试直接查看变量指针内存地址
    • 4、总结
  • 专栏推荐
  • 完结

知识回顾

C# 中的变量类型可以分为 值类型引用类型 两大类。

值类型

变量类型描述范围
byte无符号8位整数0 到 255
sbyte有符号8位整数-128 到 127
short有符号16位整数-32,768 到 32,767
ushort无符号16位整数0 到 65,535
int有符号32位整数-2,147,483,648 到 2,147,483,647
uint无符号32位整数0 到 4,294,967,295
long有符号64位整数-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
ulong无符号64位整数0 到 18,446,744,073,709,551,615
float32 位单精度浮点数±1.5 × 10^−45 到 ±3.4 × 10^38(精度约7位有效数字)
double64 位双精度浮点数±5.0 × 10^−324 到 ±1.7 × 10^308(精度约15–16位有效数字)
decimal128 位高精度小数±1.0 × 10^−28 到 ±7.9 × 10^28(精度约28–29位有效数字)
bool8 位布尔型truefalse
char16 位单一字符型Unicode字符(0 到 65,535)

引用类型

变量类型描述范围
string字符串任意长度的字符序列(理论上最多可达到 2GB)

一、栈(Stack)和堆(Heap)

要了解值类型和引用类型的区别,我们得先得栈和堆的概率有个了解。

1、什么是栈和堆

简单理解就是,程序运行时,它的数据必须存储在内存中。栈和堆就是计算机内存中的两种不同的存储区域。

2、为什么要分栈和堆

通过分栈和堆,程序可以在性能和内存管理上做出平衡,从而让程序既高效又灵活。

3、栈和堆的区别

  • 栈空间比较小,但是读取速度快。
  • 栈存储的是一些简单的数据
  • 栈遵循先进后出原则,栈就像一个堆叠的盘子。你每次放入一个新盘子(数据),都会把它放在最上面。拿东西的时候,也都是从最上面拿,所以非常快速。
  • 栈里的数据只在当前函数或方法运行时有效,一旦方法执行完毕,这些数据就会自动被销毁。
    在这里插入图片描述

  • 堆空间比较大,但是读取速度慢。
  • 堆存储的是一些较大的数据。
  • 堆就像一个大大的垃圾堆,可以随意放东西。它不按照顺序来存放数据,而是根据需要分配空间,可以存储更复杂的对象
  • 堆中的数据不会像栈那样自动清理。(但在 C# 中,垃圾回收会自动清理不再使用的对象)

在这里插入图片描述

4、总结

实际上,我们写程序并不需要关心内存是如何使用的,C#已经帮我们做好了。这里只是简单介绍这个概念,有些知识看不懂也没关系,比如垃圾回收,后面肯定还会详细介绍。现在有个印象就行。


二、值类型和引用类型

在 C# 中,数据类型分为两大类:值类型(Value Types)和 引用类型(Reference Types)。

我们目前学了值类型和引用类型只有变量,但是其实不止

  • 值类型其实还有结构体(Struct)枚举(Enum)
  • 引用类型还有类(Class)数组(Array)委托(Delegate)

这些我们后面会一一介绍,现在了解一下就行。

1、那么值类型和引用类型到底有什么区别呢?

因为只学了变量,这里就用变量举例。

值类型

  • 直接存储数据,值类型的变量直接保存它们的数据。值类型直接存储在上。
  • 值类型赋值时,会复制值本身

比如

int a, b;
a = 100;
b = a;
Console.WriteLine("a的值:" + a);
Console.WriteLine("b的值:" + b);a = 20; // 重新给a赋值,b的值不会改变
Console.WriteLine("a的值:" + a);
Console.WriteLine("b的值:" + b);

打印结果,正如前面所说,重新给a赋值,b的值不会改变
在这里插入图片描述

画图说明
在这里插入图片描述
解释

  • 声明变量 int a, b;
    当你声明两个整数变量 a 和 b 时,编译器会在栈上为它们各自分配32位的存储空间。此时,这两个存储空间是空的,没有初始化任何值。

  • 赋值 a = 100;
    当你给变量 a 赋值为 20 时,栈上的存储空间 a 会被写入值 20。这个操作不会重新分配内存,而是直接在已经分配的内存位置写入新的值。

  • 赋值 b = a;
    当你执行 b = a; 时,栈上的存储空间 b 会被写入 a 的当前值。此时,a 和 b 都存储了值 20,但它们是独立的存储空间。

  • 重新赋值 a = 20;
    当你再次给 a 赋值为 20 时,栈上的存储空间 a 会被更新为新的值 20。这不会重新分配内存,而是直接在已经分配的内存位置写入新的值。

引用类型

  • 间接存储数据,引用类型的变量保存的是对实际数据所在位置的引用或地址(也叫指针),而不是数据本身。引用类型存储在栈上的引用(或指针)和堆上的实际数据
  • 引用类型赋值时,会复制引用,但实际的数据不会复制。

画图说明,假设a b c都是引用类型
在这里插入图片描述
解释

  • 声明引用类型 a 和 b;

    这时 a 和 b 都是空引用,它们在栈上分配了空间,但它们指向的堆内存地址尚未确定,二者目前都没有引用任何实际的对象。

  • 给 a 赋值:

    此时,a 作为栈上的一个引用变量,指向堆上的值。b 仍然是空引用。

  • b = a; b 也指向 a 的堆值:

    此时,a 和 b 都存储相同的堆内存地址,指向相同的堆对象。

  • a 修改为新值:

    这时候a b的值就都变成了新值

  • 重新定义 c,并给 c 赋值

    此时,c 是一个新的引用类型变量,它在栈上存储了指向堆上c值的地址,且与 a 和 b 的值互不影响。

ps:有些小伙伴可能会说了,前面不是说了string不就是引用类型吗,为什么不用string举例呢,这样不是更加直观?其实是因为string是特殊的引用类型,这个问题我接下来会说。

2、总结

特性值类型 (Value Type)引用类型 (Reference Type)
存储方式存储数据的值本身存储数据的引用(内存地址)
赋值行为赋值时会复制数据,原始值和复制值互不影响赋值时会复制引用,两个变量指向同一个对象
存储位置通常存储在栈上 (stack),但结构体和其他类型可能存储在堆上存储在堆上 (heap),引用存储在栈上
初始化默认值为零或空值(如 0falsenull默认值为 null
内存管理系统负责管理内存(栈上分配的内存自动释放)由垃圾回收器 (GC) 管理内存
常见类型基本数据类型(如 intfloat 等)、结构体、枚举类、数组、委托、字符串等

三、特殊的引用类型string

1、为什么说string是特殊的引用类型?

学了前面引用类型的知识,我们可以拿string测试一下试试。

string str1, str2;
str1 = "名";
str2 = str1;
Console.WriteLine("str1的值:" + str1);
Console.WriteLine("str2的值:" + str2);str1 = "字";//重新赋值str1
Console.WriteLine("str1的值:" + str1);
Console.WriteLine("str2的值:" + str2);

按前面引用类型的概念,可能你想说第二次打印的结果应该是"字" "字"

实际上真是这样吗?我先来看看执行结果
在这里插入图片描述
有人会说,如果是值类型,结果倒还说的过去.但是不是说string是引用类型么?如果是引用类型的话。输出的结果难道不应该是: "名""名""字" "字"么?

2、理解字符串(string)引用类型

理解字符串(string)在C#中的行为确实可能有些困惑,因为它们在某种程度上表现出值类型和引用类型的特性。让我们来详细解释一下。

  • 字符串是不可变
    字符串在C#中是不可变的,这意味着一旦你创建了一个字符串对象,就不能修改它的内容。当你尝试修改一个字符串时,实际上是创建了一个新的字符串对象。

  • 字符串为什么是引用类型
    因为它们在堆上分配内存,并且在栈上存储对堆上对象的引用。因此,多个变量可以引用同一个字符串对象。

3、如何证明呢?

使用 GetHashCode 方法

虽然这并不返回内存地址,但 GetHashCode 方法会返回一个与字符串内容相关的哈希值。这个值可以作为字符串的“标识符”,有时候在调试中,它能帮助你判断是否为同一个字符串实例。

string str1 = "xxxx";
string str2 = str1;
Console.WriteLine(str1.GetHashCode());
Console.WriteLine(str2.GetHashCode());str1 = "yyyy";
Console.WriteLine(str1.GetHashCode());
Console.WriteLine(str2.GetHashCode());

结果
在这里插入图片描述

通过断点调试直接查看变量指针内存地址

在这里插入图片描述
值类型,一开始内存地址就不一样
在这里插入图片描述
string引用类型,开始地址一样,重新赋值后地址不一样了
在这里插入图片描述
在这里插入图片描述

4、总结

字符串不叫值类型,因为它们确实具有引用类型的基本特性:在堆上分配内存,并且在栈上存储引用。尽管字符串的不可变性使得它们在某些方面表现得像值类型,但从技术上讲,它们仍然是引用类型。

由于字符串的不可变性,即使它们是引用类型,修改一个字符串变量不会影响其他引用相同字符串的变量。这是因为当你修改字符串时,实际上是创建了一个新的字符串对象,并将变量的引用指向了这个新对象。

string虽然方便,但是有一个小缺点就是频繁的改变string重新赋值会产生内存垃圾,优化替代方案我们会在后面进行讲解


专栏推荐

地址
【从零开始入门unity游戏开发之——C#篇】
【从零开始入门unity游戏开发之——unity篇】
【制作100个Unity游戏】
【推荐100个unity插件】
【实现100个unity特效】
【unity框架开发】

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

相关文章:

【从零开始入门unity游戏开发之——C#篇04】栈(Stack)和堆(Heap),值类型和引用类型,以及特殊的引用类型string

文章目录 知识回顾一、栈(Stack)和堆(Heap)1、什么是栈和堆2、为什么要分栈和堆3、栈和堆的区别栈堆 4、总结 二、值类型和引用类型1、那么值类型和引用类型到底有什么区别呢?值类型引用类型 2、总结 三、特殊的引用类…...

ARCGIS国土超级工具集1.2更新说明

ARCGIS国土超级工具集V1.2版本,功能已增加至47 个。在V1.1的基础上修复了若干使用时发现的BUG,新增了"矢量分割工具"菜单,同时增加及更新了了若干功能,新工具使用说明如下: 一、勘测定界工具栏更新界址点成果…...

暂停window11自动更新

window11 的自动更新功能,一方面在后台占用资源,容易导致电脑卡顿;另一方面,“更新并关机” 和 “更新并重启” 的设置令人极其反感。很多补丁兼容性很差,更新后极易引发电脑蓝屏、闪屏等意想不到的 bug。 1.winR打开运…...

Git简介和特点

目录 一、Git简介 二、Git特点 1.集中式和分布式 (1)集中式版本控制系统 (2)分布式版本控制系统 2.版本存储方式的差异 (1)直接记录快照,而非差异比较 3.近乎所有操作都是本地执行 一、Git简介 Git是目前世界上最先进的的分布式控制系统(没有之一…...

如何通过docker 部署minio,端口号为9105

通过Docker部署MinIO对象存储服务,并指定API端口为9105,可以按照以下步骤进行。我们将基于已有的资料来详细说明这一过程。 1. 准备工作 首先,确保你的系统上已经安装了Docker。如果没有安装,可以根据官方文档指导完成安装。接下…...

设置Qt程序开机自启动(windows版本)

前言 本文展示在windows环境下,通过代码实现更改系统注册表的方式来实现程序的开机自动启动。 一、注册表 需要更改的系统注册表为: HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run 二、代码演示 1.头文件 头文件autorun.h #ifndef …...

【HarmonyOS】鸿蒙获取appIdentifier,Identifier

【HarmonyOS】鸿蒙获取appIdentifier,Identifier 一、前言 三方后台需要填写的所谓appIdentifier,Identifier信息,其实对应鸿蒙应用的appID。 二、解决方案: 注意,模拟器获取data.signatureInfo.appIndentifer为空…...

【Rust自学】3.5. 控制流:if else

3.5.0. 写在正文之前 欢迎来到Rust自学的第三章,一共有6个小节,分别是: 变量与可变性数据类型:标量类型数据类型:复合类型函数和注释控制流:if else(本文)控制流:循环 通过第二章…...

美国信息学奥林匹克竞赛USACO 2024年12月比赛铜级问题1. 循环舍入-答案代码

题目见&#xff1a; USACO 2024年12月比赛铜级问题1. 循环舍入(USACO 2024 December Contest, Bronze Problem 1. Roundabount Rounding) 最简单的青铜级 亲测所有得分点通过哈&#xff01; 下一篇会给解题分析哦&#xff01; #include <iostream> using namespace std;…...

Llama3模型详解 - Meta最新开源大模型全面解析

&#x1f4da; Meta最新发布的Llama3模型在开源社区引起广泛关注。本文将全面解析Llama3的技术特点、部署要求和应用场景。 一、模型概述 1. 基本信息 发布机构: Meta AI开源协议: Llama 2 Community License Agreement模型规格: 7B/13B/34B/70B训练数据: 2万亿tokens上下文长…...

2021-02-12 c++里面cin.sync()函数的意思

回复急~救救菜鸡吧&#xff0c;C用cin.clear()和cin.sycn()清空缓存区一直清不了!_编程语言-CSDN问答 标识符号为:goodbit 无错误 Eofbit 已到达文件尾 failbit 非致命的输入/输出错误可挽回 badbit 致命的输入/输出错误无法挽回 int a 0;cin >> a;if (cin.rdstate() i…...

下载红米Note 9 Pro5G对应的LineageOS代码下载及编译

构建 LineageOS 进入网站&#xff1a;Info about gauguin | LineageOS Wiki&#xff0c;点击&#xff1a;Build for yourself&#xff0c;里面有详细的教程&#xff0c;我这里就按照Note 9 Pro 5G来。 机器环境 Ubuntu环境为&#xff1a;20.04.6LinagesOS版本&#xff1a;21-…...

《探索 Caffe2 的 C++接口在移动设备上的性能优化之路》

在当今移动应用日益智能化的时代&#xff0c;将深度学习框架如 Caffe2 的 C接口应用于移动设备上已成为众多开发者的目标。然而&#xff0c;移动设备资源相对有限&#xff0c;如何优化其性能成为了关键挑战。 一、移动设备应用深度学习的现状与挑战 随着智能手机等移动设备的…...

1.编写一个程序,给定一个大写字母,要求用小写输出

思路&#xff1a;ascII码值 例如&#xff1a;A的ASCII码值为65&#xff0c;a的ASCII码值为97&#xff0c;不难发现&#xff0c;大小写字母之间的ascii值相差了32 #include <stdio.h> int main() {char c;scanf("%c",&c);printf("%c",c32);retu…...

条件随机场(CRF)详解:原理、算法与实现(深入浅出)

目录 1. 引言2. 什么是条件随机场&#xff1f;2.1 直观理解2.2 形式化定义 3. CRF的核心要素3.1 特征函数3.2 参数学习 4. 实战案例&#xff1a;命名实体识别5. CRF vs HMM6. CRF的优化与改进6.1 特征选择6.2 正则化 7. 总结与展望参考资料 1. 引言 条件随机场(Conditional Ra…...

Android Studio、JDK、AGP、Gradle、kotlin-gradle-plugin 兼容性问题

文章目录 问题&#xff1a;解决办法&#xff1a;gradle与 java的版本兼容AGP与Gradle的版本兼容kotlin 与 jvm 的版本兼容KGP、Gradle、AGP兼容关系kotlin 与 java 的编译版本配置 问题&#xff1a; 你从githb上clone了一个项目&#xff0c;本地跑的时候&#xff0c;各种报错。…...

防抖(Debounce)和节流(Throttle)的区别和应用场景

防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09;虽然都是用来限制函数的执行频率&#xff0c;但它们的实现方式和应用场景有所不同。以下是两者的主要区别&#xff1a; 1. 执行原理 防抖&#xff08;Debounce&#xff09;&#xff1a; 执行条件&a…...

前端 Code Review 常见问题

在前端开发中&#xff0c;代码审查&#xff08;Code Review&#xff09;是一个至关重要的步骤。它不仅可以帮助团队成员之间共享知识和经验&#xff0c;还可以提高代码质量&#xff0c;减少错误和安全漏洞。以下是一些常见的前端 Code Review 问题和相应的解决方案。 1. 不一致…...

Python监控AWS ECS集群和服务的CPU和内存利用率

在电子商务或其他行业,重要节日通常会带来大量的流量和订单,这对应用程序的资源利用率提出了更高的要求。为了确保应用程序在节日期间能够顺利运行,提前监控和优化资源利用率至关重要。 在本文中,我们将介绍如何使用Python编写一个脚本,从AWS CloudWatch中获取ECS集群和服务的…...

淘宝天猫API接口深度解析:如何高效利用商品详情与关键词搜索商品列表功能

在电子商务的浩瀚海洋中&#xff0c;淘宝和天猫作为两大巨头&#xff0c;其平台上的商品信息无疑是商家和消费者关注的焦点。为了更高效地获取这些信息&#xff0c;淘宝天猫开放平台提供了丰富的API接口&#xff0c;其中商品详情接口和关键词搜索商品列表接口尤为关键。本文将深…...

python快速接入阿里云百炼大模型

1.注册阿里云账号 访问阿里云官网&#xff0c;完成账号注册流程&#xff0c;并开通百炼服务&#xff0c;网址&#xff1a;https://bailian.console.aliyun.com 2.获取 API Key 登录阿里云百炼平台&#xff0c;在个人中心或相关设置页面找到并生成 API Key&#xff0c;妥善保管此…...

基于AI对话生成剧情AVG游戏

游戏开发这个领域&#xff0c;一直有较高的学习门槛。作为一个非专业的游戏爱好者&#xff0c;如果想要开发游戏&#xff0c;往往受制于游戏引擎的专业程度&#xff0c;难以完成复杂的游戏项目。 AI IDE的诞生&#xff0c;提供了另外的一种思路&#xff0c;即通过AI 生成项目及…...

[flutter] 安卓编译配置

Maven 镜像 android/build.gradle buildscript {ext.kotlin_version 1.7.10repositories {google() // mavenCentral()maven { url https://maven.aliyun.com/repository/google }maven { url https://maven.aliyun.com/repository/jcenter }maven { url https://mav…...

使用ENSP实现NAT(2)

一、NAT的类型 二、静态NAT 1.项目拓扑 2.项目实现 路由器AR1配置&#xff1a; 进入系统视图 sys将路由器命名为AR1 sysname AR1关闭信息中心 undo info-center enable 进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为192.168.10.254/24 ip address 192.168.10.254 24进…...

解决小程序中ios可以正常滚动,而Android失效问题

解决小程序中 iOS 可以正常滚动&#xff0c;而 Android 失效问题 在开发小程序时&#xff0c;我们经常会遇到一些平台兼容性问题。最近&#xff0c;我在开发一个小程序时遇到了一个问题&#xff1a;在 iOS 设备上可以正常滚动加载更多数据&#xff0c;而在 Android 设备上却无…...

docker安装部署

1.Docker简介 Docker是一个开源的容器引擎,开发者可以打包应用以及相关依赖包到一个可移植的容器中,发布到任何流行的Linux机器上。容器是完全使用沙箱机制,相互之间不会有任何接口,而且更轻量级。 1.1 概念 docker会自动搜索并下载应用镜像,镜像不仅包含应用本身,还包含…...

百度23届秋招研发岗A卷

百度23届秋招研发岗A卷 2024/12/16 1.下面关于 SparkSQL 中 Catalyst 优化器的说法正确的是&#xff08;ABC&#xff09; A.Catalyst 优化器利用高级编程语言功能&#xff08;例如 Scala 的模式匹配&#xff09;来构建可扩展的查询优化器 B.Catalyst 包含树和操作树的规则集…...

metrics.roc_curve函数介绍

目录 函数介绍使用方法 函数介绍 metrics.roc_curve 是 scikit-learn 中的一个函数&#xff0c;用于计算接收者操作特征曲线&#xff08;Receiver Operating Characteristic, ROC&#xff09;曲线的参数。 具体来说&#xff0c;metrics.roc_curve 函数接受真实的标签和预测标…...

stm32进硬件错误怎么回事

STM32进入硬件错误状态&#xff0c;通常是由一些特定的编程或硬件问题引起的。以下是一些可能的原因及相应的解决方法&#xff1a; 可能的原因 数组越界操作&#xff1a;在编程过程中&#xff0c;如果数组访问超出了其定义的边界&#xff0c;可能会导致内存访问错误&#xff0…...

【网络安全】掌握 Active Directory 攻防审计实操知识点

掌握 Active Directory 攻防审计实操知识点 在深入了解 Active Directory 之前&#xff0c;我们需要先掌握网络基础设施的映射和资源访问管理方式。这一切通常通过目录服务 (Directory Services) 实现&#xff0c;目录服务在组织内提供网络资源的映射和访问。轻量目录访问协议…...