C#入门到精通系列课程——第3章变量及运算符
◆本章内容
(1)变量是什么
(2)变量的声明及初始化
(3)常量
(4)运算符
(5)数据类型转换
(6)运算符优先级及结合性
(7)难点解答
◆本章简述
很多人认为学习C#之前必须要学习C++,其实并非如此,产生这种错误的认识是因为很多人在学习C#之前都学过C++。事实上,C#比C++更容易掌握。要掌握并熟练应用C#,就需要对C#语言基础进行充分的了解。本章将对C#语言的基础语法进行详细讲解,对于初学者来说,应该对本章内容进行仔细的阅读和深入的思考,这样才能达到事半功倍的效果。
知识框架
3.1 为什么要使用变量
变量关系到数据的存储,计算机是使用内存来存储计算时所使用的数据,那么内存是如何存储数据的呢?通过生活常识,我们知道数据是各式各样的,比如整数、小数、字符串等等,那么,在内存中存储这些数据时,就首先需要根据数据的需求(即类型)为它申请一块合适的空间,然后在这个空间中存储相应的值。实际上,内存就像一个宾馆,客人如果到一个宾馆住宿,首先需要开房间,然后再入住,而在开房间时,客人需要选择是开单间、开双人间、还是开总统套房等等,这其实就对应一个变量的数据类型选择问题。
在内存中为数据分配一定的空间之后,如果要使用定义的这个数据,由于内存中的数据是以二进制格式进行存储的,而这些二进制数据都对应相应的内存地址,因此,必须通过一种技术使用户能够方便地访问到二进制数据的内存地址,这种技术就是变量。
3.2 变量是什么
变量主要用来存储特定类型的数据,用户可以根据需要随时改变变量中所存储的数据值。变量具有名称、类型和值,其中,变量名是变量在程序源代码中的标识,类型用来确定变量所代表的内存的大小和类型,变量值是指它所代表的内存块中的数据。在程序执行过程中,变量的值可以发生变化。使用变量之前必须先声明变量,即指定变量的类型和名称。
这里以上面的客人入住宾馆为例,说明一个变量所需要的基本要素。首先,客人需要选择房间类型,也就是确定变量类型的过程;选择房间类型后,需要选择房间号,这是确定变量的名称;完成以上操作后,这个客人就可以顺利入住,这样,这个客人就相当于这个房间中存储的数据。示意图如图3.1所示。
3.3 变量的声明及初始化
好比一个新生儿必须有一个名字一样,使用变量时,也需要首先对变量进行命名,对变量命名的过程,其实就是声明一个变量。变量在使用之前,必须进行声明并初始化,本节将对变量的声明、简单数据类型、变量初始化,以及变量的作用域进行详细讲解。
3.3.1 声明变量
1.声明变量
声明变量就是指定变量的名称和类型,变量的声明非常重要,未经声明的变量本身并不合法,也无法在程序中使用。在C#中,声明一个变量是由一个类型和跟在后面的一个或多个变量名组成,多个变量之间用逗号分开,声明变量以分号结束,语法如下:
例如,声明一个整型变量mr,然后再同时声明3个字符串型变量mr_1.mr_2和mr_3,代码如下:
2.变量的命名规则
在声明变量时,要注意变量的命名规则。C#的变量名是一种标识符,应该符合标识符的命名规则。另外,需要注意的一点是:C#中的变量名是区分大小写的,比如num和Num是两个不同的变量,在程序中使用时是有区别的。下面列出变量的命名规则:
◆变量名只能由数字、字母和下划线组成。
◆变量名的第一个字符只能是字母或下划线,不能是数字。
◆不能使用C#中的关键字作为变量名。
◆一旦在一个语句块中定义了一个变量名,那么在变量的作用域内都不能再定义同名的变量。例如,下面的变量名是正确的:
下面的变量名是不正确的:
说明:在C#语言中允许使用汉字或其他语言文字作为变量名,如“int年龄=21”,在程序运行时并不出现什么错误,但建议读者尽量不要使用这些语言文字作为变量名。
3.3.2 简单数据类型
前面提到,声明变量时,首先需要确定变量的类型,那么,开发人员可以使用哪些类型呢?实际上,可以使用的变量类型是无限多的,因为开发人员可以通过自定义类型存储各种数据,但这里要讲解的简单数据类型是C#中预定义的一些类型。
C#中的数据类型根据其定义可以分为两种:一种是值类型,另一种是引用类型,从概念上看,值类型是直接存储值,而引用类型存储的是对值的引用。C#中的数据类型结构如图3.2所示。
从图3.2可以看出,值类型主要包括简单类型和复合类型两种,其中简单类型是程序中使用的最基本类型,主要包括整数类型、浮点类型、布尔类型和字符类型等4种,这4种简单类型都是.NET中预定义的;而复合类型主要包括枚举类型和结构类型,这两种复合类型既可以是.NET中预定义的,也可以是用户自定义的。本节主要对简单类型进行详细讲解,简单类型在实际中的应用如图3.3所示。
1.整数类型
整数类型用来存储整数数值,即没有小数部分的数值。可以是正数,也可以是负数。整型数据在C#程序中有3种表示形式,分别为十进制、八进制和十六进制。
◆十进制:十进制的表现形式就是我们在日常生活中使用的数据,如120、0、-127。
注意:不能以0作为十进制数的开头(0除外)。
◆八进制:以0开头的数,如0123(转换成十进制数为83)、-0123(转换成十进制数为-83)。
注意:八进制必须以0开头。
◆十六进制:以0x或0X开头的数,如0x25(转换成十进制数为37)、0Xb01e(转换成十进制数为45086)。
注意:十六进制必须以0X或0x开头。
C#中内置的整数类型如表3.1所示。
说明:表3.1中出现了“有符号整数”和“无符号整数”,其中,“无符号整数”是在“有符号整数”类型的前面加了一个u,这里的u是unsigned的缩写。它们的主要区别是:“有符号整数”既可以存储正数,也可以存储负数;“无符号整数”只能存放不带符号的整数,因此,它只能存放正数。例如,下面的代码:
例如,定义一个int类型的变量i和一个byte类型的变量j,并分别赋值为2017和255,代码如下:
此时,如果将byte类型的变量j赋值为256,即将代码修改如下:
此时在Visual Studio开发环境中编译程序,会出现如图3.4所示的错误提示。
分析图3.4中出现的错误提示,主要是由于byte类型的变量是8位无符号整数,它的范围在0~255之间,而256这个值已经超出了byte类型的范围,所以编译程序会出现错误提示。
说明:整数类型变量的默认值为0。
2.浮点类型
浮点类型变量主要用于处理含有小数的数据,浮点类型主要包含float和double两种类型。表3.2列出了这两种浮点类型的描述信息。
如果不做任何设置,包含小数点的数值默认为是double类型,例如9.27,没有特别指定的情况下,这个数值是double类型。如果要将数值以float类型来处理,就需要通过使用f或F将其强制指定为float类型。
例如,下面的代码就是将数值强制指定为float类型。
如果要将数值强制指定为double类型,则应该使用d或D进行设置,但加不加“d”或“D”没有硬性规定,可以加也可以不加。
例如,下面的代码就是将数值强制指定为double类型。
注意:
(1)需要使用float类型变量时,必须在数值的后面跟随f或F,否则编译器会直接将其作为double类型处理另外,也可以在double类型的值前面加上(float),对其进行强制转换。
(2)浮点类型变量的默认值是0,而不是0.0。
3.decimal类型
decimal类型表示128位数据类型,它是一种精度更高的浮点类型,其精度可以达到28位,取范围为土1.0X1028~士7.9X1028。
多学两招:由于decimal类型的高精度特性,它更合适于财务和货币计算。
如果希望一个小数被当成decimal类型,需要使用后缀m或M,例如:
如果小数没有后缀m或M,数值将被视为double类型,从而导致编译器错误,例如,在开发环境中运行下面代码:
将会出现如图3.5所示的错误提示。
从图3.5可以看出,3.14这个数如果没有后缀,直接被视为double类型,所以赋值给decimal类型的变量时,就会出现错误提示,应该将3.14改为3.14m或3.14M。
实例01:根据身高和体重计算BMI指数
创建一个控制台应用程序,声明double型变量height来记录身高,单位为米,声明int型变量weight记录体重,单位为千克,根据“BMI=体重/(身高*身高)”的公式计算BMI指数(身体质量指数),代码如下:
代码注解:
第10、14、18和22行代码使用了f...else if条件判断语句,该语句主要用来判断是否满足某种条件,该语句将在后面章节进行详细讲解,这里只需要了解即可。
程序运行效果如图3.6所示。
拓展训练:
一、在用户注册模块中,使用整型变量记录用户的年龄。
二、C#开发的财务系统中,需要创建一个存储流动资金金额的临时变量,则应使用下列( )语句?
A) decimal theMoney;
B) int theMoney;
C) string theMoney;
D) Dim theMoney as double;
4.bool 类型
bool类型(又称布尔类型)主要用来表示true或者false 值,C#中定义布尔类型时,需要使用bool关键字。例如,下 面代码定义一个布尔类型的变量:
说明:布尔类型通常被用在流程控制语句中作为判断条件。
这里需要注意的是,布尔类型变量的值只能是true或者false,不能将其他的值指定给布尔类型变量,例如,将一个整数10赋值给布尔类型变量,代码如下:
在Visual Studio开发环境中运行这句代码,会出现如图3.7所示的错误提示。
说明:布尔类型变量的默认值为false。
5.字符类型
字符类型在C#中使用Char类来表示,该类主要用来存储单个字符,它占用16位(两个字节)的内存空间。在定义字符型变量时,要以单引号('')表示,如'a'表示一个字符,而\"a\"则表示一个字符串,因为虽然其只有一个字符,但由于使用了双引号,所以它仍然表示字符串,而不是字符。字符类型变量的声明非常简单,代码如下:
注意:Char类只能定义一个Unicode字符。Unicode字符是目前计算机中通用的字符编码,它为针对不同语言中的每个字符设定了统一的二进制编码,用于满足跨语言、跨平台的文本转换和处理的要求,这里了解Unicode即可。
◆Char类的使用
Char类为开发人员提供了许多的方法,可以通过这些方法灵活地对字符进行各种操作。Char类的常用方法及说明如表3.3所示。
从表3.3可以看到,C#中的Char类提供了很多操作字符的方法,其中以Is和To开始的方法比较常用。以Is开始的方法大多是判断Unicode字符是否为某个类别,比如是否大小写、是否是数字等;而以To开始的方法主要是对字符进行转换大小写及转换字符串的操作。
实例02:字符类Char的常用方法应用
创建一个控制台应用程序,演示如何使用Char类提供的常见方法,代码如下:
代码注解:
(1)第3行到第8行代码,声明了5个不同类型的字符变量,下面的操作都是围绕这5个字符变量进行的。
(2)第25行代码主要是为了使控制台界面能够停留在桌面上。
程序的运行结果如图3.8所示。
拓展训练:
一、打印保险单详细列表时,使用Char类型记录用户的性别是M(男)还是W(女),效果如图3.9所示。
二、尝试在Visual Studio 2017开发工具中比较'g'和103是否相等。
◆转义字符
前面讲到了字符只能存储单个字符,但是,如果在Visual Studio开发环境中编写如下代码:
会出现如图3.10所示的错误提示。
从代码表面上看,反斜线“\”是一个字符,正常应该是可以定义为字符的,但为什么会出现错误呢?这里就引出了转义字符的概念。
转义字符是一种特殊的字符变量,以反斜线“\”开头,后跟一个或多个字符,也就是说,在C#中,反斜线“\”是一个转义字符,不能单独作为字符使用。因此,如果要在C#中使用反斜线,可以使用下面代码表示:
转义字符就相当于一个电源变换器,电源变换器就是通过一定的手段获得所需的电源形式,例如交流变成直流、高电压变为低电压、低频变为高频等。转义字符也是,它是将字符转换成另一种操作形式,或是将无法一起使用的字符进行组合。
注意:转义符(单个反斜线)“\”只针对后面紧跟着的单个字符进行操作。
C#中的常用转义字符如表3.4所示。
实例03:输出Windows系统目录
创建一个控制台应用程序,通过使用转义字符在控制台窗口中输出Windows的系统目录,代码如下:
程序的运行结果如图3.11所示。
拓展训练:
一、在控制台窗口中输出Visual Studio2017开发环境的安装目录。
二、使用转义字符输出带特殊效果的内容,效果如图3.12所示。
多学两招:实例03中输出系统目录时,遇到反斜线时,使用“\\”表示,但是,如果遇到下面的情况:
从上面的代码看到,在有多级目录时,如果都使用“\\”,会显得非常麻烦,这时可以用一个@符号来进行多级转义,代码修改如下:
3.3.3 变量的初始化
变量的初始化实际上就是给变量赋值,以便在程序中使用。首先,在Visual Studio 2017开发环境中运行下面一段代码:
运行上面代码时,会出现如图3.13所示的错误提示。
从图3.13可以看出,如果直接定义一个变量进行使用,会提示使用了未赋值的变量,这说明:在程序中使用变量时,一定要对其进行赋值,也就是初始化,然后才可以使用。那么如何对变量进行初始化呢?
初始化变量有3种方法,分别是单独初始化变量、声明时初始化变量、同时初始化多个变量等,下面分别进行讲解。
1.单独初始化变量
在C#中,使用赋值运算符“=”(等号)对变量进行初始化,即将等号右边的值赋给左边的变量。
例如,声明一个变量sum,并初始化其默认值为2017,代码如下:
说明:在对变量进行初始化时,等号右边也可以是一个已经被赋值的变量。例如,首先声明两个变量sum和num,然后将变量sum赋值为2017,最后将变量sum赋值给变量num,代码如下:
2.声明时初始化变量
声明变量时可以对变量进行初始化,即在每个变量名后面加上给变量赋初始值的指令。
例如,声明一个整型变量mr,并且赋值为927。然后再同时声明3个字符串型变量并初始化,代码如下:
3.同时初始化多个变量
在对多个同类型的变量赋同一个值时,为了节省代码的行数,可以同时对多个变量进行初始化。
例如,声明5个int类型的变量a、b、c、d、e,然后将这5个变量都初始化为0,代码如下:
上面讲解了初始化变量的3种方法,现在对本节开始出现错误的代码段进行修改,使其能够正常运行,修改后的代码如下:
再次运行程序,即可正常运行。
3.3.4 变量的作用域
由于变量被定义后,只是暂时存储在内存中,等程序执行到某一个点后,该变量会被释放掉,也就是说变量有它的生命周期。因此,变量的作用域是指程序代码能够访问该变量的区域,如果超出该区域,则在编译时会出现错误。在程序中,一般会根据变量的“有效范围”将变量分为“成员变量”和“局部变量”。
1.成员变量
在类体中定义的变量被称为成员变量,成员变量在整个类中都有效。类的成员变量又可以分为两种,即静态变量和实例变量。
例如,在Test类中声明实例变量和静态变量,代码如下:
其中,x为实例变量,y为静态变量(也称类变量)。如果在成员变量的类型前面加上关键字static,这样的成员变量称为静态变量。静态变量的有效范围可以跨类,甚至可达到整个应用程序之内。对于静态变量,除了能在定义它的类内存取,还能直接以“类名.静态变量”的方式在其他类内使用。
2.局部变量
在类的方法体中定义的变量(定义方法的“{”与“}”之间的区域)称为局部变量,局部变量只在当前代码块中有效。
在类的方法中声明的变量,包括方法的参数,都属于局部变量。局部变量只有在当前定义的方法内有效,不能用于类的其他方法中。局部变量的生命周期取决于方法,当方法被调用时,C#编译器为方法中的局部变量分配内存空间,当该方法的调用结束后,则会释放方法中局部变量占用的内存空间,局部变量也将会销毁。
变量的有效范围如图3.14所示。
实例04:使用变量记录用户登录名
创建一个控制台应用程序,使用一个局部变量记录用户的登录名,代码如下:
程序运行结果如图3.15所示
拓展训练:
一、制作用户登录模块时,使用局部变量记录登录用户和登录时间(提示:记录登录时间时,需要用到DataTime结构,该结构用来获取日期相关的信息)。
二、使用一个int类型的变量记录每年京东的年中促销活动节日名称(提示:618),运行效果如图3.16所示。
3.4 常量
通过对前面知识的学习,我们知道了变量是随时可以改变值的量,那么,在遇到不允许改变值的情况时,该怎么办呢?这就是本节将要讲解的常量。
3.4.1 常量是什么
常量就是程序运行过程中,值不能改变的量,比如现实生活中的居民身份证号码、数学运算中的π值等,这些都是不会发生改变的,它们都可以定义为常量。常量可以区分为不同的类型,比如98、368是整型常量,3.14、0.25是实数常量,即浮点类型的常量,m、r是字符常量。
3.4.2 常量的分类
常量主要有两种,分别是const常量和readonly常量,下面分别对这两种常量进行讲解。
1.const常量
在C#中提到常量,通常指的是const常量。const常量也叫静态常量,它在编译时就已经确定了值。const常量的值必须在声明时就进行初始化,而且之后不可以再进行更改。
例如,声明一个正确的const常量,同时再声明一个错误的const常量,以便读者对比参考,代码如下:
2. readonly常量
readonly常量是一种特殊的常量,也称为动态常量,从字面理解上看,readonly常量可以进行动态赋值,但需要注意的是,这里的动态赋值是有条件的,它只能在构造函数中进行赋值,例如,下面的代码:
如果要在构造函数以外的位置修改readonly常量的值,比如,在Main方法中进行修改,代码如下:
这时再运行程序,将会出现如图3.17所示的错误提示。
3. const常量与readonly常量的区别
const常量与readonly常量的主要区别如下:
◆const常量必须在声明时初始化,而readonly常量则可以延迟到构造函数中初始化。
◆ const常量在编译时就被解析,即将常量的值替换成了初始化的值,而readonly常量的值需要在运行时确定。
◆ const常量可以在类中或者方法体中定义,而readonly常量只能在类中定义。
3.5 运算符
运算符是具有运算功能的符号,根据使用操作数的个数,可以将运算符分为单目运算符、双目运算符和三目运算符,其中,单目运算符是作用在一个操作数上的运算符,如正号(+)等;双目运算符是作用在两个操作数上的运算符,如加法(+)、乘法(*)等;三目运算符是作用在3个操作数上的运算符,C#中唯一的三目运算符就是条件运算符(?:)。本节将详细讲解C#中的运算符。
3.5.1 算术运算符
C#中的算术运算符是双目运算符,主要包括+、-、*、/和%5种,它们分别用于进行加、减、乘、除和模(求余数)运算。C#中算术运算符的功能及使用方式如表3.5所示。
实例05计算学生成绩的分差及平均分
某学员3门课程的成绩如下所示:
编程实现两个功能:计算C#课和SQL课的分数之差;计算3门课的平均分数。代码如下:
程序运行结果如图3.18所示。
拓展训练:
一、制作一个简易的加法计算器程序,具体实现时,提示用户输入3个整型或浮点型数值,并计算这3个数值的和。
二、使用克莱姆法则求解下面的二元一次方程组。
21.8x+2y=28
7x+ 8y= 62
提示:克莱姆法则求解二元一次方程组的公式如图3.19所示。
注意:使用除法(/)运算符和求余运算符时,除数不能为0,否则将会出现异常,如图3.20所示。
3.5.2 自增自减运算符
使用算术运算符时,如果需要对数值型变量的值进行加1或者减1操作,可以使用下面的代码:
针对以上功能,C#中还提供了另外的实现方式:自增和自减运算符,分别用++和--表示,下面分别对它们进行讲解。
自增和自减运算符是单目运算符,在使用时有两种形式,分别是++expr、expr++,或者--expr、expr--,其中,++expr、--expr是前置形式,它表示expr自身先加1或者减1,其运算结果是自身修改后的值,再参与其他运算;而expr++、expr--是后置形式,它也表示自身加1或者减1,但其运算结果是自身未修改的值,也就是说,expr++、expr--是先参加完其他运算,然后再进行自身加1或者减1操作,自增、自减运算符放在不同位置时的运算示意图如图3.21所示。
例如,下面代码演示自增运算符放在变量的不同位置时的运算结果:
注意:自增、自减运算符只能作用于变量,因此,下面的形式是不合法的:
多学两招:如果程序中不需要使用操作数原来的值,只是需要其自身进行加(减)1,那么建议使用前置自加(减),因为后置自加(减)必须先保存原来的值,而前置自加(减)不需要保存原来的值。
3.5.3 赋值运算符
赋值运算符主要用来为变量等赋值,它是双目运算符。C#中的赋值运算符分为简单赋值运算符和复合赋值运算符,下面分别进行讲解。
1.简单赋值运算符
简单赋值运算符以符号“=”表示,其功能是将右操作数所含的值赋给左操作数。例如:
2.复合赋值运算符
在程序中对某个对象进行某种操作后,如果要再将操作结果重新赋值给该对象,则可以通过下面的代码实现:
上面的代码看起来很烦琐,在C#中,上面的代码等价于:
上面代码中的+=就是一种复合赋值运算符,复合赋值运算符又称为带运算的赋值运算符,它其实是将赋值运算符与其他运算符合并成一个运算符来使用,从而同时实现两种运算符的效果。
C#提供了很多复合赋值运算符,其说明及运算规则如表3.6所示。
3.复合赋值运算符的优势及劣势
使用复合赋值运算符时,虽然“a+= 1”与“a=a+ 1”两者的计算结果是相同的,但是在不同的场景下,两种使用方法都有各自的优势和劣势,下面分别介绍。
(1)低精度类型自增
在C#中,整数的默认类型是int型,所以下面的代码会报错:
上面的代码中,在没有进行强制类型转换的条件下,a+1的结果是一个int值,无法直接赋给一个byte变量。但是如果使用“+=”实现递增计算,就不会出现这个问题,代码如下:
(2)不规则的多值运算
复合赋值运算符虽然简洁、强大,但是有些时候是不推荐使用的,例如,下面的代码:
如果将,上面这行代码改成复合赋值运算符实现,就会显得非常烦琐,代码如下:
说明:在C#中可以把赋值运算符连在一起使用。如:
在这个语句中,变量x、y. z都得到同样的值5,但在程序开发中不建议使用这种赋值语法。
3.5.4 关系运算符
关系运算符是双目运算符,它用于在程序中的变量之间以及其他类型的对象之间的比较,它返回一个代表运算结果的布尔值。当运算符对应的关系成立时,运算结果为true,否则为false。 关系运算符通常用在条件语句中来作为判断的依据。C#中的关系运算符共有6个,其使用及说明如表3.7所示。
说明:不等于运算符(!=)是与等于运算符相反的运算符,它与!(a==b) 是等效的。
实例06:使用关系运算符比较大小关系
创建一个控制台应用程序,声明3个int 类型的变量,并分别对它们进行初始化,然后分别使用C#中的各种关系运算符对它们的大小关系进行比较,代码如下:
代码注解:
(1)第6行代码使用“Console.WriteLine);" 输出了一个空行,起到换行的作用。
(2)第7行到第12行代码主要演示6种关系运算符的使用方法。
程序运行结果如图3.22所示。
拓展训练:
一、有两个链球,它们分别重5kg和8kg,请使用程序输出其中更重的一个链球。
二、国家推出二胎政策,A家庭陆续生了2个孩子,B家庭陆续生了4个孩子,哪个家庭属于超生家庭?
3.5.5 逻辑运算符
假定某面包店,在每周二的下午7点至8点和每周六的下午5点至6点,对生日蛋糕商品进行折扣让利活动,那么想参加折扣活动的顾客,就要在时间上满足这样的条件(周二并且7:00 PM~8:00 PM) 或者(周六并且5:00 PM~6:00 PM),这里就用到了逻辑关系,在C#中也提供了这样的逻辑运算符来进行逻辑运算。
逻辑运算符是对真和假这两种布尔值进行运算,运算后的结果仍是一个布尔值。在C#中,逻辑运算符主要包括& (&&) (逻辑与)、| (||) (逻辑或)、! (逻辑非)。在逻辑运算符中,除了“!”是单目运算符之外,其他都是双目运算符。表3.8列出了逻辑运算符的用法和说明。
使用逻辑运算符进行逻辑运算时,其运算结果如表3.9所示。
多学两招:逻辑运算符“&&”与“&”都表示“逻辑与”,那么它们之间的区别在哪里呢?从表3.9可以看出,当两个表达式都为true时,逻辑与的结果才会是true。使用“&”会判断两个表达式; 而“&&”则是针对bool类型的数据进行判断,当第一个表达式为false时,则不去判断第二个表达式,直接输出结果从而节省计算机判断的次数。通常将这种在逻辑表达式中从左端的表达式可推断出整个表达式的值称为“短路”,而那些始终执行逻辑运算符两边的表达式称为“非短路”。“&&”属于“短路”运算符,而“&”则属于“非短路”运算符。“||”与“|”的区别跟“&&”与“&”的区别类似。
实例07参加面包店的打折活动
创建一个控制台应用程序,使用代码实现前面描述的面包店打折活动的场景,代码如下:
代码注解:
(1)第9行和第13行代码使用了if...else条件判断语句,主要用来判断是否满足某种条件,该语句将在第4章进行详细讲解,这里只需要了解即可。
(2)第9行代码中对条件进行判断时,使用了逻辑运算符&&、||和关系运算符==、>=、<=。
程序运行结果如图3.23和图3.24所示。
拓展训练:
一、在某网站首页中,可以使用账户名、手机号或者电子邮箱进行登录。请判断某用户是否可以登录。(已知服务器中有如下记录,账户名:123,手机号: 123****8910, 电子邮箱: 123@123.com )
二、有两名男性应聘者:一位25岁,一位32岁。该公司招聘信息中有一个要求,即男性应聘者的年龄在23~30岁之间,判断这两名应聘者是否满足这个要求。
3.5.6 位运算符
位运算符的操作数类型是整型,可以是有符号的也可以是无符号的。C#中的位运算符有位与、位或、位异或和取反运算符,其中位与、位或、位异或运算符为双目运算符,取反运算符为单目运算符。位运算是完全针对位方面的操作,因此,它在实际使用时,需要先将要执行运算的数据转换为二进制,然后才能进行运算。
说明:整型数据在内存中以二进制的形式表示, 如整型变量7的32位二进制表示是00000000 00000000 00000000 00000111,其中,左边最高位是符号位,最高位是0则表示正数,若为1则表示负数。负数采用补码表示,如-8的32位二进制表示为11111111 11111111 11111111 11111000
1.“位与”运算
“位与”运算的运算符为“&”,“位与”运算的运算法则是:如果两个整型数据a和b对应位都是1,则结果位才是1,否则为0。如果两个操作数的精度不同,则结果的精度与精度高的操作数相同,如图3.25所示。
2.“位或”运算
“按位或”运算的运算符为“|”,“位或”运算的运算法则是:如果两个操作数对应位都是0,则结果位才是0,否则为1。如果两个操作数的精度不同,则结果的精度与精度高的操作数相同,如图3.26所示。
3. “位异或” 运算
“位异或”运算的运算符是“∧”,“位异或”运算的运算法则是:当两个操作数的二进制表示相同(同时为0或同时为1)时,结果为0,否则为1。若两个操作数的精度不同,则结果数的精度与精度高的操作数相同,如图3.27所示。
4.“取反”运算
“取反”运算也称“按位非”运算,运算符为“~”。“取反”运算就是将操作数对应二进制中的1修改为0,0修改为1,如图3.28所示。
说明:图3.28 中,123取反后得到的结果中,由于前面符号位为1,因此最高位以负数计算,即-27+22,所以结果为-124。
在C#中使用Console.WriteLine输出图3.25~图3.28的运算结果,主要代码如下:
运算结果如图3.29所示。
3.5.7 移位运算符
C#中的移位运算符有两个,分别是左移位<<和右移位>>,这两个运算符都是双目运算符,它们主要用来对整数类型数据进行移位操作。移位运算符的右操作数不可以是负数,并且要小于左操作数的位数。下面分别对左移位<<和右移位>>进行讲解。
1.左移位运算符<<
左移位运算符<<是将-一个二进制操作数向左移动指定的位数,左边(高位端)溢出的位被丢弃, 右边(低位端)的空位用0补充。左移位运算相当于乘以2的n次幂。
例如,int类型数据48对应的二进制数为00110000,将其左移1位,根据左移位运算符的运算规则可以得出(00110000<<1)=01100000所以转换为十进制数就是96 (48*2); 将其左移2位,根据左移位运算符的运算规则可以得出(01100000<<2)=11000000所以转换为十进制数就是192 (48*22), 其执行过程如图3.30所示。
2.右移位运算符>>
右移位运算符>>是将一个二进制操作数向右移动指定的位数,右边( 低位端)溢出的位被丢弃,而在填充左边(高位端)的空位时,如果最高位是0 (表示正数),左侧空位填入0;如果最高位是1(表示负数),左侧空位填入1。右移位运算相当于除以2的n次幂。
正数48右移1位的运算过程如图3.31所示。
负数-80右移2位的运算过程如图3.32所示。
多学两招:由于移位运算的速度很快,在程序中遇到表达式乘以或除以2的n次幂的情况时,一般采用移位运算来代替。
3.5.8条件运算符
条件运算符用“?:” 表示,它是C#中唯一的三目运算符,该运算符需要3个操作数,形式如下:
其中,表达式1是一个布尔值,可以为真或假,如果表达式1为真,返回表达式2的运算结果,如果表达式1为假,则返回表达式3的运算结果。例如:
多学两招:条件运算符相当于一个if语句,因此,上面的第 2行代码可以修改如下:
关于if语句的详细讲解,请参见后面章节
另外,条件运算符的结合性是从右向左的,即:从右向左运算,例如:
等价于:
实例08:判断人的年龄所处阶段
创建一个控制台应用程序,使用条件运算符判断输入年龄所处的阶段,并输出相应的提示信息,代码如下;
代码注解:
(1)第4行代码中,Int32.Parse方法用来将用户的输入转换为int类型,存储到int类型变量中。
(2)第6行代码是定义了一个string类型的变量,记录条件表达式的返回结果
程序运行结果如图3.33所示。
拓展训练:
一、通过使用条件运算符判断输入的年份是不是闰年。
二、使用逻辑运算符判断用户输入的用户名和密码是否同时满足条件,如果是,输出“登录成功”,否则,输出“登录失败”。提示:默认的用户名和密码分别是mr和mrsoft,另外,该程序实现时需要用到关系运算符“==”和条件运算符“?:”。登录成功和失败的效果分别如图3.34和图3.35所示。
3.6 数据类型转换
类型转换是将一个值从一种数据类型更改为另一种数据类型的过程。例如,可以将string类型数据“457”转换为一个int类型,也可以将任意类型的数据转换为string类型。
数据类型转换有两种方式,即隐式转换与显式转换。如果从低精度数据类型向高精度数据类型转换,则永远不会溢出,并且总是成功的;而把高精度数据类型向低精度数据类型转换,则必然会有信息丢失,甚至有可能失败,这种转换规则就像如图3.36所示的两个场景,高精度相当于一个大水杯,低精度相当于一个小水杯,大水杯可以轻松装下小水杯中所有的水,但小水杯无法装下大水杯中所有的水,装不下的部分必然会溢出。
3.6.1 隐式类型转换
隐式类型转换就是不需要声明就能进行的转换,进行隐式类型转换时,编译器不需要进行检查就能自动进行转换。下列基本数据类型会涉及数据转换(不包括逻辑类型),这些类型按精度从“低”到“高”排列的顺序为byte < short < int < long < float < double,可对照图3.37,其中char类型比较特殊,它可以与部分int型数字兼容,且不会发生精度变化。
例如,将int类型的值隐式转换成long类型,代码如下:
3.6.2 显式类型转换
有很多场合不能隐式地进行类型转换,否则编译器会出现错误,例如,下面的类型在进行隐式转换时会出现错误:
◆int类型转换为short类型——会丢失数据
◆int类型转换为uint类型——会丢失数据
◆float类型转换为int类型——会丢失小数点后面的所有数据
◆double类型转换为int类型——会丢失小数点后面的所有数据
◆数值类型转换为char类型——会丢失数据"
◆decimal类型转换为其他数值类型——decimal类型的内部结构不同于整数和浮点数
如果遇到上面类型之间的转换,就需要用到C#中的显式类型转换。显式类型转换也称为强制类型转换,它需要在代码中明确地声明要转换的类型。如果要把高精度的变量转换为低精度的变量,就需要使用显式类型转换。
显式类型转换的一般形式为:
其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。
例如,下面的代码用来把x转换为float类型:
通过显式类型转换,就可以解决高精度数据向低精度转换的问题,例如,将double类型的值4.5赋值给int类型变量时,可以使用下面的代码实现:
3.6.3 使用Convert类进行转换
在3.6.2节中讲解了可以使用“(类型说明符)表达式”进行显式类型转换,使用这种方式实现将long型数据转换成int型数据:
按照代码的本意,i的值应该是3000000000,但在运行这两行代码时,却发现i的值是-1294967296,这主要是由于int类型的最大值为2147483647,很明显,3000000000要比2147483647大,所以在使用上面代码进行显式类型转换时,出现了与预期不符的结果,但是程序并没有报告错误。如果在实际开发中遇到这种情况,可能会引起大的BUG,那么,在遇到这种错误时,有没有一种方式能够向开发人员报告错误呢?答案是肯定的。C#中提供了Convert类,该类也可以进行显式类型转换,它的主要作用是将一个基本数据类型转换为另一个基本数据类型。Convert类的常用方法及说明如表3.10所示。
例如,定义一个double类型的变量x,并赋值为198.99,使用Convert类将其显式转换为int类型,代码如下:
下面使用Convert类的ToInt32对本节开始的两行代码进行修改,修改后的代码如下:
再次运行这两行代码,则会出现如图3.38所示的错误提示。
这样,开发人员即可根据图3.38中的错误提示对程序代码进行修改,避免程序出现逻辑错误。
3.7 运算符优先级与结合性
C#中的表达式是使用运算符连接起来的符合C#规范的式子,运算符的优先级决定了表达式中运算执行的先后顺序。运算符优先级其实相当于进销存的业务流程,如进货、入库、销售、出库,只能按这个步骤进行操作。运算符的优先级也是这样的,它是按照一定的先后顺序进行计算的,C#中的运算符优先级由高到低的顺序依次是:
(1)自增、自减运算符。
(2)算术运算符。
(3)移位运算符。
(4)关系运算符。
(5)逻辑运算符。
(6)条件运算符。
(7)赋值运算符。
如果两个运算符具有相同的优先级,则会根据其结合性确定是从左至右运算,还是从右至左运算。表3.11列出了运算符从高到低的优先级顺序及结合性。
说明:表3.11中的“←”表示从右至左,“→”表示从左至右。从表3.11中可以看出,C#中的运算符中,只有单目、条件和赋值运算符的结合性为从右至左,其他运算符的结合性都是从左至右,所以,下面的代码是等效的:
3.8 难点解答
3.8.1 使用赋值运算符时的注意事项
使用赋值运算符时,其左操作数不能是常量,但所有表达式都可以作为赋值运算符的右操作数,例如,下面的3种赋值形式是错误的:
另外,在使用赋值运算符时,右操作数的类型必须可以隐式转换为左操作数的类型,否则,将会出现错误提示,例如,下面的代码:
运行上面的代码,将会出现如图3.39所示的错误提示。
3.8.2 条件运算符不能单独作为语句
在C#中使用条件运算符对两个整型变量a和b进行运算,如果a>b,则得到a的值,否则,得到b的值,代码如下:
运行程序,出现如图3.40所示的错误提示。
分析错误原因,“?:”是C#中的三目运算符,而三目运算符是不能单独构成语句的,所以上面的代码才会出现错误,要修改该程序,只需要使用一个变量记录三目运算符运算之后的结果即可。改正后的代码如下:
3.9 小结
本章介绍的是C#的基础语法,其中需要重点掌握的是C#中的基本数据类型、变量与常量以及运算符三大知识点。另外,要对数据类型之间的转换有一定的了解。在使用变量时,需要注意的是变量的有效范围,否则在使用时会出现编译错误或浪费内存资源。此外,各种运算符也是本章的重点,正确使用这些运算符,才能得到预期的结果。
C#入门到精通系列课程——第3章变量及运算符的更多相关文章
- C#入门到精通系列课程——第2章编写C#程序
◆本章内容 (1)熟悉Visual Studio 2017开发环境 (2)编写第一个C#程序 (3)C#程序结构预览 (4)程序编写规范 (5)难点解答 ◆本章简述 要学习C#编程,必然要熟悉C#程序 ...
- C#入门到精通系列课程——第1章软件开发及C#简介
◆本章内容 (1)了解软件 (2)软件开发相关概念 (3)认识.NET Framework (4)C#语言 (5)Visual Studio 2017 ◆本章简述 软件在现代人们的日常生活中随处可见, ...
- Provisioning Services 7.6 入门到精通系列之一:PVS前期规划
1. Provisioning Services 产品概述 Provisioning Services (简称PVS)采用了一种与传统映像解决方案截然不同的方法,从根本上改变了硬件与依托硬件而运行的 ...
- Jenkins pipeline 入门到精通系列文章
Jenkins2 入门到精通系列文章. Jenkins2 下载与启动jenkins2 插件安装jenkins2 hellopipelinejenkins2 pipeline介绍jenkins2 jav ...
- 办公软件Office PPT 2010视频教程从入门到精通系列教程(22课时)
办公软件Office PPT 2010视频教程从入门到精通系列教程(22课时) 乔布斯的成功离不开美轮美奂的幻灯片效果,一个成功的商务人士.部门经理也少不了各种各样的PPT幻灯片.绿色资源网给你提供了 ...
- NHibernate从入门到精通系列
http://www.cnblogs.com/GoodHelper/archive/2011/02/17/1948744.html NHibernate从入门到精通系列(4)——持久对象的生命周期(上 ...
- Selenium 入门到精通系列:六
Selenium 入门到精通系列 PS:Checkbox方法 例子 HTML: <html> <head> <title>测试页面</title> &l ...
- Selenium 入门到精通系列:五
Selenium 入门到精通系列 PS:显式等待.隐式等待.强制等待方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019 ...
- Selenium 入门到精通系列:四
Selenium 入门到精通系列 PS:鼠标右键.鼠标悬停.键盘操作方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019 ...
随机推荐
- ElasticSearch 中的 Mapping
公号:码农充电站pro 主页:https://codeshellme.github.io 1,ES 中的 Mapping ES 中的 Mapping 相当于传统数据库中的表定义,它有以下作用: 定义索 ...
- 使用PageHelper进行分页查询
service层代码: public Result getDataSetList(String dataCode, String dataName, int pageIndex, int length ...
- 基于OpenSSL的PKI的PKI数字证书系统实现
本篇主要介绍了基于OpenSSL的PKI的PKI数字证书系统实现,利用OpenSSL建立一个CA中心的详细解决方案和建立的具体步骤. 1.PKI数字证书系统设计 PKI数字证书系统主要包括证书颁发机构 ...
- 微信小程序折线图表折线图加区域图
1.先来个效果图 这里我用的是插件@antv/f2-canvas(安装的方法如下) npm init 此处如果直接使用官方npm install 可能会出现没有node_modules错误 npm i ...
- C#正则实现匹配一块代码段
最近项目,生成聚合网关,但是生成的网关文件中,存在着不必要的代码段,比如一个类A,类B等 之前一直使用手动删除,这么做劳民伤财,浪费时间,考虑使用正则写一个工具实现自动删除. 正则写法: string ...
- 【转载】UML类图中箭头和线条的含义和用法
文章转载自 http://blog.csdn.net/hewei0241/article/details/7674450 https://blog.csdn.net/iamherego/article ...
- List调用toString()方法后,去除两头的中括号
import org.apache.commons.lang.StringUtils; public class Test { public static void main(String[] ...
- 如何下载Image Properties Context Menu(图片)插件
如何下载Image Properties Context Menu(图片)插件 可以通过:http://www.cnplugins.com/zhuanti/four-image-processing. ...
- EmEditor, 在正则使用()匹配后 使用$1 $2进行对括号内的值进行引用
$1表示第一个括号,$2表示第二个括号,以此类推
- [unknown source] 快乐树
一.题目 题目描述 有一棵 \(n\) 个节点的数,每个点有点权 \(a_i\),定义一条路径的权值为路径上所有点的异或和,求所有路径的权值和,有 \(q\) 次修改,每次改一个点的点权. 数据范围 ...