数据类型存储双雄:栈和堆
栈:
后进先出
栈存储几种类型的数据:某些类型变量的值(主要是值类型);程序当前的执行环境;传递给方法的参数;
数据只能从栈顶插入和删除;将数据放到栈顶叫做入栈;将数据从栈顶移除叫做出栈;
堆
能够任意的插入或删除
在堆里可以分配大块的内存用于存储某类型(主要是引用类型)的数据对象;
堆中的数据不能显示地删除,CLR中的自动GC(Garbage Collector,垃圾收集器)会自动清除无主(判断程序代码是否将不再访问某数据项的时候)的堆内存对象。
值类型和引用类型
值类型
只需要一段单独的内存,用于存储实际的数据
包含了所有的内置类型:数值,字符,bool,自定义的结构体struct,枚举neum
引用类型
需要两段内存,第一段存储实际的数据,它总是位于堆中;第二段是一个引用,指向数据在堆中的存放位置;TIP:对于引用类型,实际数据存放在堆里,而引用存放在栈里
显示转换和隐式转换
C#里,兼容的实例间可以进行相互转换
转换总是从一个值转换成一个新的值
隐式转换:隐式转换是自动发生的
显式转换:显式转换是手动操作的
长整型转换成整型的时候可能会导致数据丢失,所以要用显示转换
如果编译器断定转换不能成功的化两种转换都是会被禁止的
static void Main(string[] args)
{
int i = 3;
long a = i;//因为int是整型,long是长整型,已经包括了int的情况下直接隐式转换
short b = (short)i;//由于short比long的范围小,所以i前面需要指定short,显示转换
}
关键字和操作符
Console -类-类拥有方法,方法存放于类中-若要访问方法,则必须知道方法所处的类
// -代码注释
WriteLine()-方法 -向输出窗口编写一行数据
decimal-小数
Write()也可用书写,多行可连续
.(点)-访问运算符
;(分号)-完成命令输入
= -赋值,从左到右
创建变量的时候,必须初始化才能使用
隐式类型变量用var表示,只能在初始化时使用
var message = "Hello world!";
在 C# 中,无论是使用实际数据类型还是让编译器推断数据类型,编译器都将以静态方式键入变量。 换句话说,声明时类型是锁定的,因此永远无法保存不同数据类型的值。
var
关键字指示编译器根据变量的初始化值来推断变量的数据类型。- 阅读其他人的代码时,你可能会看到
var
关键字。但是,你应尽可能使用数据类型。
\\表示单\,否则单斜杠会代表转义
逐字字符串文本
逐字字符串文本将保留所有空格和字符,而无需转义反斜杠。 要创建逐字字符串,请在文本字符串的前面使用 @
指令。
Console.WriteLine(@" c:\source\repos
(this is where your code goes)");
用转义字符\u翻译编码生成日语
// To generate Japanese invoices:
// Nihon no seikyū-sho o seisei suru ni wa:
Console.Write("\n\n\u65e5\u672c\u306e\u8acb\u6c42\u66f8\u3092\u751f\u6210\u3059\u308b\u306b\u306f\uff1a\n\t");
Console.WriteLine(@"c:\invoices\app.exe -j");
//使用 \u 加上四个字符的代码来表示字符串中的 Unicode 字符 (UTF-16)。
连接文本字符串和变量。
要将两个字符串连接在一起,请使用字符串连接运算符,即加号 +
。
string firstName = "Bob";
string message = "Hello " + firstName;
Console.WriteLine(message);
运行代码。
Hello Bob
串联多个变量和文本字符串。
可以在同一行代码中执行多个串联操作。
将上面中编写的代码修改成以下代码:
string firstName = "Bob";
string greeting = "Hello";
Console.WriteLine(greeting + " " + firstName + "!");
通过合并多个变量和文本字符串来创建更复杂的消息。
运行代码。
Hello Bob!
字符串内插
string firstName = "Bob";
string greeting = "Hello";
//string message = $"{firstName} {greeting} !"; 最好直接打印,减少中间变量
//Console.WriteLine(message);
Console.WriteLine($"{greeting} {firstName} !");
这就是一个综合运用的实例
string projectName = "ACME";
string russianMessage = "\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0440\u0443\u0441\u0441\u043a\u0438\u0439 \u0432\u044b\u0432\u043e\u0434";
Console.WriteLine($@"view english output:
(c:\exercise\{projectName}\date.txt)");
Console.WriteLine($@"{russianMessage}:
(c:\exercise\{ projectName}\{russianMessage}\date.txt)");
类的实例称为对象。 若要创建类的新实例,使用 new
运算符。
Random dice = new Random();
int roll = dice.Next(1, 7);
Console.WriteLine(roll);
- 若要调用 .NET 类库中类的方法,采用
ClassName.MethodName()
格式,其中.
符号是成员访问运算符,用于访问在类中定义的方法,而()
符号是方法调用运算符。 - 调用无状态方法时,无需先创建其类的新实例。
- 在调用有状态方法时,需要创建类的实例,并访问对象的方法。
- 使用
new
运算符创建类的新实例。 - 类的实例称为对象。
int firstValue = 500;
int secondValue = 600;
int largerValue;
largerValue = Math.Max(secondValue, firstValue);
Console.WriteLine(largerValue);
Math.Max()
方法支持 11 个重载版本,以接受不同的数据类型。 调用的 Math.Max()
方法的重载版本接受 int
作为两个输入参数,并将两个值中的较大值作为 int
返回。
运行代码,应看到以下输出:
600
调用 .NET 类库中不同种类的方法
双竖线分隔符 ||
是“逻辑或”运算符,主要表示“要使整个布尔表达式为 true,要么左侧表达式必须为 true,要么右侧表达式必须为 true”。 如果两个布尔表达式均为 false,则整个布尔表达式为 false。 我们使用两个“逻辑或”运算符,以便可将评估扩展到第三个布尔表达式。
if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3))
摇骰子游戏
包含了基本的if语句用法(“从没有摇到过豹子”)
Random dice = new Random();
int roll1 = dice.Next(1, 7);
int roll2 = dice.Next(1, 7);
int roll3 = dice.Next(1, 7);
int msn = roll1 + roll2 + roll3;
Console.WriteLine($"Dice roll:{roll1} + {roll2} + {roll3} = {msn}");
if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3))
{
if ((roll1 == roll2) && (roll2 == roll3))
{
Console.WriteLine("豹子,恭喜你获得三倍奖励");
Console.WriteLine("点数加3");
msn += 3;
}
}
else
{
Console.WriteLine("两个相同值,两倍奖励");
Console.WriteLine("点数加 2");
msn += 2;
}
Console.WriteLine(msn);
if (msn >= 14)
{
Console.WriteLine("恭喜");
Console.WriteLine("你将在今年暴富");
}
else if(msn >= 10)
{
Console.WriteLine("恭喜");
Console.WriteLine("你能在今年收获爱情");
}
else if(msn >= 6)
{
Console.WriteLine("很抱歉,你只能变得更帅");
}
else
{
Console.WriteLine("谢谢惠顾");
}
C#的逻辑运算符(一)
逻辑运算符用来连接多个 bool 类型表达式,实现多个条件的复合判断。C#中的逻辑运算符包括:逻辑非( ! )、逻辑与( && )、逻辑或( || )。
逻辑非用来对某一个 bool 类型表达式取反,即“真变假”或“假变真”。请看下面的代码:
Console.WriteLine(1 > 0);//条件表达式为true,输出True Console.WriteLine(!(1 > 0));//用逻辑非对条件表达式取反,输出False
逻辑与用来判断 2 个 bool 类型表达式是否同时为 true 。请看下面的代码:
int x = 5, y = 2;//同时声明2个int型变量并赋值 Console.WriteLine(x>3 && y>3);//判断x>3和y>3是否同时为true,由于y>3为false,所以整个表达式为false
只有当&&两边的表达式均为 true 时,整个表达式才为 true ;若任意一个表达式为 false ,整个表达式即为 false 。
逻辑或用来判断2个 bool 类型表达式中是否有一个为 true 。请看下面的代码:
int x = 5, y = 2;//同时声明2个int型变量并赋值 Console.WriteLine(x>3 || y>3);//判断x>3和y>3是否有一个为true,由于x>3为true,所以整个表达式为true
只要||两边的表达式有一个为 true ,整个表达式即为 true ;若两边的表达式均为 false ,整个表达式为 false 。
对比一下,就是说: && 运算符,两边同真才算真,一边为假就算假; || 运算符,一边为真即为真,两边同假才是假。
C#的运算符优先级
前面我们学习了那么多运算符,如果编程中同时使用了多个运算符,到底哪一个会先运算呢?这就是优先级的问题。C#运算符的优先级请参考下面的顺序:
①括号。学数学的时候我们就知道,要先计算括号里面的内容。C#语言也是一样,如果有多层括号,要从里向外计算。括号优先级最高。
②一元运算符。有些运算符两边有2个操作数,比如2+3、6%5等等,这些叫做二元运算符。只有一个操作数的叫做一元运算符,它们的优先级高于二元运算符。一元运算符包括:++(自加) 、 --(自减) 、 !(逻辑非)。
③*(乘)、/(除)、%(取余)。
④+(加)、-(减)。
⑤>(大于)、<(小于)、>=(大于等于)、<=(小于等于)。
⑥==(等于)、!=(不等于)。
⑦&&(逻辑与)。
⑧||(逻辑或)。
⑨赋值运算符。包括:=、+=、-=、*=、/=、%=。
另外,还需要注意一点:优先级相同的运算符从左向右计算(赋值运算符相反)