资源描述
,C#实用教程,第5章Windows应用程序,第4章面向对象编程进阶,第3章面向对象编程基础,第2章C#编程基础,第1章C#快速入门,C#实用教程,第10章Web应用程序,第9章C#多线程技术,第8章数据库应用,第7章文件操作,第6章GDI+编程,1.1C#的优势,1.1C#的优势,简单性,1.没有指针是C#的一个显著特性,用户使用一种可操控的(Managed)代码进行工作时,直接的内存存取,将是不允许的。2.在C#中不再需要记住那些源于不同处理器结构的数据类型,现代性,1.用户可以使用一个新的decimal数据类型进行货币计算。2.C#通过代码访问安全机制来保证安全性,根据代码的身份来源,可以分为不同的安全级别,不同级别的代码在被调用时会受到不同的限制。,面向对象,1.C#支持面向对象的所有关键概念:封装、继承和多态性。2.C#的继承机制只允许一个基类。如果需要多重继承,用户可以使用接口。,类型安全性,1.C#实施了最严格的类型安全机制来保护它自身及其垃圾收集器。2.边界检查。3.算术运算溢出检查。4.C#中传递的引用参数是类型安全的。,版本处理技术,C#尽其所能支持DLL版本处理功能,虽然C#自己并不能保证提供正确的版本处理结果,但它为程序员提供了这种版本处理的可能性。有了这个适当的支持,开发者可以确保当他开发的类库升级时,会与已有的客户应用保持二进制级别上的兼容性。,1.2第一个C#程序,第2章C#编程基础,C#的基本数据类型、变量、常量、表达式、程序流程控制语句及数组等概念是C#程序设计的基础,掌握这些基本知识是编写正确程序的前提。,2.1基本类型,C#的基本数据类型、变量、常量、表达式、程序流程控制语句及数组等概念是C#程序设计的基础,掌握这些基本知识是编写正确程序的前提。,第2章C#编程基础,C#的基本数据类型、变量、常量、表达式、程序流程控制语句及数组等概念是C#程序设计的基础,掌握这些基本知识是编写正确程序的前提。,2.2.1值类型,所谓值类型就是一个包含实际数据的量。当定义一个值类型的变量时,C#会根据它所声明的类型,以堆栈方式分配一块大小相适应的存储区域给这个变量,随后对这个变量的读/写操作就直接在这块内存区域进行。.例如:intiNum=10;/分配一个32位内存区域给变量iNum,并将10放入该内存区域iNum=iNum+10;/从变量iNum中取出值,加上10,再将计算结果赋给iNum,图2.1值类型操作示意图,表2.1C#简单类型,C#中的值类型包括:简单类型、枚举类型和结构类型。,续表,表中“C#关键字”是指在C#中声明变量时可使用的类型说明符。,2.1.2引用类型,引用类型包括class(类)、interface(接口)、数组、delegate(委托)、object和string。其中object和string是两个比较特殊的类型。object是C#中所有类型(包括所有的值类型和引用类型)的根类。string类型是一个从object类直接继承的密封类型(不能再被继承),其实例表示Unicode字符串。一个引用类型的变量不存储它们所代表的实际数据,而是存储实际数据的引用。引用类型分两步创建:首先在堆栈上创建一个引用变量,然后在堆上创建对象本身,再把这个内存的句柄(也是内存的首地址)赋给引用变量。,例如:strings1,s2;s1=ABCD;s2=s1;其中,s1、s2是指向字符串的引用变量,s1的值是字符串ABCD存放在内存的地址,这就是对字符串的引用,两个引用型变量之间的赋值,使得s2、s1都是对ABCD的引用,如图2.2所示。,图2.2引用类型赋值示意,引用类型的值是引用类型实例的引用,特殊值null适用于所有引用类型,它表明没有任何引用的对象。当然也可能有若干引用类型的变量同时引用一个对象的实例,对任何一个引用变量作出修改都会导致该对象的值的修改。注意:堆栈是按先进后出(FILO)的原则存储数据项的一种数据结构;堆(heap)则是用于动态内存分配的一块内存区域,可以按任意顺序和大小进行分配和释放。C#中,值类型就分配在堆栈中,堆栈内存区域内保存着值类型的值,内存区域可以通过变量名来存取。引用类型分配在堆中,对象分配在堆时,返回的是地址,这个地址被赋值给引用。,可以把值类型与引用类型的值赋给object类型变量,C#用“装箱”和“拆箱”来实现值类型与引用类型之间的转换。“装箱”就是将值类型包装成引用类型的处理过程。当一个值类型被要求转换成一个object对象时,“装箱”操作自动进行,它首先创建一个对象实例,然后把值类型的值复制到这个对象实例,最后由object对象引用这个对象实例。,2.1.3值类型与引用类型的关系,例如:usingSystem;classDemopublicstaticvoidMain()intx=123;objectobj1=x;/装箱操作x=x+100;/改变x的值,此时obj1的值并不会随之改变Console.WriteLine(x=0,x);/x=223Console.WriteLine(obj1=0,obj1);/obj1=123,该实例的“装箱”操作说明如图2.3所示。,“拆箱”操作与“装箱”相反,它是将一个object类型转换成值类型。首先检查由object引用的对象实例值类型的包装值,然后把实例中的值复制到值类型的变量中。注意:当一个“装箱”操作把值类型转换为一个引用类型时,不需要显式地强制类型转换;而拆箱操作把引用类型转换到值类型时,由于它可以强制转换到任何可以相容的值类型,所以必须显式地强制类型转换。,usingSystem;classDemopublicstaticvoidMain()intx=123,y;objectobj1=x;/装箱操作x=x+100;/改变x的值,此时obj1的值并不会随之改变y=(int)obj1;/拆箱操作,必须进行强制类型转换Console.WriteLine(x=0,x);/x=223Console.WriteLine(obj1=0,obj1);/obj1=123,2.2变量与常量,C#的基本数据类型、变量、常量、表达式、程序流程控制语句及数组等概念是C#程序设计的基础,掌握这些基本知识是编写正确程序的前提。,2.2.1常量,常量,顾名思义就是在程序运行期间其值不会改变的量,它通常可以分为字面常量和符号常量。常量及其使用非常直观,以能读懂的固定格式表示固定的数值,每一种值类型都有自己的常量表示形式。,对于一个整数值,默认的类型就是能保存它的最小整数类型,其类型可以分为int、uint、long或ulong。如果默认类型不是想要的类型,可以在常量后面加后缀(U或L)来明确指定其类型。在常量后面加L或l(不区分大小写)表示长整型。例如:32/这是一个int类型32L/这是一个long类型在常量后面加U或u(不区分大小写)表示无符号整数。例如:128U/这是一个uint类型128UL/这是一个ulong类型整型常量既可以采用十进制也可以采用十六进制,不加特别说明默认为十进制,在数值前面加0 x(或0X)则表示十六进制数,十六进制基数用09、AF(或af),例如:0 x20/十六进制数20,相当于十进制数320 x1F/十六进制数1F,相当于十进制数31,1整数常量,一般带小数点的数或用科学计数法表示的数都被认为是浮点数,它的数据类型默认为double类型,但也可以加后缀符表明三种不同的浮点格式数。在数字后面加F(f)表示是float类型。在数字后面加D(d)表示是double类型。在数字后面加M(m)表示是decimal类型。例如:3.14,3.14e2,0.168E2/这些都是double类型常量,其中3.14e2相当于,/0.618E2相当于3.14F,0.168f/这些都是float类型常量3.14D,0.168d/这些都是double类型常量3.14M,0.168m/这些都是decimal类型常量,2浮点常量,字符常量,简单地说,就是用单引号括起来的单个字符,如A,它占16位,以无符号整型数的形式存储这个字符所对应的Unicode代码。这对于大多数图形字符是可行的,但对一些非图形的控制字符(如回车符)则行不通,所以字符常量的表达有若干种形式。单引号括起的一个字符,如A。十六进制的换码系列,以“x”或“X”开始,后面跟4位十六进制数,如X0041。Unicode码表示形式,以“U”或“u”开始,后面跟4位十六进制数,如U0041。显式转换整数字符代码,如(char)65。字符转义系列,如表2.2所示。,3字符常量,表2.2字符转义符,字符串常量是用双引号括起的零个或多个字符序列。C#支持两种形式的字符串常量,一种是常规字符串,另一种是逐字字符串。(1)常规字符串。双引号括起的一串字符,可以包括转义字符。例如:Hello,WorldnC:windowsMicrosoft/表示字符串C:windowsMicrosoft(2)逐字字符串。在常规的字符串前面加一个,就形成了逐字字符串,它的意思是字符串中的每个字符均表示本意,不使用转义字符。如果在字符串中需用到双引号,则可连写两个双引号来表示一个双引号。例如:C:windowsMicrosoft/与C:windowsMicrosoft含义相同HesaidHellotome/与HesaidHellotome含义相同,4字符串常量,5布尔常量,它只有两个值:true和false。,6符号常量,在声明语句中,可以声明一个标识符常量,但必须在定义标识符时就进行初始化,并且定义之后就不能再改变该常量的值。具体的格式为:const类型标识符=初值例如:constdoublePI=3.14159,变量是在程序运行过程中其值可以改变的量,它是一个已命名的存储单元,通常用来记录运算的中间结果或保存数据。在C#中,每个变量都具有一个类型,它确定哪些值可以存储在该变量中。创建一个变量就是创建这个类型的实例,变量的特性由类型来决定。C#中的变量必须先声明后使用。声明变量包括变量的名称、数据类型,必要时指定变量的初始值。声明变量的形式:类型标识符表;或类型标识符=初值,;,2.2.2变量,标识符必须以字母或者_(下划线)开头,后面跟字母、数字和下划线的组合。例如,name、_Int、Name、x_1等都是合法的标识符,但C#是大小写敏感的语言,name、Name分别代表不同的标识符,在定义和使用时要特别注意。另外变量名不能与C#中的关键字相同,除非标识符是以作为前缀的。例如:intx;/合法floaty1=0.0,y2=1.0,y3;/合法,变量说明的同时可以设置初始数值stringchar/不合法,因为char是关键字stringchar/合法C#允许在任何模块内部声明变量,模块开始于“”,结束于“”。每次进入声明变量所在的模块时,则创建变量并分配存储空间,离开这个模块时,则销毁这个变量并收回分配的存储空间。实际上,变量只在这个模块内有效,所以称为局部变量,这个模块区域就是变量的作用域。,表达式是由操作数和运算符构成的。操作数可以是常量、变量、属性等;运算符指示对操作数进行什么样的运算。因此,也可以说表达式就是利用运算符来执行某些计算并且产生计算结果的语句。C#提供大量的运算符,按需要操作数的数目来分,有一元运算符(如+)、二元运算符(如+,*)、三元运算符(如?:)。按运算功能来分,基本的运算符可以分为以下几类:(1)算术运算符(2)关系运算符(3)逻辑运算符(4)位运算符(5)赋值运算符(6)条件运算符(7)其他(分量运算符,下标运算符等),2.3运算符与表达式,2.3.1算术运算符,算术运算符作用的操作数类型可以是整型也可以是浮点型,运算符如表2.3所示,其中:“+*/”运算与一般代数意义及其他语言相同,但需要注意:当“/”作用的两个操作数都是整型数据类型时,其计算结果也是整型。例如:4/2/结果等于25/2/结果等于25/2.0/结果等于2.5“%”取模运算,即获得整数除法运算的余数,所以也称取余。例如:11%3/结果等于212%3/结果等于011.0%3/结果等于2,这与C/C+不同,它也可作用于浮点类型的,操作数“+”和“”递增和递减运算符是一元运算符,它作用的操作数必须是变量,不能是常量或表达式。它既可出现在操作数之前(前缀运算),也可出现在操作数之后(后缀运算),前缀和后缀有共同之处,也有很大区别。例如:+x先将x加一个单位,然后再将计算结果作为表达式的值。x+先将x的值作为表达式的值,然后再将x加一个单位。不管是前缀还是后缀,它们操作的结果对操作数而言,都是一样的,操作数都加了一个单位,但它们出现在表达式运算中是有区别的。例如:intx,y;x=5;y=+x;/x和y的值都等于6x=5;y=x+;/x的值是6,y的值是5,操作数“+”和“”递增和递减运算符是一元运算符,它作用的操作数必须是变量,不能是常量或表达式。它既可出现在操作数之前(前缀运算),也可出现在操作数之后(后缀运算),前缀和后缀有共同之处,也有很大区别。例如:+x先将x加一个单位,然后再将计算结果作为表达式的值。x+先将x的值作为表达式的值,然后再将x加一个单位。不管是前缀还是后缀,它们操作的结果对操作数而言,都是一样的,操作数都加了一个单位,但它们出现在表达式运算中是有区别的。例如:intx,y;x=5;y=+x;/x和y的值都等于6x=5;y=x+;/x的值是6,y的值是5,2.3.2关系运算符,关系运算符用来比较两个操作数的值,运算结果为布尔类型的值(true或false),如表2.4所示。,在C#中,简单类型和引用类型都可以通过=或!=来比较它们的数据内容是否相等。对简单类型,比较的是它们的数据值;而对引用类型来说,由于它的内容是对象实例的引用,所以若相等,则说明这两个引用指向同一个对象实例,如果要测试两个引用对象所代表的内容是否相等,则通常会使用对象本身所提供的方法,如Equals()。如果操作数是string类型的,则在下列两种情况下被视为两个string值相等。(1)两个值均为null。(2)两个值都是对字符串实例的非空引用,这两个字符串不仅长度相同,并且每一个对应的字符位置上的字符也相同。关系比较运算“、=、flase在C#中是没有意义的。,在C#中,简单类型和引用类型都可以通过=或!=来比较它们的数据内容是否相等。对简单类型,比较的是它们的数据值;而对引用类型来说,由于它的内容是对象实例的引用,所以若相等,则说明这两个引用指向同一个对象实例,如果要测试两个引用对象所代表的内容是否相等,则通常会使用对象本身所提供的方法,如Equals()。如果操作数是string类型的,则在下列两种情况下被视为两个string值相等。(1)两个值均为null。(2)两个值都是对字符串实例的非空引用,这两个字符串不仅长度相同,并且每一个对应的字符位置上的字符也相同。关系比较运算“、=、flase在C#中是没有意义的。,2.3.3逻辑运算符,假设p、q是两个布尔类型的操作数,表2.6给出了逻辑运算的真值表。,逻辑运算符是用来对两个布尔类型的操作数进行逻辑运算的,运算的结果也是布尔类型,如表2.5所示。,运算符“classEncodepublicstaticvoidMain()charch1=O,ch2=K;intkey=0 x1f;Console.WriteLine(明文:+ch1+ch2);ch1=(char)(ch1key);ch2=(char)(ch2key);Console.WriteLine(密文:+ch1+ch2);ch1=(char)(ch1key);ch2=(char)(ch2key);Console.WriteLine(解码:+ch1+ch2);,移位运算符有两个:一个左移()。语法形式:valuenum_bits左操作数value是要被移位的值,右操作数num_bits是要移位的位数。(1)左移。将给定的value向左移动num_bits位,左边移出的位丢掉,右边空出的位填0。例如:0 x1A2。右移过程如图2.8所示。,例如:0 x8AU2。右移过程如图2.9所示。右移运算符的作用相当于将value的值整除以,赋值运算符有两种形式,一种是简单赋值运算符,另一种是复合赋值运算符。1简单赋值运算符语法形式:var=exp2复合赋值运算符在进行如x=x+3运算时,C#提供一种简化方式x+=3,这就是复合赋值运算。语法形式:varop=exp/op表示某一运算符等价的意义是:var=varopexp,2.3.5赋值运算符,除了关系运算符,一般二元运算符都可以和赋值运算符在一起构成复合赋值运算,如表2.8所示。,语法形式:exp1?exp2:exp3其中,表达式exp1的运算结果必须是一个布尔类型值,表达式exp2和exp3可以是任意数据类型,但它们返回的数据类型必须一致。首先计算exp1的值,如果其值为true,则计算exp2值,这个值就是整个表达式的结果;否则,取exp3的值作为整个表达式的结果。例如:z=xy?x:y;/z的值就是x,y中较大的一个值z=x=0?x:x;/z的值就是x的绝对值条件运算符“?:”是C#中唯一一个三元运算符。,2.3.6条件运算符,当一个表达式含有多个运算符时,C#编译器需要知道先做哪个运算,这就是所谓的运算符的优先级,它控制各个运算符的运算顺序。例如,表达式x+5*2是按x+(5*2)计算的,因为“*”运算符比“+”运算符优先级高。当操作数出现在具有相同优先级的运算符之间时,如表达式“1062”按从左到右计算的结果是2,如果按从右到左计算,结果是6。当然“”运算符是按从左到右的次序计算的,也就是左结合。再如表达式“x=y=2”,它在执行时是按从右到左运算的,即先将数值2赋给变量y,再将y的值赋给x。所以“=”运算符是右结合的。在表达式中,运算符的优先级和结合性控制着运算的执行顺序,也可以用圆括号“()”显式地标明运算顺序,如表达式“(x+y)*2”。,2.3.7运算符的优先级与结合性,表2.9运算符的优先级与结合性,在表达式中,操作数的数据类型可以不同,只要相互兼容即可。当表达式中混合了几种不同的数据类型时,C#会基于运算的顺序将它们自动转换成同一类型。下面是C#的类型提升规则。(1)一个操作数是decimal类型,另一个操作数提升为decimal,但float或double类型不能自动提升为decimal。(2)一个操作数是double类型,另一个操作数提升为double。(3)一个操作数是float类型,另一个操作数提升为float。(4)一个操作数是ulong类型,另一个操作数提升为ulong,但带符号数,如sbyte、short、int或long不能自动提升。(5)一个操作数是long类型,另一个操作数提升为long。(6)一个操作数是uint类型,另一个操作数若是sbyte、short或int,那么这两个操作数都提升为long。(7)一个操作数是uint类型,另一个操作数提升为uint。(8)除以上情况之外,两个数值类型的操作数都提升为int类型。,2.3.8表达式中的类型转换:,任何程序都可以且只能由三种基本流程结构构成,即顺序结构、分支结构和循环结构。1.顺序结构是三种结构中简单的一种。即语句按照书写的顺序依次执行;2.分支结构又称为选择结构,它将根据计算所得的表达式的值来判断应选择执行哪一个流程分支;3.循环结构则是在一定条件下反复执行一段语句的流程结构。,2.4.1结构化程序设计的三种基本流程,图2.10程序设计的三种控制流程,分支语句就是条件判断语句,它能让程序在执行时根据特定条件是否成立而选择执行不同的语句块。C#提供两种分支语句结构,if语句和switch语句。,2.4.2分支语句,1if语句1.if框架语法形式:if(条件表达式)语句;2.if_else框架语法格式:if(条件表达式)语句1;else语句2;,3.if_elseif框架语法形式:if(条件表达式1)语句1;elseif(条件表达式2)语句2;elseif(条件表达式3)语句3;else语句n;4.嵌套的if语句,switch语句是一个多分支结构的语句,它所实现的功能与if_elseif结构相似,但在大多数情况下,switch语句表达方式更直观、简单、有效。,2switch语句,语法形式:switch(表达式)case常量1:语句序列1;/由零个或多个语句组成break;case常量2:语句序列2;break;.default:/default是任选项,可以不出现语句序列n;break;,使用注意(1)switch语句表达式必须是整数类型,case常量必须与表达式类型兼容,case常量的值必须互异,不能有重复。(2)“不穿透”规则(3)可以有两个或多个case前缀指向相同的语句序列。,usingSystem;classStudentGradepublicstaticvoidMain()Console.Write(输入学生百分制的成绩:);intGrade=(int)Console.Read();switch(Grade/10)case9:case10:Console.WriteLine(你的成绩为:A);break;case8:Console.WriteLine(你的成绩为:B);break;case7:Console.WriteLine(你的成绩为:C);break;case6:Console.WriteLine(你的成绩为:D);break;default:Console.WriteLine(你的成绩为:E);break;,【例2.1】从键盘输入学生的百分制成绩,换算成等级制成绩,循环语句是指在一定条件下,重复执行一组语句,它是程序设计中的一个非常重要也是非常基本的方法。C#提供了4种循环语句:while、do_while、for和foreach。foreach语句主要用于遍历集合中的元素。,2.4.3循环语句,1while语句语法形式:while(条件表达式)循环体语句;如果条件表达式为真(true),则执行循环体语句。while语句执行流程如图2.11所示,图2.11while语句执行流程图,usingSystem;classStudentGradepublicstaticvoidMain()Console.Write(输入学生百分制的成绩:);intGrade=(int)Console.Read();switch(Grade/10)case9:case10:Console.WriteLine(你的成绩为:A);break;case8:Console.WriteLine(你的成绩为:B);break;case7:Console.WriteLine(你的成绩为:C);break;case6:Console.WriteLine(你的成绩为:D);break;default:Console.WriteLine(你的成绩为:E);break;,2do_while语句,语法形式:do循环体语句;while(条件表达式)该循环首先执行循环体语句,再判断条件表达式。如果条件表达式为真(true),则继续执行循环体语句。do_while循环语句执行流程如图2.12所示。,图2.12do_while语句执行流程图,usingSystem;publicclassSum100publicstaticvoidMain()intSum,i;Sum=0;i=1;doSum+=i;i+;while(i=100)Console.WriteLine(Sumis+Sum);while语句与do_while语句很相似,它们的区别在于while语句的循环体有可能一次也不执行,而do_while语句的循环体至少执行一次。,3for语句,语法形式:for(表达式1;表达式2;表达式3)循环体语句;一般情况下,表达式1是设置循环控制变量的初值;表达式2是布尔类型的表达式,作为循环控制条件;表达式3是设置循环控制变量的增值(正负皆可)。for语句执行流程如图2.13所示。,图2.13for语句执行流程图,usingSystem;publicclassSum100publicstaticvoidMain()intSum,i;Sum=0;for(i=1;i0;i)/i也可以每次减1Sum+=i;Console.WriteLine(Sumis+Sum);,usingSystem;publicclassSum100publicstaticvoidMain()intSum,i;for(Sum=0,i=1;i=100;i+)Sum+=i;Console.WriteLine(Sumis+Sum);for(Sum=0,i=1;i100)/这种情况一般都会用if语句来设置跳出循环break;Console.WriteLine(Sumis+Sum);,usingSystem;publicclassSum100publicstaticvoidMain()intSum=0;for(inti=1;i=100;i+)/i只在这个for循环中有效Sum+=i;Console.WriteLine(i=+i);/编译出错,i这时已经无效Console.WriteLine(Sumis+Sum);,(1)for循环语句,表达式1和表达式3可引入逗号运算符“,”,这样可以对若干变量赋初值或增值。(2)for循环的三个表达式可以任意默认,甚至全部默认,如果表达式2默认就约定它的值是true。但不管哪个表达式默认,其相应的分号“;”不能默认。(3)可在for循环内部声明循环控制变量。如果循环控制变量仅仅只在这个循环中用到,那么为了更有效地使用变量,也可在for循环的初始化部分(表达式1)声明该变量,当然这个变量的作用域在这个循环内。,for循环的一些变化特点:,跳转语句用于改变程序的执行流程,转移到指定之处。C#中有4种跳转语句:continue、break、return、goto语句。它们具有不同的含义,用于特定的上下文环境之中。,2.4.4跳转语句,1continue语句语法形式:continue;continue语句只能用于循环语句中,它的作用是结束本轮循环,不再执行余下的循环体语句,对while和do_while结构的循环,在continue执行之后,就立刻测试循环条件,以决定循环是否继续下去;对for结构循环,在continue执行之后,先求循环增量部分,然后再测试循环条件。,usingSystem;publicclassFactor3publicstaticvoidMain()for(intn=1;n=100;n+)if(n%3!=0)continue;/如果n不能被3整除,则直接进入下一轮循环Console.WriteLine(n);/只有能被3整除的数,才会执行到此,【例2.8】输出1100之间含有因子3的数。,2break语句,语法形式:break;break语句只能用于循环语句或switch语句中。如果在switch语句中执行到break语句,则立刻从switch语句中跳出,转到switch语句的下一条语句;如果在循环语句执行到break语句,则会导致循环立刻结束,跳转到循环语句的下一条语句。不管循环有多少层,break语句只能从包含它的最内层循环跳出一层。,例2.9】求1100之间的所有素数。usingSystem;publicclassPrimepublicstaticvoidMain()intm,k,n=0;for(m=2;m=m)Console.Write(0,4,m);if(+n%10=0)Console.WriteLine(n);,3return语句,语法形式:return;或return表达式;return语句出现在一个方法内。在方法中执行到return语句时,程序流程转到调用这个方法处。如果方法没有返回值(返回类型修饰为void),则使用“return”格式返回;如果方法有返回值,那么使用“return表达式”格式,其后面跟的表达式就是方法的返回值。,例2.9】求1100之间的所有素数。usingSystem;publicclassPrime100publicstaticboolprime(intm)for(inti=2;im;i+)if(m%i=0)returnfalse;/返回给调用者returntrue;publicstaticvoidMain()intm,k,n=1;Console.Write(0,4,2);for(m=3;m100;m+=2),4goto语句,语法形式:goto标号;其中,“标号”就是定位在某一语句之前的一个标识符,称为标号语句。语法形式:标号:语句;它给出goto语句转向的目标。值得注意的是,goto语句不能使控制转移到另一个语句块内部,更不能转到另一个函数内部。,另外,goto语句如果用在switch语句中,有如下形式。语法形式:gotocase常量;gotodefault;它只能在本switch语句中从一种情况转向另一种情况。【例2.11】用goto语句写“百钱百鸡问题”程序。公鸡5元一只,母鸡3元一只,小鸡1元三只,问100元钱可买公鸡、母鸡、小鸡各多少只?,usingSystem;publicclassChook100publicstaticvoidMain()intx,y,z;x=y=z=0;for(x=1;x=100/5;x+)for(y=1;y=100/3;y+)z=100xy;if(z%3=0,程序运行结果如下:,【例2.12】用break语句写“百钱百鸡问题”程序。公鸡5元一只,母鸡3元一只,小鸡1元三只,问100元钱可买公鸡、母鸡、小鸡各多少只?,usingSystem;publicclassChook100publicstaticvoidMain()intx,y,z;boolflag=false;x=y=z=0;for(x=1;x=100/5;x+)for(y=1;y=100/3;y+)z=100xy;if(z%3=0,usingSystem;classSchedulestaticvoidMain()Console.Write(输入一个06之间的数字代表星期日至星期六);intweek;stringsline;RepIn:sline=Console.ReadLine();week=int.Parse(sline);switch(week)case0:case6:Console.WriteLine(今天是周末,自行安排!);break;case1:Console.WriteLine(今天的课程是:哲学、英语、C#);break;,【例2.13】缩写课程表查询程序。,case2:Console.WriteLine(今天的课程是:数学、英语、体育);break;case3:Console.WriteLine(今天下午政治学习);gotocase1;case4:Console.WriteLine(今天的课程是:数学英语、C#);break;case5:Console.WriteLine(今天下午打扫卫生);gotocase2;default:Console.WriteLine(输入数据有错,请重新输入!);gotoRepIn;Console.Read();,程序运行结果如下:,数组是一种包含若干变量的数据结构,这些变量都具有相同的数据类型并且排列有序,因此可以用一个统一的数组名和下标唯一地确定数组中的元素。C#中的数组主要有三种形式:一维数组、多维数组和不规则数组。,2.5数组,2.5.1数组的定义1一维数组(1)一维数组的声明语法形式:typearrayName;其中:type可以是C#中任意的数据类型。表明后面的变量是一个数组类型,必须放在数组名之前。arrayName数组名,遵循标识符的命名规则。,2多维数组,(1)多维数组的声明语法形式:type,arrayName;多维数组就是指能用多个下标访问的数组。在声明时方括号内加逗号,就表明是多维数组,有n个逗号,就是n+1维数组。例如:int,score;/score是一个int类型的二维数组float,table;/table是一个float类型的三维数组,一维数组和多维数组都属于矩形数组,而C#所特有的不规则数组是数组的数组,在它的内部,每个数组的长度可以不同,就像一个锯齿形状。(1)不规则数组的声明语法形式:typearrayName;方括号的个数与数组的维数相关。例如:intjagged;/jagged是一个int类型的二维不规则数组(2)创建数组对象以二维不规则数组为例:,3不规则数组,在用new运算符生成数组实例时,若没有对数组元素初始化,则取它们的默认值。对数值型变量默认值为0,引用型变量默认值为null。当然数组也可以在创建时按照自己的需要进行初始化,需要注意的是,初始化时不论数组的维数是多少,都必须显式地初始化所有数组元素,不能进行部分初始化。,2.5.2数组的初始化,语法形式1:typearrayName=newtypesizeval1,val2,valn;数组声明与初始化同时进行时,size就是数组元素的个数,它必须是常量,而且应该与大括号内的数据个数一致。语法形式2:typearrayName=newtypeval1,val2,valn;默认size,由编译系统根据初始化表中的数据个数,自动计算数组的大小。语法形式3:typearrayName=val1,val2,valn;数组声明与初始化同时进行,还可以默认new运算符。语法形式4:typearrayName;arrayName=newtypesizeval1,val2,valn;把声明与初始化分开在不同的语句中进行时,size同样可以默认,也可以是一个变量。,1一维数组初始化,多维数组初始化是将每维数组元素设置的初始值放在各自的大花括号内,下面以最常用的二维数组为例来讨论。语法形式1:type,arrayName=newtypesize1,size2val11,val12,val1n,val21,val22,val2n,valm1,valm2,valmn;数组声明与初始化同时进行,数组元素的个数是size1*size2,数组的每一行分别用一个花括号括起来,每个花括号内的数据就是这一行的每一列元素的值,初始化时的赋值顺序按矩阵的“行”存储原则。语法形式2:typearrayName=newtype,val11,val12,val1n,val21,val22,val2n,valm1,valm2,valmn;默认size,由编译系统根据初始化表中花括号的个数确定行数,再根据内的数据确定列数,从而得出数组的大小。,2多维数组初始化,语法形式3:type,arrayName=val11,val12,val1n,val21,val22,val2n,valm1,valm2,valmn;数组声明与初始化同时进行,还可以默认new运算符。语法形式4:type,arrayName;arrayName=newtypesize1,size2val11,val12,val1n,val21,val22,val2n,valm1,valm2,valmn;把声明与初始化分开在不同的语句中时,size1、size2同样可以默认,但也可以是变量。例如:以下数组初始化实例都是等同的。int,a=newint3,40,1,2,3,4,5,6,7,8,9,10,11;int,a=newint,0,1,2,3,4,5,6,7,8,9,10,11;int,a=0,1,2,3,4,5,6,7,8,9,10,11;inta;a=newint3,40,1,2,3,4,5,6,7,8,9,10,11;,下面以二维不规则数组为例来讨论。不规则数组是一个数组的数组,所以它的初始化通常是分步骤进行的。语法形式:typearrayName=newtypesize;size可以是常量或变量,后面一个中括号是空着的,表示数组的元素还是数组且其中的每一个数组的长度是不一样的,需要单独使用new运算符生成。语法形式:arrayName0=newtypesize0val1,val2,valn1;arrayName1=newtypesize1val1,val2,valn2;例如:charst1=newchar3;/st1是由三个数组组成的数st10=newcharS,e,p,t,e,m,b,e,rst11=newcharO,c,t,o,b,e,rst12=newcharN,o,v,e,m,b,e,r;,3不规则数组初始化,一个数组具有初值时,就可以像其他变量一样被访问,既可以取数组元素的值,又可以修改数组元素的值。在C#中是通过数组名和数组元素的下标来引用数组元素的。1一维数组的引用语法形式:数组名下标下标数组元素的索引值,实际上就是要访问的那个数组元素在内存中的相对位移,记住,相对位移是从0开始的,所以下标的值从0到数组元素的个数1为止。,2.5.3数组元素的访问,usingSystem;classMaxMinpublicstaticvoidMain()intmax,min;intqueue=newint1089,78,65,52,90,92,73,85,91,95;max=min=queue0;for(inti=1;imax)max=queuei;if(queueimin)min=queuei;Console.WriteLine(最大数是0,最小数是1,max,min);,【例2.14】定义一个数组,存放一组数据,找出该组数中最大数和最小数。,语法形式:数组名下标1,下标2,下标n【例2.15】求两个矩阵的乘积。假定一个矩阵A为3行4列,另一个矩阵B为4行3列,根据矩阵乘法的规则,其乘积C为一个3行3列的矩阵。usingSystem;classmatrixpublicstaticvoidMain()inti,j,k;int,a=newint3,41,2,3,4,5,6,7,8,9,10,11,12;int,b=newint4,312,11,10,9,8,7,6,5,4,3,2,1;int,c=new3,3;for(i=0;i3;i+)for(j=0;j3;j+)for(k=0;k4;+k)ci,j+=ai,k*bk,j;for(i=0;i3;+i)for(j=0;j3;+j)Console.Write(0,4:d,ci,j);Console.WriteLine();,2多维数组的引用,语法形式:数组名下标1下标2下标n【例2.16】打印杨辉三角形。usingSystem;classYH_tripublicstaticvoidMain()inti,j,k,m;k=7;intY=newintk;/定义二维锯齿状数组Yfor(i=0;iY.Length;i+)/Y.Length返回的是Y数组的长度,7Yi=newinti+1;Yi0=1;Yii=1;for(i=2;iY.Length;i+)for(j=1;jYi.Length1;j+)/Yi.Length是Yi这个数组的长度Yij=Yi1j1+Yi1j;for(i=0;iY.Length;i+),3不规则数组的引用,for(j=0;jYi.Length;j+)Console.Write(0,5:d,Yij);Console.WriteLine();Console.Read();程序运行结果如下:,在C#中,System.Array类型是所有数组类型的抽象基类型,所有的数组类型均由它派生,这样设计的好处是任何数组都可以使用System.Array具有的属性及方法。例如,System.Array有一个Length属性,通过它可以获取数组的长度;它有一个GetLength(n)方法,用它可以得到第n维的数组长度(n从0开始)。程序中利用这个属性和方法,可以有效地防止数组下标越界。,2.5.4数组与System.Array,usingSystem;classmatrixpublicstaticvoidMain()inti,j,k;int,a=newint3,41,2,3,4,5,6,7,8,9,10,11,12;int,b=newint4,312,11,10,9,8,7,6,5,4,3,2,1;int,c=newint3,3;for(i=0;ic.GetLength(0);i+)/c.GetLength(0)是c数组第一维的长度for(j=0;jc.GetLength(1);j+)/c.GetLength(1)是c数组第二维的长度for(k=0;k4;+k)ci,j+=ai,k*bk,j;for(i=0;i3;+i),【例2.17】求两个矩阵的乘积。假定一个矩阵A为3行4列,另一个矩阵B为4行3列,根据矩阵乘法的规则,其乘积C为一个3行3列的矩阵。,for(j=0;j=60)passed+;Console.Write(0,4:d,x);Console.WriteLine(n及格率:0:P,(double)passed/score.Length);Console.Read();程序运行结果如下:,【例2.18】统计一组考试成绩中及格的人数并打印及格的分数,计算及格率,【例2.19】扑克牌游戏。用计算机模拟洗牌,分发给4个玩家并将4个玩家的牌显示出来。基本思路:用一维数组Card存放52张牌(不考虑大、小王),二维数组Player存放4个玩家的牌。用三位整数表示一张扑克牌,最高位表示牌的种类,后两位表示牌号。例如:101,102,113分别表示红桃A,红桃2,红桃K。201,202,213分别表示方块A,方块2,方块K。301,302,313分别表示梅花A,梅花2,梅花K。401,402,413分别表示黑桃A,黑桃2,黑桃K。程序:usingSystem;classTestCardstaticvoidMain(stringargs)inti,j,temp;RandomRnd=newRandom();intk;intCard=newint52;int,Player=newint4,13;,2.6综合应用实例,for(i=0;i4;i+)/52张牌初始化for(j=0;j13;j+)Cardi*13+j=(i+1)*100+j+1;Console.Write(Howmanytimesforcard:);strings=Console.ReadLine();inttimes=Convert.ToInt32(s);for(j=1;j=times;j+)for(i=0;i52;i+)k=Rnd.Next(51i+1)+i;/产生i到52之间的随机数temp=Cardi;Cardi=Cardk;Cardk=temp;k=0;for(j=0;j13;j+)/52张牌分发给4个玩家for(i=0;i4;i+)Playeri,j=Cardk+;for(i=0;i4;i+)/显示4个玩家的牌Console.WriteLine(玩家0的牌:,i+1);for(j=0;j13;j+),k=(int)Playeri,j/100;/分离出牌的种类switch(k)case1:/红桃s=Convert.ToString(x0003);break;case2:/方块s=Convert.ToString(x0004);break;case3:/梅花s=Convert.ToString(x0005);break;case4:/黑桃s=Convert.ToString(x0006);break;,k=Playeri,j%100;/分离出牌号switch(k)case1:s=s+A;break;case11:s=s+J;break;case12:s=s+Q;break;case13:s=s+K;break;default:s=s+Convert.ToStrin
展开阅读全文