本博客中的源代码由于电脑系统问题,均未编译调试过,都是按照《C#从入门到项目实践》一书人工敲上去的(为了练手速),待重装完系统安装了软件之后,立马马上调试修改。
顺序结构是程序代码中最基本的结构,是指程序中的所有语句都是按书写顺序逐一执行的,代码从main()函数开始运行,从上到下,一行一行地执行,不漏掉代码。
分支选择语句可以根据条件是否满足或者根据表达式的值,来控制代码的执行流程。C#有两种控制代码分支的结构,分别是if语句和switch语句。
一个if语句的条件可以是布尔变量,也可以是表达式,但如果是表达式,则得到的结果必须是布尔值。
1.单选择if语句
if语句的语法格式如下:
如果布尔表达式为true,则if语句内的代码块将被执行。如果布尔表达式为false,则if语句结束后的第一组代码将被执行。
2.if…else语句
一个if语句后可以跟一个else语句。当布尔表达式为假,才会执行else后面的语句。
if…else的语法格式如下:
if(布尔表达式) { /*如果布尔表达式为真执行的语句*/ } else { /*如果布尔表达式为假执行的语句*/ }
如果布尔表达式为true,则执行if块内的代码;如果布尔表达式为false,则执行else块内的代码。在前面的章节中讲解了条件运算符(?:
),可以用来替代if…else
语句。
它的一般形式如下:
<表达式> ? <resultIfTrue> : <resuletIfFalse>
其中,计算表达式可得到一个布尔值,运算符的结果根据这个值来确定是,还是。
例如:
int a = 8; string b = (a < 10) "小于10" : "大于10";
该段代码表示,如果变量a小于10条件成立,就将字符串“小于10”赋予变量b,否则就将字符串“大于10”赋予变量b。这里需要注意冒号的使用和位置。
3.if…else if…else 语句
一个if语句后可跟一个可选的else if…else语句。该语句用于执行多种条件。
语法格式如下:
if(布尔表达式1) { /*当布尔表达式 1 为真时执行*/ } else if(布尔表达式2) { /*当布尔表达式 2 为真时执行*/ } else if(布尔表达式3) { /*当布尔表达式 3 为真时执行*/ } else { /*当上面的条件都不为真时执行*/ }
在使用if…else if…else语句时,需要注意以下几点。
(1)一个if后可跟零个或一个else,它必须在任何一个else if之后。
(2)一个if后可跟零个或多个else if,它们必须在else之前。
(3)if语句是自上而下执行,只要有一个条件成立就不会去判断其他任何条件。
其中,else if语句的个数不受限制,但是如果else if语句的个数较多,则应该考虑另一种分支结构:switch语句。
4.嵌套if语句
在C#中,嵌套if…else语句是合法的,这意味着用户可以在一个if或else if语句内使用另一个if或else if语句。
C#中嵌套if语句的语法格式如下:
if(布尔表达式1) { /*当布尔表达式 1 为真时执行*/ if(布尔表达式2) { /*当布尔表达式 2 为真时执行*/ } }
也可以嵌套else if…else语句,该方式与嵌套if语句相似。
一个switch语句允许测试一个变量等于多个值时的情况。每个值称为一个case,且被测试的变量会对每个case进行检查。
switch语句的语法格式如下:
switch(控制表达式) { case 测试值1: 当控制表达式的值等于测试值1时的执行代码; break; case 测试值2: 当控制表达式的值等于测试值2时的执行代码; break; case 测试值3: 当控制表达式的值等于测试值3时的执行代码; break; .../*用户可以有任意数量的case语句*/ case 测试值n: 当控制表达式的值等于测试值n时的执行代码; break; default: 当控制表达式的值不等于以上任何测试值时的执行代码; break; }
在switch语句的开始,首先计算控制表达式的值,如果该值符合某个case语句中指定的“测试值”,就跳转到该case内的语句执行;当控制表达式的值没有任何匹配的“测试值”时,则执行default内的代码,执行完后退出switch语句,继续执行下面的代码。其中,测试值只能是某个整数类型或字符类型,并且各个测试值不能相同。default是可选的,没有default语句时,如果控制表达式的值不等于任何“测试值”,程序一样会退出switch而执行后面的代码。
用户可以把一个switch语句嵌套在另一个switch语句内。即使内部和外部switch的case常量包含共同的值,也是没有矛盾的。
例如:
int a = 1; int b = 2; switch (a) { case 1: Console.WriteLine("此处a是外部switch的一部分"); switch(b) { case 1: Console.WriteLine("此处b是内部switch的一部分"); break; case 2: /*内部 b case 代码*/ break; } case 2: /*外部 b case 代码*/ break; }
switch语句是非常有用的,但是在使用时必须谨慎。所写的任何switch语句都必须遵循以下规则。
(1)只能针对基本数据类型使用switch,这些类型包括int和string等。对于其他类型,则必须使用if语句。
(2)case标签必须是常量表达式,如37或者“37”。如果需要在运行时计算case标签的值,必须使用if语句。
(3)case标签必须是唯一性的表达式;也就是说,不允许两个case具有相同的值。
(4)可以连续写下一系列case标签(中间不能间插额外的语句),从而指定自己希望在多种情况下都运行相同的语句。如果像这样写,那么最后一个case标签之后的代码将适用于所有case。然而,假如一个标签关联了一条或多条语句,又没有使用break语句跳出,那么执行就不能贯穿到后续的标签,而且编译器会报告一个错误。
例如:
int a = 2; int x, y, z; switch (a) { case 1: case 2: //允许贯穿————标签之间无额外代码 case 3: Console.WriteLine("1 或者 2 或者 3"); //针对1、2和3这三种情况都会执行的代码 x = a; Console.WriteLine("x={0}",x); break; case 4: y = a; case 5: //出错————标签之间有额外代码,而且没有使用break跳出 z = a; break; }
注意:由于C#存在不准贯穿的规则,所以需要一条跳转语句来阻止贯穿,而break语句则是最常见的方式,但是也可以用一条return语句或者一条throw语句来替代它。
一般情况下,语句是顺序执行的,函数中的第一条语句先执行,接着是第二条语句,以此类推。在C#中提供了允许重复执行同一代码块的循环语句,有while语句、do…while语句、for语句和foreach语句。
只要给定的条件为真,C#中的while循环语句会重复执行一条目标语句。
while循环语句的语法格式如下:
while(表达式) { 语句或语句块; }
while循环是先判断表达式的值,然后再执行语句或语句块,直到表达式的值为false。如果循环刚开始表达式的值就为false,那么语句或语句块就不会被执行。
使用while语句时要注意以下几点。
(1)while语句中的表达式一般是关系表达式或逻辑表达式,只要表达式的值为真(非0)即可继续循环。
(2)循环体包含一条以上语句时,应用“{}”括起来,以复合语句的形式出现;否则,它只认为while后面的第1条语句是循环体。
(3)循环前,必须给循环控制变量赋初值,如int x=3;
。
(4)循环体中,必须有改变循环控制变量值的语句,如x++;
,否则循环永远不结束,形成所谓的死循环。
do…while循环与while循环类似,但是do…while循环会确保至少执行一次循环。
其语法格式如下:
do { 语句或语句块; }while (表达式);
do…while循环是先执行语句或语句块,然后再判断表达式的值,如果表达式的值为true,则继续执行循环,直到表达式的值为false。
注意:do…while循环刚执行的时候不管表达式的值为true或者是false它都要先执行一次语句或语句块,然后再来判断表达式的值。也就是说,如果一开始表达式的值为false,它也会执行一次循环。另外,while语句后面必须使用分号(;)。
使用do…while语句应注意以下几点。
(1)do…while语句是先执行“循环体语句”,后判断循环终止条件,与while语句不同。二者的区别在于:当while后面的表达式开始的值为0(假)时,while语句的循环体一次也不执行,而do…while语句的循环体至少要执行一次。
(2)在书写格式上,循环体部分要用“{}”括起来,即使只有一条语句也如此;do…while语句最后以分号结束。
(3)通常情况下,do…while语句是从后面控制表达式退出循环。但它也可以构成无限循环,此时要利用break语句或return语句直接从循环体内跳出循环。
一个for循环是一个允许用户编写执行特定次数的循环控制结构。在C#中,for循环的语法如下:
for(<初始化表达式>;<条件表达式>;<迭代表达式>) { 语句或语句块; }
初始化表达式:可以在该位置定义一个变量并为其赋一个初始值,也可以使用for循环前面定义的变量,但是使用for循环前面定义的变量必须在该位置为其重新赋一个初始值。
注意:在该位置定义一个变量并为其赋一个起始值,这种用法定义的变量的作用域仅在for循环语句中,也就是说,for循环语句后面的代码不能使用该变量;但是用for循环前面定义的变量这种用法定义的变量,在for循环语句后面的代码也能被使用。
条件表达式:如果条件表达式为真,则执行循环主体;如果为假,则不执行循环主体,且控制流会跳转到紧接着for循环的下一条语句。
迭代表达式:执行完语句或语句块后就执行迭代表达式,然后再执行条件表达式判断循环是否继续。
for循环语句中的3个表达式都是可以省略的,但“;”不能省略。
(1)省略<初始化表达式>,此时应在for语句之前给该变量赋初值。
(2)省略<条件表达式>,表示不判断循环条件,循环无终止地进行下去,也可以认为<条件表达式>始终为真。
该语句将无休止地执行循环体,一直输出变量x的值,成为死循环。为了终止循环,就要在循环体中加入break语句和return语句等。
(3)省略<迭代表达式>,此时应在循环体内部实现循环变量的增量,以保证循环能够正常结束。
相当于把<迭代表达式>写在了循环体内部,作为循环体的一部分。
(4)省略<初始化表达式>和<条件表达式>,此时只给出了循环条件。
相当于把<初始化表达式>放在了循环的外面,<条件表达式>作为循环体的一部分。这种情况与前面介绍的while语句完全相同。
(5)3个表达式都省略,既不设初值,也不判断条件,循环变量不增值,无终止地执行循环体。
注意:表达式可以省略,但中间的两个分号不能省略。
foreach循环用于列举出集合中所有的元素,foreach语句中的表达式由关键字in隔开的两个项组成。in右边的项是集合名,in左边的项是变量名,用来存放该集合中的每个元素。
foreach循环语句的语法格式如下:
foreach(类型 标识符 in 集合) { 循环代码; }
foreach语句括号中的类型和标识符用来声明该语句的循环变量,标识符即循环变量的名称。循环变量相当于一个只读的局部变量。在每一次循环时,都会从集合中取出一个新的元素值,放到只读变量中去,如果括号中的整个表达式返回值为true,foreach块中的语句就能够执行。一旦集合中的元素都已经被访问到,整个表达式的值为false,控制流程就转入到foreach块后面的执行语句。
注意:循环变量的类型必须与集合的类型相同。集合内元素的个数决定循环内程序段重复执行的次数。
例如:通过foreach循环找出字符数组中0和1的个数并输出。
using System; namespace Project { class Program { static void Main(string[] args) { int x = 0, y = 0; char[] ch = new char[] { '0', '1', '0', '1', '1', '1', '0', '0', '1', '0', '0' }; foreach (char a in ch) { if (a == '0') x++; else y++; } Console.WriteLine(ch); Console.WriteLine("0的个数为:{0}\n1的个数为:{1}", x, y); } } }
本例演示了foreach语句的使用。在代码中,首先初始化了两个变量x和y,分别用来表示0和1的个数;之后声明一个字符类型的数组,用foreach循环判断字符格式,如果遍历到0,则将x的值加1,否则就将b的值加1;最后输出x和y的值。
嵌套循环语句,是指一个循环结构的循环体内又包含另一个完整的循环结构。内嵌的循环中还可以嵌套循环,这样就构成了多层嵌套循环。
1.C#中嵌套for循环语句
2.C#中嵌套while循环语句
3.C#中嵌套do…while循环语句
例如:接收用户输入的一个正整数,然后程序会计算这个数的阶乘并输出,接着用户可以再输入另一个整数计算它的阶乘,直到输入一个负数时,程序终止。
using System; namespace Project { class Program { static void Main(string[] args) { int x = 0; do { Console.WriteLine("输入一个整数:"); x = int.Parse(Console.ReadLine()); long y = 1; for (int i = 1; i <= x; i++) { y *=i; } Console.WriteLine(y); }while (x >= 0); } } }
本例演示了循环嵌套语句的使用。在代码中,变量x接收用户输入的数值,变量y通过嵌套的for循环计算用户输入值的阶乘,直到输入一个负数为止。
C#中的跳转语句,可以使程序在执行过程中跳转到指定位置。跳转可以更改执行的正常序列。当执行离开一个范围时,所有在该范围中创建的自动对象都会被销毁。C#提供的跳转语句有break语句、continue语句和return语句。
C#中break语句有以下两种用法:
(1)当break语句用于do…while、for、while等循环语句中时,可使程序终止循环而执行循环后面的语句。通常break语句总是与if语句连在一起,即满足条件时便跳出循环。
(2)它可用于终止switch语句中的一个case。如果用户使用的是嵌套循环,break语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。
C#中的continue语句有点像break语句,但它不是强迫终止。continue会跳过当前循环中的代码,强迫开始下一次循环。
对于for循环,continue语句会导致执行条件测试和循环增量部分。对于while和do…while循环,continue语句会导致程序控制回到条件测试上。通常情况下,continue语句总是与if语句连在一起,用来加速循环。
例如:输出10~30所有不能被3和7同时整除的整数。
using System; namespace Project { class Program { static void Main(string[] args) { Console.WriteLine("10~30不能被3和7同时整除的数:"); int i, n = 0; /*n计数*/ for (i = 10; i <= 30; i++) { if (i & 3 == 0 && i & 7 == 0) /*如果能同时整除3和7,不打印*/ { continue; /*结束本次循环未执行的语句,继续下一次判断*/ } Console.Write("{0} ",i); n++; if (n % 10 == 0) /*10个数输出一行*/ Console.WriteLine('\n'); } } } }
本例演示了continue语句的使用。在代码中首先定义两个变量i和n,变量i作为循环变量,变量n用于计数。只有当i的值能同时被3和7整除时,才执行continue语句,执行后越过后面的语句,直接判断循环条件i<=30,再进行下一次循环。
return语句就是用于指定函数返回的值。return语句只能出现在函数体内,出现在代码中的其他任何地方都会造成语法错误。
return语句后面可以是常量、变量、表达式、方法,也可以什么都不加。一个方法中也可以出现多条return语句,但只有一条会执行。当return语句后面什么都不加时,返回的类型为void。
例如:
return 1; return a; return a+b; return Add(a+b); return;
goto是跳转到的意思,它的作用是当程序执行到goto语句时,程序会直接跳转到标识符所标识的程序位置,继续执行代码。
例如:
int i = 5; goto tab; i = 100; tab: Console.WriteLine(i); //标识符
本段代码的意思是,首先定义了一个变量i,然后跳转到标签为tab的语句,接下来就输出i的结果。可以看出第三条语句是无意义的,因为没有被执行,而直接跳到了标签位置。所以最后输出的值是5,而不是100。
goto跳转的语句,并不是一定要跳转到之后的语句。也就是说,goto还可以跳到前面去执行。
例如:
int i = 0; tab: Console.WriteLine(i); goto tab;
本段代码的意思是,首先定义变量i,然后执行标签tab输出变量i的值,最后再跳转到标签tab输出变量。因为每次输出i以后,都又跳转回到标签tab,所以程序会不停地输出i。
注意:goto语句的一个好处就是可以保证程序存在唯一的出口,避免了过于庞大的if嵌套。但是,在C#中还是建议少使用,因为它会使代码的易读性下降。
流程控制是程序的基本问题。通过流程控制,编程者可以完成业务逻辑和模块的整合等。在C#语言中,程序的基本结构分为顺序、循环、分支、跳转等,在编程的时候,通过判断、分支和循环来对程序的流程进行控制,很多程序在设计的时候也会做出流程图,以方便开发者更好地理解程序的流程,更准确地判断采取怎样的控制方式。
面试官:for循环语句的计算顺序是什么?
应聘者:for语句的执行顺序是先从左至右执行循环条件语句,如果循环条件语句的判断语句为true,则在循环条件语句执行之后继续执行一次循环执行语句,然后再回到循环条件语句。如果循环语句判断条件为false,则停止循环。
面试官:while循环与do…while循环有什么区别?
应聘者:while循环与do…while循环的主要区别在于,如果循环条件语句为false,while语句不会执行循环,而do…while保证循环体执行一次。
面试官:if语句中的条件表达式可以是任意合法的表达式吗?switch语句中break的作用是什么?
应聘者:可以是任意数值。在switch语句中,break语句可使流程立即跳出switch语句体不执行其他的case。
面试官:三种循环结构中的条件是循环进行的条件还是循环结束的条件?循环结构中,break语句和continue语句的作用是什么?二者有何区别?
应聘者:for语句、while语句是循环进行的条件;do…while语句是循环结束的条件。
循环结构中,break可用于switch语句,表示跳出整个switch块,而continue则不能用于switch语句。它们都可用于循环语句的循环体,break用于立即退出当前循环,而continue仅跳过当次循环,本次循环体内不执行continue语句后的其他语句,但下次循环还会执行。
面试官:C#中的跳转语句都有哪些?各自的作用是什么?
应聘者:C#中的跳转语句包括break、continue、goto、return和throw。这些语句可以及时、有效地跳转,将有助于提升程序的执行效率。其中,throw语句是用来处理程序异常,在后面章节会详细介绍。
跳转语句的说明如下:
break语句用于终止最近的封闭循环或它所在的switch语句。控制传递给终止语句后面的语句。
continue语句将控制权传递给它所在的封闭迭代语句的下一次迭代。
goto语句将程序控制直接传递给标记语句。goto的一个通常用法是将控制传递给特定的switch…case标签或switch语句中的默认标签。goto语句还用于跳出深嵌套循环。
return语句终止它出现在其中的方法的执行并将控制返回给调用方法。它还可以返回一个可选值。如果方法为void类型,则可以省略return语句。
throw语句用于发出在程序执行期间出现反常情况(异常)的信号。通常throw语句与try…catch或try…finally语句一起使用。当引发异常时,程序查找处理此异常的catch语句。也可以用throw语句重新引发已捕获的异常。