.NET Core C# 初级篇 1-1 基础类型介绍

2019-08-03  本文已影响0人  WarrenRyan

.NET Core CSharp初级篇 1-1

本节内容是对于C#基础类型的存储方式以及C#基础类型的理论介绍

基础数据类型介绍

例如以下这句话:“张三是一名程序员,今年15岁重50.3kg,他的代号是‘A’,他家的经纬度是(N30,E134)。”,这句话就是一个字符串,使用双引号括起来。而15则表示是一个 整数类型,50.3就是小数类型,不过我们在C# 中通常称为 浮点类型,最后一个经纬度,我们通常定位地点的时候都是成对出现,所以我们认为这二者是一个密不可分的结构,这种类型我们称为 结构体类型(struct)

以上我所说的数据类型都是一个所含有信息量一定的数值,我们称为值类型;而张三这个人,他所含有的数据大小是不固定的,比如我又了解到了张三是一个富二代,那么他就会增加一个属性是富二代,我们需要更多的空间去存储他,张三这个变量我们通常就称为引用类型,而张三这个名字,我们就称为引用,如果你对C或者C++熟悉的话,张三这个名字就是指向张三这个人(对象)的一个指针

CSharp 中两种数据存储方式

C# 中,数据在内存中的存储方式主要分为在堆中存储和栈中存储。我们之前提到的值类型就是存储在栈中,引用类型的数据是存储在堆中,而数据是在栈中。

值类型:存储在栈(Stack,一段连续的内存块)中,存储遵循先进后出,有严格的顺序读取访问速度快,可通过地址推算访问同一个栈的其余变量。

引用类型:引用(本质上和C++中的指针一致)存储在栈中,内含的数据存储在堆中(一大块内存地址,内部变量存储不一定连续存储)。

(此处需要补充堆栈图片)

事实上,值类型和引用类型有一个很明显的区别就是值类型应当都是有值的,而引用类型是可以为空值的。

常见的几种数据类型

C#中定义变量的方式及数据转换的方法

在C#中定义变量的方式和其他的主流语言没有太大的区别,以下是几种定义方式:

int number = 5;//定义一个32位整数类型
bool b = true;//定义
//注意看以下两条,string定义的字符串必须为双引号,而char使用单引号并且只允许输入一个字符
string str = "test";
char a = 'a';
//记得后缀
float f = 1.3f;
decimal d = 1.5m;

数据类型的转换分为隐式转换和显式转换,看下面几个例子:

string a = "15";
int b = int.Parse(a);//显式转换
b = (int)a;//强制转换
b = Convert.ToInt32(a);//显式转换,较常用
double d = 1.5;
b = d;//隐式转换

数组

数组指一个类型(任意)的集合,例如你定义一个变量为a=5,很轻松,假设你需要100个呢?因此我们使用数组来存储。
数组的定义以及使用如下:

///伪代码,T为类型,n为大小
T [] t = new T[n];
//定义一个整型数组
int [] a = new int [5];
//你也可以选择初始化的方式定义
int [] b = new int [] {1,2,3,4,5};
//或
int [] c = new int [5]{1,2,3,4,5};
//数组的访问,从0开始索引
Console.WriteLine(b[0]);

常见的运算符

^是异或,result=1110,就是说异是不同返回1,相同是0,或就是只要有1就返回1。
&是与, result=0001,也就是相同返回1,不同为0
|是或, result=1111,除了两个都为0,否则返回1
~称为按位取反,我们表示符号是用四个0表示,运算规则就是正数的反码,补码都是其本身的源码,
负数的反码是符号位不变,本身的0变1,1变0,补码就是反码+1,
最后进行补码取反时连同符号位一起变得到的反码就是结果
流程如下:0000 0111 --> 0000 1000 --> 0000 1001 --> 1111 0110 = -8
'>>'称为右移,右移一位流程如下 0000 1001 --> 0000 0100 = 4

<<称为左移,左移一位流程如下 0000 1001 --> 0000 10010 = 18

具体的操作我会在我在BiliBili上发布的 .Net Core 教程上进行详细的讲述。

*结构体(选看)

结构体是一种比较特殊的数据类型,它很像我们后面讲述到的类,但是他并不是一个类,他本质还是值类型,结构体的使用是很重要的,如果结构体使用得当,可以有效的提升程序的效率。

结构体你可以理解为将将若干个类型拼接在一起,但是存在一个很重要的内容——内存对齐。例如下面两个结构体:

struct S
{
    int a;
    long b;
    int c;
}
struct SS
{
    int a;
    int b;
    long c;
}

乍一看你会觉得这两个结构体完全一致,丝毫没有任何的差别。但事实上,在大多数编程语言里面,对于结构体这种大小并不是定值的值类型,都存在一个最小分配单元用于结构体内单个变量的大小分配。在内存中,他们两个的存储方式有很大的不同。
对于上面两个结构体,他们在内存中的单元分配是:

在C#中,如果你不指定最小分配单元,那么编译器将会把结构体中占用内存最大的作为最小分配单元。不过尤其需要注意一件事,就是引用类型在结构体中。鉴于我们现在尚未讲解面向对象的类,我们用string作为成员写一个结构体。如下面这个例子:

struct S
{
    char a;
    long b;
    string c;
}
//函数中创建
S s = new S();
s.a = 'a';
s.b = 15;
s.c = "I Love .NET Core And Microsoft"

很显然s.c的大小超过了结构体中其余两个,但是内存分配的时候就是以最大的c作为标准吗?

显然不是,我们要知道struct是在栈中分配内存,string的内容是在堆中的,所以在结构体中存储的string只是一个引用,并不会包含其他的东西,只占用4个字节。并且特别的,引用类型在内存中的位置位于大于四字节的字段前,小于四字节字段后。

上面内存分配应当是这样:
a(8) --> c(8) --> b(8)。

如果需要深入了解这一方面内容,建议去阅读《CLR Via C#》这本书,以及学习SOS调试相关内容。


练习题

理论分析题:

计算题:

编程题:

更多内容的讲解请看 Github

更多内容请关注我的BiliBili地址以及我的博客。

Github

BiliBili主页

WarrenRyan's Blog

博客园

上一篇下一篇

猜你喜欢

热点阅读