c# 中的变量和常量

2.3.1 变量

定义变量的语法格式

   [访问修饰符] 数据类型 变量名[=初始值];

例如 string name = “王华”;

     int age = 20;

 

C# 3.0 开始引入新关键字var,它可以在指定变量中替代“数据模型”,其使用格式如下

  Var变量名 = 初始值

这样定义的变量成为隐士类型的变量,必须同时初始化。

Var n = 10 ;//在运行此行代码时,变量n 隐士的转换为int类型,所以var不是类型名,也不是定义一个没有类型的变量,更不是定义一个类型可变的变量,否则c#就不再是强类型化的语言了。

 

 定义任何一个变量,系统就会在内存中开辟相应大小的空间来存放数据,用户可以从四个层面来理解。

  1 变量的名称

在定义一个变量时,系统根据它的数据类型为其分配相应大小的内存空间,此空间用来存放数据,变量名称和该内存空间绑定在一起的对变量名称的操作,即对该内存的操作。

2 变量的值

  变量的值表示变量的名称所指向的内存空间中存储的内容。

  在c# 中不允许使用未初始化的值,但在c# 中每种值类型均有一个隐士的默认构造函数来初始化该类型的默认值,在使用new运算符时,将调用特定类型的默认构造函数并对变量赋默认值。

例如 int n = new int();语句等同于 定义了整型变量并且对其初始化为默认值0.

3 变量的数据类型

变量的数据类型决定了这个变量可以容纳什么样的数据。

4 变量的作用域与和生命周期

  变量的作用域:变量的作用范围,若一个变量超过了其他的作用域,就失去了意义,会被销毁

  变量的生命周期:变量从定义到销毁的这段时间。

2.3.2  值类型变量和引用类型变量的区别

  在程序中运行时,系统会为其分配运行空间,用于存放临时数据,该内存空间分为栈空间和堆空间。

值类型---栈空间  引用类型—堆空间

1 栈空间和堆空间

栈空间用于存储以下类型的数据

*某些类型变量的值

*程序当前的执行环境

*传递给方法的参数

由系统管理所有的栈空间操作,当一个数据出栈后,其空间由系统自动收回。

堆空间时一块内存空间,在堆空间中可以分配大块的内存以存储某类型的数据对象,与栈不同的是,堆里的空间能够以任意顺序存入和移除。

虽然程序可以在堆空间里保存数据,但不能显式的删除它们。CLR的垃圾回收器在判断程序的代码不会再访问某数据时将自动清除无用的堆数据对象。

2 理解值类型的变量

C# 中的值类型变量和c/c++语言中的普通变量相似,这类变量直接包含它们的值,所有的值类型均隐式派生自System.Value Type。

在c#中,在内存的栈空间中为值类型分配空间,值类型变量会随着方法的调用后栈空间的消亡而自动清除。

当定义一个值类型变量并且给它赋值的时候,这个变量只能存储相同类型的数据,另外,当把某个值赋给某个值类型的变量时,c#会首先创建这个值的一个副本,然后把这个副本放在变量名所标记的存储位置上。对于引用类型却不是这样。

3 理解引用类型的变量

在c/c++ 中可以定义指针变量

而在c#中没有指针,而是引用,引用表示某个对象的地址而不是变量或对象本身,在c#中引用类型变量和它所指向的对象的关系如同指针。

无论值类型变量还是引用类型变量,都是在栈空间中分配对应的存储空间,但是,引用类型变量所指的对象是在托管堆上分配内存空间的。

在c#中定义一个引用类型变量时,系统在栈空间中为该引用变量分配存储空间,要想创建对象并且把对象的存储地址赋给该变量,就需要使用new操作符。

MyClass var ;//MyClass是已经定义的类或类型

Var = new MyClass()//创建var引用的实例

第二个语句使用new操作符创建对象,c#会在堆存储空间中为这个对象分配足够的空间来存放MyClass类的一个实例,然后会把这个实例的地址赋给这个引用类型变量var,以后可以通过这个引用类型变量var来操作堆中创建的那个对象。

说明:

在c中,指针变量可以指向相应类型的某个变量,也可以指向某个没有变量名的内存空间,对于后者,只能通过该指针变量对这个内存空间进行操作。而在c#中,引用类型变量指向的实例都是没有名称,所以不再使用指针,引用类型变量指向的实例统一在堆空间中分配空间,以便统一收回,这也是c#语言更加安全的特性之一。

在c#中引用类型只有类,接口,数组和委托,下面以数组引用类型变量为例,进一步说明引用类型变量和值类型变量的区别。

int[]a = new int[3]{1,2,3};//定义一个数组a

for (int i =0;i<3 ;i++)
    Console.Write("{0}",a[i]);//输出数组a的所有的元素

Console.WriteLine();

int[]b = a ;//定义一个数组b并赋值给为a
for (int i = 0;i<3 ;i++)
    b[i] *=2;//修改数组b中的元素

for (int i =0;i<3 ;i++)
    Console.Write("{0}",a[i]);//再次输出数组a的所有的元素
Console.WriteLine();

此代码先定义了一个数组a(引用类型变量)并且初始化,实际上,数组{1,2,3}是在堆空间中分配,并且将其地址存放在变量a中,后来又定义了数组b(引用类型变量),将a复制给b,也就是将数组{1,2,3}在堆空间中的地址赋给b,这样a,b中都存放该数组的地址,再通过b修改该数组的值,显然a数组也发生了改变。

编译结果:
1 2 3
2 4 6

  //栈空间中包含了两个数组引用类型,堆空间中包含了值,引用类型全部指向了堆空间的值。

再看一个实例,有以下代码:

string s1 = null;
string s2 = "";

这两个语句在内存分配上有什么区别?
对于第一个语句,定义了一个引用类型变量s1,初始化为null,表示s1不指向任何一个对象,所有仅在栈空间中分配s1,不需要再堆空间中分配任何对象,即不占用堆空间。
对于第二个语句,定义了一个引用类型变量s2,初始化为空字符串,空字符串也是一个字符串对象,需要分配其空间,所以不仅在栈空间中分配s2,还要占用堆空间。

 

 

你可能感兴趣的:(c#)