- ASP.NET从入门到精通(第2版)
- 龙马高新教育策划 国家863中部软件孵化器著
- 168字
- 2024-12-21 22:33:12
第3章 ASP.NET中的编程语言——C#语言基础
本章视频教学录像:1 小时38分钟
为了让您认识C#,本章将学习C#语言的基础知识,并在ASP.NET环境中练习运用C#编写简单程序。如果您已经对C#有了一定程度的了解,可以直接跳过本章,进入第4章学习。对于C#不熟悉的读者,一定要认真学习本章的内容,并且进行大量的编程练习,为后续章节的学习打下基础。
本章要点(已掌握的在方框中打钩)
□ ASP.NET与C#的关系
□ C# 的语法规则
□ 标识符和关键字
□ 数据类型
□ 常量和变量
□ 数组
□ 程序流程控制及常用语句
3.1 ASP.NET与C#的关系
本节视频教学录像:10分钟
我们常常看到一些ASP.NET书的书名中挂上C#的字样,到底ASP.NET与C#有什么关系?我们学习的是ASP.NET,那为什么又要学习C# ?C#是什么?
本节将为你揭晓答案。
3.1.1 什么是C#
C#,英文是“C sharp”,是微软于2002年推出的一种新型的面向对象的编程语言,基于强大的C++传统语言创建,是一种现代化的、直观的、面向对象的编程语言。它不仅可以让 C++和 Java 开发人员快速熟悉,而且提供了重要的改进,包括统一的类型系统、最大化开发人员控制的“不安全”代码,以及大多数开发人员容易理解的强大的新语言构造。它只存在于Windows中的.NET平台,主要特点如下。
⑴功能强大。几乎Windows下的任何应用程序,用C#都可以实现。
⑵简单易学。如果你之前没有任何编程基础,而又想学编程,那么建议你从C#学起。
如果你有一些编程基础,那么想转到C#上就会更容易。C#就像自动挡的汽车,如果你没有开过车,那么教练可能会建议你开自动挡的车,因为好开;如果你有一点基础,那么自动挡的车对你来说将是小菜一碟。
3.1.2 我的第1个C#应用程序
提示
学习C#可以分为两步。
第1步是语法学习,可以从编写控制台应用程序学起,也就是编写类似于DOS的应用程序,通过在命令行中输入命令或参数来操作。控制台程序常见于一些后台软件,主要的开发运行环境是控制台。
第2步是应用开发学习。主要是通过Visual C#等这样的软件进行界面的设计以及代码的编写,最后生成可以实现既定功能的Windows下的应用程序。主要的开发工具有ASP.NET、Visual. C#等。
本章中的大部分程序都是简单的控制台程序。
每个程序语言的教学都是从Hello World开始的,这个传统来源于一门新的语言诞生时向世界发出的第一声问候。本小节也从编写C#中的Hello World程序开始,通过该程序我们可以了解到如何与程序“交流”——输入和输出,如何运行C#程序以及C#语言的基本特点。
【范例3-1】C#中的Hello World程序。
⑴启动Visual Studio 2010,选择【新建】【项目】菜单命令,在弹出的【新建项目】对话框中选择【Visual C#】【控制台应用程序】,在【名称】文本框中输入项目名称“Hello World”。
⑵单击【确定】按钮,会直接打开“Program.cs”的代码窗口,在static void Main(string[] args)下面的大括号中输入以下代码。
Console.WriteLine("Hello World!");
【运行结果】
按【Ctrl+F5】组合键运行程序,即可在控制台中输出“Hello World!”。
提示
按【F5】运行此程序,这个控制台窗口会一闪而过。如果按【Ctrl+F5】组合键不调试直接运行,即可保持住此窗口。另外,在步骤⑵的代码下方再添加下面的一句代码,也能有效地解决这个问题。
Console.Read();
步骤⑵中的代码使用了WriteLine方法来输出“HelloWorld!”,该方法是运行时库中的“Console”类的输出方法之一,而这个类就包含在命名空间System中,所以说系统自动生成的代码也是不可或缺的,如果删除“using System;”这句代码,就会提示当前上下文中不存在名称“Console”。另一方面,自动生成可以节省很多操作步骤。
从这个程序中也可以看出C#的以下几个典型特点。符合这些特点的程序就可以断定是一个C#程序。
⑴可以使用系统内定的命名空间,如“using System;”,也可以自定义命名空间,如“namespace HelloWorld;”。
⑵方法的定义,如第10行代码定义的是Main方法,程序是从这里开始执行的。
⑶类的声明,如“class Program”,声明以后就可以直接调用。
3.1.3 ASP.NET中的C#
C#如此强大,那么它和ASP.NET是什么关系呢?
ASP.NET是一个框架,如同汽车,但要发挥汽车的威力,还是要使用强有力的发动机。而C#和VB.NET就是两种不同类型的发动机。C#版的ASP.NET就如同使用汽油发动机的汽车,VB.NET版的ASP.NET就如同使用柴油发动机的汽车。
下面就来制造一个“使用汽油发动机的汽车”,把上一例中的HelloWorld在ASP.NET网页中显示出来。
【范例1-1】就是使用C#语言创建的ASP.NET网站。
3.2 C#的语法规则
本节视频教学录像:6分钟
ASP.NET只是一种编程环境,而C#则是在这种环境中进行编程使用的语言。为了使用C#进行程序设计,必须了解C#的基本语法规则,并在今后的编程中严格遵循。
1. 语序
C#源代码最基本的执行语序是从上向下,每行一条,按顺序执行。所以在书写C#的源代码时,应遵循以下基本规则。
⑴每行语句以“;”结尾。
⑵空行和缩进被忽略。
⑶多条语句可以处于同一行,之间以分号分隔即可。
例如,下面就是一系列顺序执行的语句。
int a,b;
a=10;b=20;
Console.WriteLine("a+b={0}",a+b);
int c;
c =2*a*a+3*b-1;
Console.WriteLine("c={0}",c);
2. 空白
C#语言中的空白包括空格、换行符、制表位(Tab)等,多余的空白会被编译器忽略。例如,下面的两条语句在编译器看来是完全一样的。
int a=9;
int a= 9;
不过,有的时候空白不能够省略。例如:
inta=7; //编译器不能识别
3. 书写
由于C#语言区分大小写,所以getname()和GetName()是完全不同的两个方法。在C#开发环境中如果不加注意,就可能产生一个难以察觉的bug。
注 意
强烈建议在今后书写标识符时遵循以下规则。
一般变量名首字母小写,后面各单词首字母大写(例如someStudent);而常量、类名、方法名等,则采用单词首字母大写(例如SomeFunction())。
4. 注释
注释是一段被编译器忽略的代码,仅作为我们阅读程序时参考,帮助我们理解程序,不作为编译使用。我们可以在程序中的任何地方添加注释。C#支持两种形式的注释:单行注释和带分隔符的注释。
单行注释以字符“//”开头,符号后面就是注释的内容。这种注释只能占一行。
带分隔符的注释以字符“/*”开头,以字符“*/”结束,两符号中间是注释的内容。它不仅可以进行单行注释,而且可以进行多行注释。
提示
“/*”和“*/”必须成对使用,且它们之间不能出现嵌套,否则会出现错误。
因为C#语言是微软专门为.NET平台重新开发的语言,并且已经成为了标准版本,所以,我们在日常编程中必须严格遵循它的基本语法规则。
3.3 标识符和关键字
本节视频教学录像:4分钟
标识符和关键字是C#语言中两种重要的语法记号,掌握后可以给C#中的各种对象起名字。
3.3.1 标识符
在C#程序中会用到各种对象,如常量、变量、数组、方法、类型等。为了识别这些不同的对象,我们可以给每个对象起一个名字即标识符,标识符是我们在编程时可以自由定义的一组字符序列。
C#中标识符最多可以由511个字符组成,在定义时需要遵循以下命名规则。
⑴标识符必须由字母、数字和下划线“_”组成。例如:
abc, a32, student_191
⑵标识符的第1个字符必须是字母或下划线。例如:
A_edu, _b , _123
提示
一定不能以数字开头,写成123a或123_都是非法的。
⑶C#语言区分字母的大小写,只要两个标识符对应字母大小写不同,就是不同的标识符。
例如student和sTudent就是两个完全不同的标识符。
⑷标识符不能与关键字同名。如果一定要用C#的关键字作标识符,则应使用“@”字符作为前缀。
例如:
@if //合法的标识符
If //不是合法的标识符,因为它是关键字
@price //合法的标识符,但与price是同名标识符
提示
为了与其他语言交互,C#语言允许使用前缀“@”将关键字用做标识符。不过,字符“@”并不是标识符的实际组成部分,因此在其他语言中可能将此标识符视为不带前缀的正常标识符。带“@”前缀的标识符称做逐字标识符。在C#中,也可以将“@”前缀用于非关键字的标识符,但是从代码书写的样式考虑,强烈建议大家不要这样做。
由于C#语言使用Unicode字符集,其中“字母”和“数字”定义的范围比其他编程设计语言广泛,比如“字母”就几乎包括了当今世界上任意一种印刷体文字。而仅仅改变组成标识符的任一字符的字体也会产生一个新的标识符,因为它们是不同的Unicode字符,这样就容易造成混淆。因此我们在实际编程时,一般采用ASCII字符集(它是Unicode的子集)中的字符定义标识符。
例如,HelloWorld、_isTrue、check_is_9等都是合法的标识符。
而下面的标识符则都是非法的:
23example //非法起始字符
$100 //非法起始字符,虽然在C++等语言中是合法的
Hello! //非法含有字符“!”
Hello World //非法含有空格
Hello+WorId //非法含有运算符
3.3.2 关键字
关键字是对C#编译器具有特殊意义的预定义保留字,它们不能在程序中用做标识符,除非在前面加@前缀,例如:@case、@null、@else。
下表列出了C#语言的常用关键字。
3.4 数据类型
本节视频教学录像:8分钟
所谓数据类型,就是指数据的种类。在计算机世界中,数据不止是数字,其他的像文字、图片、声音、视频等都可以称为数据。
在应用程序的开发过程中,要使这些数据能被计算机识别并处理,需要将数据分为不同的类型,这样做的好处是存储和计算时比较方便。比如在对姓名和地址的处理中需要使用字符,在对货币和数量的处理中又需要使用数字或不同精度的小数,这些数据都是不同类型的数据。在C#中,数据类型必须被定义才能使用。
提示
之所以要定义数据类型,是因为计算机是没有思维的,只有告诉它,它才知道这是什么。比如你告诉计算机“int a;”,它才知道a是一个整数。如果不告诉它或告诉的信息错误,计算机就识别不出来它是个什么东西或者出错。
下图展示了各种数据类型之间的关系。
3.4.1 整数类型
整数类型的变量的值都为整数。C#中的整数与数学意义上的整数有很大的区别。数学上的整数可从负无穷大到正无穷大,而C#的整数类型有多种,并且值都是有范围的。
C#的整数类型归纳起来可分为短字节型(sbyte)、字节型(byte)、短整型(short)、无符号短整型(ushort)、整型(int)、无符号整型(uint)、长整型(long)和无符号长整型(ulong)等。这些类型是根据各类型的变量在内存中所占的位数划分的,比如“int a;”就表示定义了为整型(int)的变量a,它在内存中占用32位,可表示232个数值。
这些类型在计算机中所占的内存位数和取值范围如下表所示。
注意
变量所占的内存位数除了和被定义的类型有关之外,还和计算机本身的运算长度有关,比如在32位和64位的计算机中,同一个“int a”所表示的范围是不同的。
【范例3-2】定义整型变量并赋值。
⑴在Visual Studio 2010中,新建名为“short”的【Visual C#】【控制台应用程序】。
⑵在“static void Main(string[]args)”后面的两个大括号中间输入以下代码。
01 short x= 32766; //定义短整型变量 x并为其赋值为32766
02 x++; //在赋值基础上加上1,为32767
03 Console.WriteLine(x); //第1次在控制台中输出 x的值
04 x++; //再加上1,此时x的值应该是32 768,已超出短整型变量的取值范围
05 Console.WriteLine(x); //第2次在控制台中输出 x的值
【运行结果】
按【Ctrl+F5】组合键运行程序,即可在控制台中输出如图所示的结果。
【范例分析】
本范例中,先定义了短整型的变量x并赋值为32766,第1次加上1后为32767,在短整型的取值范围内,所以能够正确输出32767。而第2次再加上1后为32768,已经超出短整型变量的取值范围,系统会出现溢出的错误并输出错误的结果为-32768。
注意
每一种变量类型都有固定的取值范围,在取值范围内数据有效,如果超出取值范围,则会出现意想不到的错误。如同1小时一定为60分钟,如果将时间说成10点62分,就会闹出大笑话。在学习的时候建议了解这些规则,否则就可能触雷,比如【范例3-2】。
3.4.2 实数类型
实数是整数、小数的总称,所以实数类型的变量的值可以是整数,也可以是小数。在C#中,实数类型主要分为浮点类型和十进制类型两种,具体分类如图所示。
表示数值的精确度:单精度型<双精度型<十进制型。
运算效率:双精度型<单精度型<整数类型。
下表列出了单精度、双精度和十进制等类型的取值范围和运算精度。
注意
十进制类型在变量赋值时使用m下标以表明它是一个十进制类型,如果省略了m,编译器将把这个变量当做双精度类型来处理。例如:
decimal x=2.0m; //定义十进制型变量x并赋值为2.0
3.4.3 字符型
字符型为一个单Unicode字符,一个Unicode字符长16位,它可以用来表示世界上的多种语言。可以按以下方法给一个字符变量赋值。
char chSomechar= 'A'; //定义一个字符变量chSomedhar,并赋初值为 'A'。
除此之外,还可以通过十六进制转义符 (前缀\X)或Unicode表示法给变量赋值(前缀\u)。
char chSomeChar= '\x0065';
char chSomeChar= '\u0065';
char chSomeChar= (char)65;
注意
不存在把char转换成其他数据类型的隐式转换。这就意味着,在C#中把一个字符变量当做另外的整数数据类型看待是行不通的,这是我们必须养成的习惯之一。但是,可以运用显式转换,这些内容将在3.7节中介绍。
3.4.4 布尔类型
布尔数据类型有true和false两个布尔值。我们可以赋予true或false一个布尔变量,或者赋予一个表达式,求出的值等于两者之一。例如:
bool bTest= (80>90);
注意
在C#中,true值和false值不再为任何非零值,不要为了方便而把其他的整型转换成布尔型。
3.5 常量和变量
本节视频教学录像:7分钟
C#程序中的数据都是以常量或变量的形式呈现的。
3.5.1 常量
常量又叫常数,是在程序运行过程中值不发生变化的量。常见的圆周率就是常量。在程序中还有一些不会发生变化的值,如把尺转换为米的换算常量。例如:
m=c*3.33 ; // 3.33就是换算常量
另外还可以把这些数声明为带有一个常数值的变量,并赋予它们名称。例如:
const double cTom=3.33;
这样声明的变量在程序运行中是不能通过赋值等操作改变的,C#编译器会拒绝任何为这样的变量赋新值的操作。我们可以在计算机中直接使用这个名称。例如:
M=c*cTom; //这里是用编程语言解释正在参加计算的常量,而不是直接用数字参与运算
提示
常量只要在程序需要的地方直接写出即可,其类型由书写方法自动默认,一般不需要事先定义。一个常量可以依赖于另一个常量,但不能循环依赖。
常量也有数据类型。C#语言中常用的常量有整型常量、浮点型常量、字符常量、字符串常量和布尔常量等。
1. 整型常量
整型常量就是以文字形式出现的整数,它可以用十六进制或十进制表示。如果整型常量的开头是0X或0x,则代表是十六进制,否则都被认为是十进制。
注意
与C++语言不同,C#语言中没有整型常量的八进制表示形式。
例如:
32 //十进制
0222 //十进制,与C++语言不同
OX5cD //十六进制
一般来说,整型常量的默认数据类型是int型,但当其值超出了int型的取值范围时,它将相应地被视为一个uint型、long型或ulong型常量,具体类型由该常量的数值大小决定。可以在整型常量后面加后缀L(或1)将它显式说明为long或ulong型(具体类型由该常量的数值大小决定),也可以在整型常量后面加后缀U(或u)将它显式说明为uint或ulong型(具体类型也由该常量的数值大小决定)。如果在整型常量后面同时加上这两种后缀,它就是一个ulong型常量。例如:
567892 //long型
36u //uint型
36u //ulong型
2. 浮点型常量
浮点型常量只能用十进制表示,共有两种表示形式:一般表示形式和指数表示形式。
⑴一般表示形式。
又称小数表示形式。在这种表示形式中,浮点型常量由整数和小数两部分组成。其中,整数部分在实际使用时可省略。例如:
5.6,.9,6.0
必须注意:与C++语言不同,小数部分不能省略。例如:
10. //错误
⑵指数表示形式。
使用指数表示形式时,浮点型常量由尾数部分、字母E(或e)、指数部分等3部分组成。尾数部分的表示形式和浮点型常量的一般表示形式相同(不过,小数点和小数部分可以同时省略),指数部分必须是整型文字常量(不能带后缀)。例如:
4.1E12,.27e4,5E-2
浮点型常量的默认数据类型为双精度型。如果要将其说明为浮点型,则应在常量后面加后缀F(或f)。如果要将其说明为十进制型,则应在常量后加后面缀M(或m)。另外,如果想把浮点型常量显式说明为双精度型,也可以加后缀D(或d)。例如:
5.6f,6.2D,4.1E5M
对于浮点型常量的一般表示形式,如果其后面加有后缀F、f、M、m、D或d,则小数点和小数部分可以同时省略。例如:
1F //浮点型
2M //十进制型
22D //双精度型
3. 字符常量
字符常量的数据类型是char。通常情况下,它是指用单引号括起来的一个字符。例如:
'A','b','$','*'
此外,C#语言还提供了一种转义字符。转义字符以反斜杠“\”开头,后面跟一个字符或Unicode码,它通常被用来表示那些一般方法无法表示的字符。下表列出了C#语言中常用的转义字符。
由表可知,可以采用4位十六进制Unicode码表示相应的字符常量。不过,其中的十六进制数字必须有4位。例如:
'\u0041' //表示“A”
'\u0007' //表示“!”
在C#语言中,“\”、“ ' ”和“"”各自有其特定的意义。如果需要把它们用作字符常量,就应该采用表中定义的转义字符。
4. 字符串常量
字符串常量的数据类型是string,它指的是用双引号括起来的一串字符。字符串中的字符也可以是任意有效的转义字符。标识字符串的两个双引号通常必须在程序的同一行,如果需要在字符串中插入换行符,则应该使用转义字符‘\n’。例如:
" "
"a string"
"Hello! \n How are you?"
技巧
字符串中的字符可以是0个。
C#语言允许字符串常量中出现的“\”号不表示转义字符,而是表示自身的符号。如果读者希望字符串常量中出现的“\”号不被解释成转义字符,则只需在该串字符的起始双引号前面加上一个“@”符号即可。例如:
@"c:\cshape\book" //等价于 "c:\\cshape\\book"
这种表示方法通常被称做逐字字符串表示法。使用这种表示法,双引号不必在程序的同一行。例如:
@"the string has
two lines" //正确
而
"the string has
two lines" //错误
5. 布尔常量
布尔常量仅有两个:false(假)和true(真),其数据类型为bool。
3.5.2 变量
变量是指在程序运行过程中值可以改变的量,通常在程序中存储一个中间值或最终结果。在C#中可以用一个标识符来标识变量名。
提示
作为变量名的标识符,在起名时一定要有意义,便于阅读记忆。为了和C#语言系统使用的变量区别,我们自己定义的变量应尽量不使用“_”开头。
变量是存在于内存中的,当程序运行时,每个变量都要占用连续的内存空间。变量所占内存空间的字节多少由变量的数据类型决定,但是不管变量占用多少字节的内存空间,我们都把第1个字节的地址称为变量的地址。在系统中,变量名表示对应的存储地址单元,变量类型就决定了对应存储单元中的数据类型。通过变量名可以很方便地对相应的存储单元进行存取或修改等操作。C#要求变量在使用前必须先声明其名称和数据类型。
1. 变量的声明
声明变量的格式如下。
[变量修饰符] 类型说明符变量名1=初值1,变量名2=初值2,…,
功能:定义若干个变量,变量名由“变量名1”、“变量名2”等指定,数据类型由“类型说明符”指定,简单变量的类型说明符有sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、bool、string等。在定义变量的时候,可以给变量赋初值,初值由“初值1”、“初值2”等确定。
说明:“变量修饰符”用来描述对变量的访问级别和是否是静态变量等,有private、public、protected、internal、static等类型,若缺省“变量修饰符”,则默认为private。例如:
private static int gz=65;
public double jj=76.8;
变量命名遵循标识符命名规则,变量声明时可以直接赋初值。例如:
string n="stladent";
int x=l,y,z=x*2;
在C#中要求对变量明确赋初值,使用未初始化的变量会导致编译器报错。如下面的代码在编译时就会报错:
public Void say( )
{ string strVar;
console.writeLine(strVar);} //错误,使用未赋初值的变量
C#中共定义了7种变量类别:静态变量、实例变量、数组元素、值参数、引用参数、输出参数以及局部变量。在下面的例子中:
class A
{
public static int X;
int y;
void F(int[ ] V,int a,ref int b,out int C)
{int i=1;
C=a+b++;
}}
X是静态变量,Y是实例变量,V[0]是数组元素,a是值参数,b是引用参数,c是输出参数,i是局部变量。
提示
在C#中,不存在类似其他语言的全局变量,任何变量的声明都必须存在于类型结构中(类、结构、接口等)。
如果声明变量时没有给变量赋初始值,变量会带有默认的值。默认初始值如下表所示。
2. Object类型变量
在C#中,声明为Object类型的变量可以存储任意类型的数据。Object类型基于ASP.NET框架中的System.Object,是其他所有数据类型的基类型。所有数据类型均从System.Object类继承。
【范例3-3】显示Object类型的变量可以接受任何数据类型的值,以及Object类型的变量可以使用System.Object类方法。
⑴在Visual Studio 2010中,新建名为“object”的【Visual C#】【控制台应用程序】。
⑵在“class Program”后面的两个大括号中间输入以下代码(代码3-3.txt)。
01 public class MyClassl
02 {
03 public int m= 200;
04 }
05 public class MyClass2
06 {
07 public static void Main()
08 {
09 object a;
10 a= 1; //装箱操作
11 Console.WriteLine(a);
12 Console.WriteLine(a.GetType()); //调用System.Object类方法
13 Console.WriteLine(a.ToString()); //调用System.Object类方法
14 Console.WriteLine();
15 a= new MyClassl();
16 MyClassl ref_MyClassl;
17 ref_MyClassl= (MyClassl)a;
18 Console.WriteLine(ref_MyClassl.m);
19 }
20 }
【运行结果】
按【Ctrl+F5】组合键运行,即可在控制台中输出如下图所示的结果。
注意
Object类型的使用非常灵活,但是建议不要在程序中为了图方便而频繁地使用它,这样做一方面会增加程序的开销,另一方面容易导致一些隐藏的不易被发现的逻辑错误。
3.6 数组
本节视频教学录像:8分钟
我们在程序中需要使用很多相同类型的数据,如果使用一个就要声明一个相应的变量,是不是很不方便?C#中的重要数据结构——数组,恰恰为我们解决了这一问题。数组是数据类型相同、数目一定的变量的有序集合,组成数组的变量称为该数组的元素。在内存中数组对应着一组顺序排放的存储单元,数组中的每个元素按照创建时的次序在其中连续存放。这些数组元素具有相同的名称,在程序中以下标相互区分,下标可以以变量或表达式来表示,这为我们循环处理数据带来了方便。
3.6.1 声明和创建数组
在C#语言中,数组是一种引用类型,使用前需要声明和创建。本节以一维数组为例来学习数组的声明和创建方式。一维数组是指只有一个下标的数组。
1. 声明数组
一维数组的声明格式如下。
数据类型符 [ ] 数组名;
其中,数据类型表示的是数组中元素的类型,它可以是C#语言中任意合法的数据类型(包括数组类型);数组名是一个标识符;方括号“[]”是数组的标志。例如:
Int [] a;
striTlg [] s;
在C#中数组是一种引用类型。声明数组只是声明了一个用来操作该数组的引用,并不会为数组元素实际分配内存空间。因此声明数组时,不能指定数组元素的个数。例如:
int[5] a; //错误
另外,声明数组时也不能把方括号“[]”放在数组名的后面。例如:
int b[ ]; //错误
2. 创建数组
声明数组后,在访问其元素前必须为数组中的元素分配相应的内存,也即创建数组。创建一维数组的一般形式如下。
数组名=new数据类型[数组元素个数]
其中,用于指定数组元素个数的表达式的值必须是一个大于或等于0的整数。如果值为0,则表示该数组为空(不包含任何元素),一般来说,这种数组没有什么实际意义。例如:
Int [ ]a;
a=new int[5];
此处创建了一个有5个int型元素的数组。
当然,我们也可以直接写成一条语句。格式为:
数据类型符 [ ] 数组名=new 数据类型符[数组长度]
例如:
int [] a=new int[8];
创建数组后,就可以通过其下标访问其中的元素:
数组名[下标]
与C和C++不同,C#中的数组长度可以动态确定。
Int m=8;
Int a[]=new int a[m];
注意
下标的值必须是整数类型。由于在C#语言中,数组的第1个元素索引为0,第2个元素索引为1,依此类推,因此索引表达式的最大值是数组元素个数减1。如果指定的下标表达式的值大于最大值或小于0,那么程序运行时,将会引发异常。
【范例3-4】创建数组并输出各个数组元素。
⑴在Visual Studio 2010中,新建名为“shuzu”的【VisualC#】【控制台应用程序】。
⑵在“static void Main(string[] args)”后面的两个大括号中间输入以下代码(代码3-4.txt)。
01 int i;
02 int[] a= new int[4];
03 bool[]b= new bool[3];
04 object[] c= new object[5];
05 Console.Write("int");
06 for (i= 0; i< a.Length; i++)
07 Console.Write("\t a[{0}]={1}", i, a[i]);
08 Console.Write("\nbool");
09 for (i= 0; i<b.Length; i++)
10 Console.Write("\tb[{0}]={1}", i,b[i]);
11 Console.Write("\n object");
12 for (i= 0; i< c.Length; i++)
13 Console.Write("\t c[{0}]={1}", i, c[i]);
14 Console.WriteLine();
【运行结果】
按【Ctrl+F5】组合键运行,即可在控制台中输出如图所示的结果。
【范例分析】
在C#语言中,所有数组类型实际上都是从System.Array抽象类派生出来的,因此,每个数组都可以使用Array类中的属性和其成员。本例中使用的Length属性就是Array类定义的,它返回的是当前数组中元素的个数。另外从本范例的运行结果可以看到,数组中的元素一定有初值,其默认值为:数值类型元素的默认值为0(char型即为:\u0000 ),bool型元素的默认值为false,对象引用的默认值为null。
提示
在C#语言中,如果创建的是一个引用类型数组,那么数组中保存的实际上只是对象引用。在访问这些对象的成员前,必须使用new运算符创建实际的对象。
创建数组时可以给数组元素指定初始值。例如:
int[]b=new int[3]{1,2,3};
此处创建了一个有3个int型元素的数组,并且数组中的元素值都被初始化。其中,大括号中的最后一个逗号可有可无,但如果大括号中用于初始化的值的个数与数组创建的元素个数不同,就会产生编译错误。例如:
int[]c=new int[4]{1,2,3}; //错误
注意
在这种初始化形式中,方括号内用于指定数组元素个数的表达式必须是一个常量表达式。
int i=3;
int[]c=new int[i]{1,2,3}; //错误
int[]d=new int[2+1]{1,2,3}; //正确
不过,下述语句是正确的:
int i=3;
int[]c=new int[i]; //正确
因为用于初始化的值的个数必须与数组中元素的个数相同,因此上述初始化表达式中完全可以不用显式地给出元素的个数。例如:
int[]b=new int[]{1,2,3}; /数组有3个元素
对应于上例,还有另一种更简洁的方式:
int[]b={l,2,3};
不过,这种简洁方式只能与数组声明出现在同一条语句中。例如:
int[]b;
b={1,2,3}; //错误
此处是错误的。而下例则是正确的:
int[]b;
b=new int[]{1,2,3};
3.6.2 多维数组
前面介绍的数组都是一维数组。一维数组只有一个下标,多维数组具有多个下标。要引用多维数组的元素,就要使用多个下标。多维数组中用得最多的就是二维数组,即有两个下标的数组,适合用来处理如成绩报表、矩阵等具有行列结构的数据。我们把二维数组中每一行数组元素个数相等的二维数组叫做方形二维数组,把不相等的叫做参差数组。在C#语言中,可以声明和创建多维数组。例如:
int[ , ]A;
A=new int[3,2];
此处声明并创建了一个3行2列的二维数组,并且数组中的每个元素都初始化为默认值。声明和创建二维数组时,在方括号“[]”中需要使用1个逗号,依此类推,使用更多的逗号就可以声明和创建三维及三维以上的数组。例如:
Int[ , , ] A=new int[2,3,4];
此处声明并创建了一个三维(2、3和4)数组,并且数组中的每个元素都初始化为默认值。创建多维数组时,可以同时初始化。多维数组的初始化形式与一维数组相似。例如:
int[ , ]Al=new int[4,2]{{1,2},{3,4},{5,6},{7,8}};
int[ , , ]A2=new int[ , , ]{{{l,2,3}},{{4,5,6}}};
其中,大括号嵌套的级别应与数组的维数相同。最外层的嵌套与最左边的维数对应,而最内层的嵌套则与最右边的维数对应。数组中每个维的长度与相应嵌套级别中元素的个数相同。与一维数组相同,也可以采用如下形式声明并创建一个多维数组:
int[ , , ]A4={{1,2},{3,4},{5,6},{7,8}};
注意
这种书写方式只能与数组声明出现在同一条语句中。
例如:
int[ , , ]A;
A={{l,2},{3,4},{5,6},{7,8}}; //错误
这两条语句就是错误的。而下例则是正确的:
int[ , , ]A;
A=new int[,]{{1,2},{3,4},{5,6},{ 7,8}};
创建一个多维数组后,就可以通过下述表达式引用其中的元素:
数组名[下标表达式1,下标表达式2,……]
其中,每个下标表达式的值都必须在0到它指定的维度的大小减l之间。例如:
A[2,1]=25;
3.7 数据类型转换
本节视频教学录像:9分钟
C#的系统编译器为了能高效地处理数据,防止由于数据类型不匹配而导致运行错误,通常不允许用一种类型替换另一种类型。但是为了提高在程序设计过程中的灵活性,与其他大部分的高级语言类似,C#也提供了类型转换机制,主要包括两种类型转换:隐式转换和显式转换。
3.7.1 隐式转换
隐式转换是系统默认的类型转换形式,即编译器能自动支持的转换,既不需要加以声明,也不需要编写代码就可以进行转换。当然,并不是所有的类型之间都可以进行隐式类型转换,一般是当被转换的类型的取值范围完全包含在转换到的类型的取值范围之内时才能进行隐式转换。例如:
char cl= 'Y';
int sl;
sl=cl; //char类型的取值范围完全包含在int范围之内
下面是C#中合法的隐式转换类型对应表。
3.7.2 显式转换
当隐式转换不能实现正确的转换时,C#还提供了显式转换形式,即明确要求编译器将一种数据类型转换为另一种数据类型,也称为强制类型转换。例如:
short s1;
int xl=13;
sl=(short)xl; //强制类型转换
显式类型转换需要在被转换的表达式前面加上被转换的类型标识。下面是常见的显式转换类型对应表。
提示
由于不同数据类型对应存储空间的大小不同,因此在显式类型转换过程中可能导致数据精度损失或引发异常。常见的情况有:
⑴将decimal值转换为整型时,该值将舍入为与零最接近的整数值。如果结果整数值超出目标类型的范围,则会引发OverflowException异常。
⑵将double或float值转换为整型时,数值会被截断。
⑶将double转换为float时,double值将舍入为最接近的float值。如果double值因过小或过大而使目标类型无法容纳它,结果将为零或无穷大。
另外在C#中,还提供了一个简单的类型转换类——Convert,利用该类的相关方法可以实现显式类型转换。下表列出了Convert类的常用方法及其转换结果。其中转换方法中的类型名称与C#的类型名称有所不同,主要是因为这些命令来自于.NET框架的System命名空间,而不是C#本身。
提示
var可以是各种类型的变量。如果这些方法不能处理该类型的变量,程序编译时会给出提示。
3.7.3 装箱与拆箱
在C#中同时存在着两大类数据类型:值类型和引用类型。值类型都是一些简单类型,其变量直接用来存放数值,操作效率高。而引用类型则通常用来存放对象的地址,具有很强的面向对象特征,适用于面向对象的开发。但是,在程序开发中有时需要的是一种更为简单的、能够囊括所有可能值的类型,这样使得任何数据都可以被看成是对象存入其中。为了实现这一目的,在C#语言中引入了让值类型在需要时转换为引用类型,以及让引用类型在需要时转换为值类型的机制,即装箱与拆箱机制。利用装箱与拆箱功能,可通过允许值类型的任何值与object类型的值相互转换,将值类型与引用类型链接起来。
1. 装箱
装箱是指将一个值类型转换为一个object类型的过程。例如:
int x=15;
object obj=x; //利用隐式转换实现装箱
也可以用显式方法进行装箱操作。例如:
int x=15;
object obj=(object)x; //利用显式转换实现装箱
2. 拆箱
拆箱是指将一个object类型显式转换成一个值类型的过程。拆箱可分为两个步骤:其一是检查被转换的对象实例是否是给定的值类型的装箱值;其二是将这个对象实例复制给值类型的变量。例如:
int val=100;
object obj=val; //装箱
int num=(int)obj; //拆箱
Console.WriteIine("num:{0)",num);
注意
装箱和拆箱都必须遵循类型兼容原则,否则会引发异常。
3.8 表达式和运算符
本节视频教学录像:15分钟
表达式和运算符是构成程序中各种运算任务的基本元素,也是程序设计的基础。
3.8.1 表达式
表达式是由操作数和运算符组成的式子,是一个可以计算且返回结果的简单结构。其返回值可以为单个值、对象、方法,甚至命名空间。最简单的表达式是一个变量或常量。一个表达式中可以包含文本值、方法调用、运算符及其操作数等,并且表达式可以嵌套,因此表达式既可以非常简单,也可以非常复杂。例如:
X //变量表达式
10 //常量表达式
i=5 //赋值运算表达式
x*y //算术运算表达式
DoWork(var);//方法调用表达式
表达式是根据约定、求值次序、结合性和优先级规则来进行计算。其中约定是指类型转换的约定;求值次序是指表达式中各个操作数的求值次序;结合性是指表达式中出现同等优先级的运算符时,该先做哪个运算的规定;而优先级则是指不同优先级的运算符,总是先做优先级高的运算。
提示
可以说有什么样的运算符就有什么样的表达式。
3.8.2 运算符
C#提供有大量的运算符,用这些运算符来实现对变量或其他数据进行加、减等各种运算。C#常用运算符的功能、优先级和结合性如表所示。
运算符具有优先级和结合性。当一个表达式中含有多个运算符时,运算符的优先级决定了表达式中进行不同运算的先后顺序,即先进行优先级高的运算,后作优先级低的运算。而运算符的结合性则决定了表达式中并列多个相同优先级的运算的进行顺序,即是自左向右,还是自右向左。
C#运算符按其所要求操作数的多少,可分为一元运算符、二元运算符、三元运算符。一元运算符需要一个操作数,二元运算符需要两个操作数,三元运算符需要3个操作数;按运算符的运算性质又可分为算术运算符、关系运算符、条件逻辑运算符等。
1. 基本赋值运算符
基本赋值运算符(=)用于赋值运算。由基本赋值运算符组成表达式的一般形式是:
变量=表达式
其中,右边的表达式可以是任何一个常量、变量或其他有能力产生数值的表达式,左边则必须是一个明确的变量。赋值表达式的意义是将运算符右边表达式的值赋给左边的变量。赋值后表达式本身的值就是左边变量的值。例如:
x=2.6 //运算后 x的值为2.6,表达式的值也是2.6
4=x //错误,左操作数必须是变量
在C#语言中可以连续赋值,例如:
x=y=z=2.6 //运算后 x、y、z的值均为2.6
进行赋值运算时,左边变量的类型必须与右边的值相容。比如,不能将一个bool类型的值赋给整数类型变量;不能将double型的值赋给int型变量(如果需要,必须显式转换)。不过,可以将int型的值赋给double型变量。
2. 算术运算符
算术运算符用于对整数类型或浮点数类型的操作数进行运算。包括基本算术运算符,一元加、减运算符、自增、自减运算符等。
⑴基本算术运算符
基本算术运算符包括:+(加号)、-(减号)、*(乘号)、/(除号)、%(取余),它们都是二元运算符。运算符“+”、“-”、“*”、“/”的使用方法与在代数中基本相同。只是需要注意:对于“/”运算符,当它的两个操作数都是整数类型时,其计算结果是运算后所得商的整数部分。例如:
5/2 //值为2
运算符“%”的意义是求两个数相除后的余数。在C++语言中,两个操作数必须都是整数类型,但C#语言对此进行了扩充,操作数可以是浮点数。例如:
10%4 //值为2
4.6%2.1 //值为0.4
注意:当对负数进行取余运算时,其结果永远与取余运算符左边的数值有相同的正负号。例如:
-7%5 //值为 -2
7%-5 //值为2
-7%-5 //值为 -2
⑵一元加、减运算符
一元加“+”和一元减“-”与二元加、减运算符的写法相同,C#编译器会根据程序中表达式的形式自动判定。例如:
i=+5 //等价于 i=5
i=8/-2
不过,第2个表达式最好写成:
i=8/(-2)
一元加、减运算符的意义等同于代数中的正、负号。实际编程时,一元加号通常省略。
⑶自增、自减运算符
自增、自减运算符都是一元运算符,有前缀和后缀两种形式。前缀是指运算符在操作数的前面,后缀是指运算符在操作数的后面。例如:
i++ //后缀递增
--i //前缀递减
自增、自减运算符不论是作为前缀还是后缀,其运算结果都是使操作数的值增1或减1,但操作数和运算符组成的表达式的值并不相同。前缀形式是先计算操作数的值(增1或减1),后把操作数的值作为表达式的结果;后缀形式是先将操作数的值作为表达式的结果,然后把操作数的值增1或减1。当这种表达式被用作操作数继续参与其他运算时,这一点要特别注意。例如:
int i=5;
int j=3;
int k1=i++; //k1=5,i=6
int k2=++i; //k2=6,i=7
int m1=--j; //m1=2,j=2
int m12=j; //m2=1,j=2
由于自增、自减运算符改变的是操作数自身的值,因此,自增、自减运算中的操作数只能是一个变量。例如:
5++ //错误
(i-j)-- //错误
提示
在C++语言中,参与自增、自减运算的操作数必须是整数类型的变量。但是在C#语言中,操作数也可以是浮点数类型的变量。
3. 关系运算符
在C#语言中,关系运算符共有6个:<(小于)、<=(小于或等于)、>(大于)、>=(大于或等于)、==(等于)、!=(不等于)。它们都是二元运算符,用于比较两个操作数之间的关系,运算结果是一个bool型的值。当两个操作数满足关系运算符指定的关系时,表达式的值为true,否则为false。运算符“==”和“!=”的操作数可以是C#语言中除了自定义结构外的任意一个数据类型的数据,但其他关系运算符的操作数只能是整数、浮点数或字符。
注意
因为浮点数在计算机中只能近似地表示,所以两个浮点数一般不能直接进行相等比较。如果需要进行相等比较,通常的做法是指定一个极小的精度值,当两个浮点数的差在这个精度之内时,就认为它们相等,否则为不等。
4. 条件逻辑运算符
在C#语言中,条件逻辑运算符共有6个:!(逻辑非)、&&(条件与)、||(条件或)、^ (逻辑异或)、&(逻辑与)、| (逻辑或)。其中,“!”是一元运算符,另外5个是二元运算符。与C++语言不同,条件逻辑运算符的操作数都必须是bool类型,运算结果也是bool类型。具体运算规则如下表所示。
提示
由上表可知,运算符“&&”与“&”,“.||”与“|”在使用方法上类似。不过它们之间也有不同之处:进行条件与“&&”或条件或“||”运算时,只要能够确定运算结果,运算就不再继续进行。如果参与这个运算的操作数也是一个需要运算求值的表达式,则必须注意这一点。
例如:
int i=2,j=4;
bool b=i>j&&j++>i--;
在计算布尔变量b的值时,首先计算关系表达式i>j的值,结果为false,根据条件与运算的规则,不论运算符“&&”右边表达式的值是什么,条件与运算后的结果都是false。因此,运算符“&&”右边的表达式就不被执行。计算结束后,b=false,i=2,j=4。而进行逻辑与“&”或逻辑或“|”运算,不管左操作数是true还是false,总会计算右操作数的值。
5. 复合赋值运算符
在C#语言中,除了基本赋值运算符=外,另外还有10个复合赋值运算符:+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|=。它们是由基本赋值运算符和二元算术运算符、逻辑运算符或位运算符等结合在一起构成的。这些复合运算符组成表达式的一般形式为:
变量 复合赋值运算符 表达式
其中,表达式与基本赋值运算符中的要求相同。上述形式可进一步分解为:
变量算术运算符(或位运算符等)=表达式
其意义等同于下述表达式:
变量=变量算术运算符(或位运算符等)表达式
例如:
x*=2 //等价于 x=x*2
x*=x+2 //等价于 x=x*(x+2)
6. 条件运算符
C#语言中有唯一的一个三元运算符,即条件运算符“?:”,由条件运算符和3个操作数组成的条件表达式的形式如下:
表达式1?表达式2:表达式3 .
其中,表达式1的值必须是bool型。它的运算顺序是:先计算表达式1的值,若表达式1的值为true,则计算表达式2,并把它的值作为条件表达式的值;否则计算条件表达式3,并把它的值作为条件表达式的值。条件表达式的类型为表达式2和表达式3中类型取值范围大者。例如:
x=(4>5)?4:5 //运算结果x=5
7. 字符串连接运算符
在C#语言中,运算符“+”能用于连接字符串,例如:
“Hello!”+”C# world” //值为 ”Hello!C# World”
注意
当运算符“+”用于操作字符串时,它的两个操作数中可以有一个不是字符串。如果其中的一个不是字符串,那么在进行字符串合并操作前,C#编译器会自动将其转换为相应的字符串形式。
3.9 程序流程控制及常用语句
本节视频教学录像:27分钟
没有流程控制结构,一个应用程序就完全无法运行。顺序、选择、循环,再繁琐的程序也离不开这3种结构。掌握之后,就可以通吃所有的程序。顺序结构就是自始至终程序流程不发生转移的程序,主要用来实现赋值、计算和输入/输出等操作。选择结构是在程序执行过程中会根据某些条件是否成立来确定某些语句是执行还是不执行,或者根据某个变量的或表达式的取值从若干个语句组中选择一组来执行。循环结构是指某些程序段需要重复执行若干次。
3.9.1 选择语句
选择语句依据一个条件表达式的计算值,从一系列被执行语句中选择出执行语句。
1. if语句
if语句也叫条件语句,它根据条件表达式的值来选择将要执行的语句。可以实现单分支、双分支和多分支等选择结构。
⑴if语句实现单分支选择结构。使用格式如下。
If(条件表达式)
语句;
流程图如下。
功能说明:首先计算条件表达式的值,如果结果为true,则执行后面的语句。如果表达式的值为false,则不执行后面的语句。
⑵if语句实现双分支选择结构。使用格式如下。
if (条件表达式)
语句1;
else
语句2;
流程图如下。
功能说明:首先计算条件表达式的值,如果为true则执行语句1,如果值为false,则执行语句2。
例如:
If (x-(int)x>0.5)
i=(int)x+1;
else
i=(int)x;
⑶if语句实现多分支选择结构。使用格式如下。
if (条件表达式1) 语句1;
else if(条件表达式2) 语句2;
else if(条件表达式3) 语句3;
……
else
语句n;
其流程图如下。
功能说明:本结构首先判断条件表达式1的值是否为true,如果是就执行语句1,如果为false,则继续判断条件表达式2的值是否为true,如果条件表达式2的值为true,就执行语句2,否则继续判断条件表达式3的值……依此类推,直到找到一个条件表达式的值为true并执行后面的语句。如果所有的条件表达式的值都是false,则执行else后面的语句n。
注意
If语句实现多分支选择结构,其实就是在双分支选择结构的else后面的语句2的位置嵌套了另一个if双分支选择结构语句。这样形成if语句的嵌套,可以实现程序中复杂的逻辑判断。
提示
语句中的条件表达式通常为关系表达式或逻辑表达式。上面的“语句”或“语句1”等在条件允许时,可以是由“{”和“}”括起来的一个程序段,当然也包括其他各类语句。else分支与最近的if语句构成一个if-else对。if语句并不一定必须有else分支。只有需要多个判断条件使程序形成多个分支的话,才在if后面的else语句中加入其他if-else分支。
例如:
If (x>0) { y=1; }
else
{ if (x==0) { y=0; }
else
{ y= -1; }
}
2. switch语句
使程序形成多个分支的另一种方法是使用switch语句,也叫开关语句。使用格式如下:
switch(控制表达式)
{
case常量表达式1:语句1;
break;
case常量表达式2:语句2;
break;
……
case常量表达式n:语句n;
break;
[default:语句n+1;break;]
}
功能说明:它根据一个控制表达式的值来决定执行不同的程序段。
流程图如下。
⑴switch后面的控制表达式可以是整形或字符型表达式,而case后面的常量表达式的类型则必须与控制表达式的类型相同,或者能够隐式地转换为控制表达式的类型。
⑵程序执行时首先计算控制表达式的值,然后依次与case后面的常量表达式1、常量表达式2……常量表达式n来比较,如果控制表达式的值与某个case后面的常量表达式的值相等,就执行这个case后面的相应语句,然后执行break语句退出switch语句。如果控制表达式的值与所有的case后面常量表达式的值都不同,则执行default后面的“语句n+1”,执行后退出switch语句,最后程序继续执行switch语句后面的下一条语句。
⑶switch语句中各个case后面的常量表达式不一定要按值的大小排列,但是要求各个常量表达式的值必须是不同的,从而保证分支选择的唯一性。
⑷如果某个分支有多条语句,可以用大括号括起来,也可以不加大括号。因为进入某个case分支后,程序会自动顺序执行本分支后面的所有语句。
⑸default总是放在最后。default语句可以缺省。当default语句缺省后,如果switch语句后面的控制表达式的值与任一常量表达式的值都不相等,将不执行任何语句,而直接退出switch语句。
⑹各个分支语句中的break不可省略,否则会出现错误。
【范例3-5】接受5分制分数的输入,并转换为相应的等级输出。
⑴在Visual Studio 2010中,新建名为“score”的【Visual C#】【控制台应用程序】。
⑵在“static void Main(string[] args)”后面的两个大括号中间输入以下代码(代码3-5.txt)。
01 Console.WriteLine("请输入分数 :");
02 int X= int.Parse(Console.ReadLine());
03 switch (X)
04 {
05 case 5:
06 Console.WriteLine("优秀 ");
07 break;
08 case 4:
09 Console.WriteLine("良好 ");
10 break;
11 case 3:
12 Console.WriteLine("及格 ");
13 break;
14 default: //3分以下均不及格
15 Console.WriteLine("不及格 ");
16 break;
17 }
18 Console.ReadLine();
【运行结果】
按【Ctrl+F5】组合键运行,即可在控制台中输出如图所示的结果。根据提示输入分数4,按【Enter】键,即可输出分级结果。
3.9.2 循环语句
循环语句用于程序段的重复执行。C#中提供有4种循环:while循环、do-while循环、for循环和foreach循环。很多条件下它们可以相互替代。
1. while循环语句
while语句实现的循环是当型循环,其使用格式如下。
while (表达式)
语句;(即循环体部分)
流程图如下。
功能说明:程序先计算while后面表达式的值,若结果为true,则执行循环语句部分,然后再次计算while后面的表达式,重复上述过程……当某次计算的表达式的值为false时,则退出循环,转入下一条语句执行。
提示
⑴循环体如果包含一条以上的语句,应该用花括号括起来作为复合语句。
⑵循环最终都要退出,所以在循环体中应包含有使循环趋于结束的语句,即能使表达式的值由true变为false的语句。
⑶由于先判断条件,也许第1次判断条件时,表达式的值就是false,在此情况下循环体则一次也不执行。所以当型循环又叫做“允许0次循环”。
【范例3-6】计算整数的阶乘。
⑴在Visual Studio 2010中,新建名为“jiecheng”的【Visual C#】【控制台应用程序】。
⑵在“static void Main(string[] args)”后面的两个大括号中间输入以下代码(代码3-6.txt)。
01 int X= int.Parse(Console.ReadLine());
02 long Y= 1;
03 while (X> 1)
04 {
05 Y *=X;
06 X--;
07 }
08 Console.WriteLine("阶乘为:{0}",Y);
09 Console.ReadLine();
【运行结果】
按【Ctrl+F5】组合键运行,输入4,按【Enter】键,即可输出4的阶乘结果。
2. do-while循环语句
do-while循环语句的使用格式如下。
do 循环体语句;
while (表达式);
流程图如下。
功能说明:执行循环体中的语句,然后计算表达式的值,若表达式的值为true,则再执行循环体中的语句……如此循环,直到某次计算表达式的值时,表达式的值为false,这个时候将不再执行循环体,而是转到循环体后面的语句执行。
提示
⑴ do--while语句是先执行语句,后判断表达式。所以无论一开始表达式的值是true还是false,循环体中的语句至少执行一次,因此直到型循环又叫“不允许0次循环”。
⑵如果do-while语句的循环体部分是由多个语句组成的,则必须作为复合语句用花括号括起来。
【范例3-7】用do-while循环改写上面求阶乘的范例。
⑴在Visual Studio 2010中,新建名为“dowhile”的【Visual C#】【控制台应用程序】。
⑵在“static void Main(string[] args)”后面的两个大括号中间输入以下代码(代码3-7.txt)。
01 int X= int.Parse(Console.ReadLine());
02 long Y= 1;
03 do
04 {
05 Y *=X;
06 X--;
07 }
08 while (X> 1);
09 Console.WriteLine("阶乘为:{0}",Y);
10 Console.ReadLine();
【运行结果】
按【Ctrl+F5】组合键运行,输入5,按【Enter】键,即可输出5的阶乘结果。
3. for循环语句
for循环语句用在预先已知循环次数的情况下。for语句又叫做计数循环语句,其使用格式如下。
for(表达式1;表达式2;表达式3)
语句;
流程图如下。
功能说明:表达式1、表达式2、表达式3分别是循环初始表达式、循环判断表达式和循环控制表达式,它们之间用分号分割。for循环的执行顺序为:首先计算表达式1(只执行一遍),通常是初始化循环变量。然后计算表达式2,若表达式2的值为true,则执行for语句中的循环体,循环体执行后,计算表达式3。接着返回再次计算表达式2,若表达式2的值为true,再执行for语句中的循环体……如此循环,当某次计算表达式2的值为false时,则退出for循环,接着执行for后面的语句。
需要注意的是:
⑴for语句中的表达式1可省略,此时应在for语句之前给循环变量赋值。例如:
for(;k<=100;k++) sum+=k;
循环执行时,没有“计算表达式1”这一步,其他不变。
⑵“表达式2”应是逻辑表达式或关系表达式,也可省略,省略时相当于表达式2的值为true,此时要退出循环,需使用后面介绍的break语句。
⑶“表达式3”也可以省略,但此时程序设计者应保证循环能正常结束。例如:
for(s=0;k=1;k<=100;)
{s+=k;k++;}
本例中的k++不是放在for语句的表达式3的位置处,而是作为循环体的一部分,效果是一样的,都能使循环正常结束。
⑷可以省略表达式1和表达式3,只有表达式2,即只给出循环条件。例如:
for( ;i<=100;)
{sum+=i;i++;}
此语句相当于:
while(i<=100){sum+=i;i++;)
⑸表达式l、表达式2和表达式3均可省略。例如:
for( ;; )
语句;
该语句相当于:
while(true)
语句;
【范例3-8】循环打印整数1~9。
⑴在Visual Studio 2010中,新建名为“print”的【Visual C#】【控制台应用程序】。
⑵在“static void Main(string[] args)”后面的两个大括号中间输入以下代码。
01 for (int i= 0; i< 10; i++)
02 Console.WriteLine(i);
【运行结果】
按【Ctrl+F5】组合键运行,即可在控制台中输出如图所示的结果。
技巧
for语句同样可以嵌套使用,以处理大量重复性的程序。
4. foreach循环语句
foreach语句是C#中新增的循环语句,对于处理数组及集合等数据类型特别方便。功能与for语句相似,但是使用起来比for语句更为方便。
foreach语句的一般语法格式如下:
foreach(数据类型标识符 in 表达式)
循环体;
功能说明:数据类型是指要访问的集合或数组中元素的类型;标识符是一个迭代变量,相当于一个指针,每次后移一位;表达式是要访问的集合或者数组名称。
for语句和foreach语句的主要区别在于,for需要通过控制计数器来控制循环体的执行次数;而用foreach无需了解循环体究竟要执行多少次,也不用考虑索引的问题。
【范例3-9】循环打印整数1~9。
⑴在Visual Studio 2010中,新建名为“printArray”的【Visual C#】【控制台应用程序】。
⑵在“static void Main(string[] args)”后面的两个大括号中间输入以下代码。
01 int[]arr=newint[]{0,1,2,3,4,5};
02 foreach (int a in arr)
03 Console.WriteLine(a);
【运行结果】
按【Ctrl+F5】组合键运行,即可在控制台中输出如图所示的结果。
3.9.3 转移语句
使用循环语句时,如果循环条件不被改变,循环就会一直进行下去。转移语句通常与循环语句结合使用,以提高循环的效率,避免“死循环”出现。
在循环执行过程中,若希望循环强制结束,则可使用break语句;若希望使本次循环结束并开始下一次循环,则可使用continue语句。
带有break语句的流程图如下。
1. break语句
break语句用于跳出switch选择语句和while、do-while、for等循环语句,并转移到其后的程序段。使用格式为:
break;
功能说明:终止对循环的执行,流程直接跳转到当前循环语句的下一语句执行。
提示
流程图中的表达式1通常是循环条件,表达式2通常是一个if语句中的条件。
(1)break语句只可用在switch语句和3种循环语句中。(2)一般在循环体中并不直接使用break语句,而是和一个if语句配合使用,在循环体中测试某个条件是否满足,若满足则执行break语句退出循环。break语句提供有退出循环的另一种方法。(3)在循环嵌套中,break语句只能终止一层循环。
【范例3-10】求1~10之间的质数。
⑴在Visual Studio 2010中,新建名为“zhishu”的【Visual C#】【控制台应用程序】。
⑵在“static void Main(string[] args)”后面的两个大括号中间输入以下代码(代码3-10.txt)。
01 bool flag;
02 for (int i= 2; i<= 10; i++)
03 {
04 flag= true;
05 for (int j= 2; j<= i / 2; j++)
06 {
07 if (i % j== 0)
08 {
09 flag= false;
10 break;
11 }
12 }
13 if (flag)
14 Console.Write("{0}\t", i);
15 }
16 Console.WriteLine();
【运行结果】
按【Ctrl+F5】组合键运行,即可在控制台中输出如图所示的结果。
2. continue语句
continue语句只用于跳出while、do-while、for和foreach等循环语句,并转移到循环语句的开始重新执行。
3. return语句
return语句用于函数的返回。如果在程序主方法中使用return语句,程序则结束。
3.10 高手点拨
本节视频教学录像:4分钟
1. 三目运算符与if…else语句的关系
或许读者已经看出来了,三目运算符就相当于if…else语句,只不过三目运算符有返回值。不过还是得提醒读者,为了使程序清晰明了,只有在if…else语句的主体部分很少时才使用三目运算符。
2. var隐式声明
VAR 是从NET 3.5开始出现的一个定义变量的类型,VAR可代替任何类型,编译器会根据上下文来判断到底是什么类型。类似于Object类型。Object类型在使用时要注意以下几点:
⑴必须在定义时初始化。也就是必须是var s =“abcd”形式,而不能是如下形式:var s;s =“abcd”;
⑵一旦初始化完成,就不能再给变量赋予与初始化值类型不同的值了。
⑶var要求是局部变量。
⑷使用var定义变量和object不同,它在效率上和使用强类型方式定义变量完全一样。
3. 三种循环的关系
我们讲到的三种循环结构其实是可以互相转化的,通常我们只是使用其中一种结构,因为这样可以使程序结构更加清晰。例如,下面的三段代码在功能是等同的,读者可根据自己的习惯取舍其中的一种方式。
⑴使用for 循环。
for( int i=0; i<10;++i )
{
System.out.println( "i ="+ i );
}
⑵使用while循环。
int i = 0;
while( i < 10 )
{
System.out.println( "i ="+ i );
++i;
}
⑶使用do-while循环。
int i = 0;
do
{
System.out.println( "i ="+ i );
++i;
}while( i < 10 )
4. 循环的区间控制
在习惯上,我们在循环中通常使用半开区,即从第一个元素开始,到最后一个元素的下一个位置之前。同样是循环十次类,我们推荐使用
for( int i = 0; i < 10;++i )
而非
for( int i =0; i <= 9;++i )
来循环十次。前者更具有可读性,而后者也能达到相同功能,读者可根据自己的代码风格进行取舍。
3.11 实战练习
1. 编写程序,使用循环控制语句计算“1+2+3+…+100”的值。
2. 编写程序,使用程序产生1~12的某个整数(包括1和12),然后输出相应月份的天数(2月按28天算)。