分享

第7章 程序控制结构

 昵称380475 2011-02-05
第7章 程序控制结构
 
  程序代码需要按一定的顺序执行,有时需要选择某一部分代码执行;有时需要反复执行某一段代码。通过程序结构控制代码可以完成这些功能。
  7.1 算法的概念及表示
  对于稍微复杂一点的应用程序,在开始编写代码之前,应该先设计其算法。本节首先简单地介绍一下算法和流程图方面的知识。
  7.1.1 算法简介
  使用计算机处理各种不同的问题时,必须事先对各类问题进行分析,确定解决问题的具体方法和步骤,再编写好一组让计算机执行的代码,交给计算机,让计算机按设计好的步骤进行工作。这些具体的方法和步骤其实就是解决一个问题的算法。根据算法,选择一种程序设计语言编写完成任务的代码,也就是编制程序。一个算法应该具有以下5个重要的特征。
  a、有穷性,一个算法必须保证执行有限步之后结束。
  b、确切性,算法的每一步骤必须有确切的定义。
  c、输入,一个算法有一个或多个输出,以反映对输入数据加工后的结果。算法是毫无意义的。
  d、可行性,算法原则上能够精确地运行,而且人们用笔和纸做有限次运算后也可完成。
  例如下面设计求三个数中最大数的算法。
  首先,定义三个A,B,C用来保存三个数,再定义一个变量MAX用来保存最大数。其算法如下:
  1)输入三个数分别保存到A,B,C中。
  2)将变量A与B进行比较,如果A大于B,则将A的值存入变量MAX中;否则将变量B的值存入变量MAX中。
  3)将变量C与MAX进行比较,如果C大于MAX,则将C的值存入变量MAX中。
  4)输出最大数MAX的值。
  使用相应的程序设计语言将以上步骤进行编码后,即可交给计算机进行运算处理了。
  7.1.2 流程图
  一般情况下,使用应用程序解决的问题都比较复杂,故大家喜欢用一种框图来描述算法,这样就可以把解决问题的思路更加清晰、形象、直观地表现出来,为下一步的程序编制打下基础。使用图形表示算法的思路是一种极好的方法,因为千言万语不如一张图。常用的流程图符号如图7-1所示。
       
  使用流程图描述上例的算法如图7-2所示。
  
  由图7-2可以看出,使用流程图比用文字描述算法更清晰明了。
  7.2 程序结构概述
  结构化程序设计的基本控制结构有三种:顺序结构、选择结构和循环结构。
  a、顺序结构:就是按照语句的书写顺序从上到下、逐条语句地执行。执行时,排在前面的代码先执行,排在后面的代码后执行,执行过程中没有任何分支。顺序结构是最普遍的结构形式,也是后面两种结构的基础。
  b、选择结构:又叫分支结构。是根据“条件”来选择执行哪一分支中的语句。包括二分支和多分支,以及分支的嵌套。
  c、循环结构:循环结构的程序设计比分支结构复杂。循环结构的思想是利用计算机高速处理运算的特性,重复执行某一部分代码,以完成大量有规则的重复运算。
  7.3 分支程序结构
  在日常生活中,常常需要对给定的条件进行分析、比较和判断,并根据判断结果采取不同的操作。在VBA的程序中对这种情况可通过分支结构程序来解决。利用分支结构使VBA能对数据进行判断,然后选择需要的分支进行处理,从而使系统具有了智能功能。
  7.3.1 If……Then语句
  要在VBA中做出判断,最简单的方法是使用“If……Then”语句。用“If……Then”结构有条件地执行一个或多个语句有两种语法形式。
  1.单行结构条件语句                                                    
  单行结构条件语句是最基本的条件语句,其语法为:                                                                               
  If 逻辑表达式 Then 语句                                                   
   逻辑表达式也可以是任何计算数值的表达式,VBA将这个值解释为True或False: 为零的数值为False,而任何非零数值都被看作True。                                                                      
  该语句的功能为:若逻辑表达式的值是Ture,则执行Then后的语句;若逻辑表达式的值是False,则不执行Then后的语句,而执行下一条语句。其流程图如图7-3所示。
                          
  例如,要删除工作表中的空行,首先检查当前单元格是否为空,如果为空,则删除当前单元格所在的行。
  If ActiveCell = "" Then Selection.EntireRow.Delete
  执行以上语句分两种情况:第一种情况是活动单元格为空,则执行Then后面的语句并删除当前行,然后执行If语句后面的语句;第二种情况是活动单元格不为空,则不执行Then后面的语句,而直接执行If语句后面的语句。
  2.块结构条件语句                
  在“If……Then”语句中,如果条件成立时需要执行多个操作,可将多个语句写在Then后面,并用冒号(:)分隔。“If……Then”语句还提供另外一种块结构的方法,可使执行多行代码的过程更清晰,其语法如下:
  If 逻辑表达式 Then
    语句1
    语句2
    ……
  End If
  块结构条件语句的作用与单行结构条件语句的功能相同。要注意的是“If……Then”的单行格式不用“End If”语句,而块语句则必须在条件语句的结束处有“End If”。例如,如果当前工作表名称为“基础资料”,则向其中添加表头数据:
  If ActiveSheet.Name = "基础资料" Then
            Range("A1") = "姓名"
   Range("B1") = "性别"
   Range("C1") = "住址" 
       End If 
  7.3.2 If……Then……Else语句
  在“If……Then”语句中,当条件为False时,不执行任何语句。若要求在条件为False时执行另一段代码,可用“If……Then……Else”语句完成。“If……Then……Else”语句也有两种格式:单行和多行。单行的格式为:
  If 逻辑表达式 Then 语句1 Else 语句2
  当“逻辑表达式”的值为True时,执行关键字Then后面的“语句1”;当“逻辑表达式”的值为False时,执行关键字Else后面的“语句2”。
  多行条件语句将根据条件表达式的值来判断并执行其中一个语句块。语法格式如下:
  If 逻辑表达式 Then
    语句序列1
  Else
    语句序列2
  End If
  VBA判断“逻辑表达式”的值如果为True,执行“语句序列1”中的各条语句;如果“逻辑表达式”的值为False时,就执行“语句序列2”中的各条语句。其流程图如图7-4所示。
   
  例如,下面的程序用于判断单元格“A1”的值:如果为空,则在该单元格中写入数据“10”,否则将单元格中的值增加10。
  If IsEmpty(Range("A1")) Then
            Range("A1") = 10
        Else
            Range("A1") = Range("A1") + 10
        End If
  7.3.3  IIf函数
  IIf函数可用来执行简单的条件判断操作,它是“If……Then……Else”结构的简写版本,其语法格式如下:
  .result=IIf(逻辑条件表达式,true部分,false部分)
  变量result保存函数的返回值。“逻辑条件表达式”为判断的条件,当条件为True时,IIf函数返回“true部分”;当条件为False时,IIf函数返回“false部分”。
  例如,有以下的If……Then……Else语句:
  If a>10 Then
               b = 1
       Else
              b = 2
       End If
  可改写为IIF函数样式:
  b = IIf(a > 10, 1, 2)
  技巧:“true部分”和“false部分”可以是表达式、变量或其他IIf函数。
  7.3.4 If……Then……ElseIf语句
  在很多情况下,可能需要判断几个不同的条件,并根据不同条件执行不同的语句。这时可使用“If……Then……ElseIf”语句来对多个不同条件进行判断,并在多个语句块中选择执行其中的一个,其语法格式如下:
  If 逻辑表达式1 Then
    语句序列1
  ElseIf 逻辑表达式2 Then
    语句序列2
  ElseIf 逻辑表达式3 Then
    语句序列3
    ……
  Else
    语句序列n
  End If
  在以上结构中,可以包括任意数量的ElseIf子句和条件,ElseIf子句总是出现在Else子句之前。
  VBA首先判断“逻辑表达式1”的值。如果它为False,再判断“逻辑表达式2”的值,以此类推,当找到一个为True的条件,就会执行相应的语句块,然后执行End If后面的代码。如果所有“逻辑表达式”都为False,且包含Else语句块,则执行Else语句块。其流程图如图7-5所示。
   
  例如,用以下代码对企业员工职务进行判断,根据不同的职务返回不同的职务工资标准:
  If Range("职务")="总经理" Then
    curPay = 1000
  ElseIf  Range("职务") = "副总经理"  Then
    curPay = 900
  ElseIf  Range("职务") = "厂长"  Then
    curPay = 800
  ElseIf  Range("职务") = "副厂长"  Then
    curPay = 700
  ElseIf  Range("职务") = "部门主任"  Then
    curPay = 500
  Else
    curPay = 0
  End If
  7.3.5 Select Case语句
  在“If……Then”分支语句中,问题可以添加更多的ElseIf块,但是,当每个ElseIf块都将相同的表达式与不同的数值比较时,这个结构编写起来很乏味,也不易阅读。在这种情况下可以用多分支选择结构“Select Case”语句。
  “Select Case”语句的功能与“If……Then……Else”语句类似,但对多重选择的情况,“Select Case”语句可使代码更加易读。
  “Select Case”在结构的开始处理一个测试表达式并只计算一次,然后,VBA将表达式的值与结构中的每个Case的值进行比较,如果相等,就执行与该Case相关联的语句块,执行完毕再跳转到End Select语句后执行。其语法格式如下:
  Select Case 测试表达式
   Case 表达式列表1
     语句序列1
   Case 表达式列表2
     语句序列2
     ……
   Case Else
     语句序列n
   End Select
  其中“测试表达式”可以是数值型或字符型的表达式,通常是一个数值型或字符型的变量。表达式列表可以是一个或几个值的列表。如果在一个列表中有多个值,就用逗号将各个值分隔开。每一个语句序列中含零个或多个语句。如果不止一个Case与测试表达式相匹配,则只对第一个匹配的Case执行与之相关联的语句块vkjs如果表达式列表中没有一个值与测试表达式相匹配,则VBA执行Case Else子句(此项可选)中的语句。其流程图如图7-6所示。表达式列表可以按以下几种情况进行书写。
  表达式:这种方式用来表达一些具体的取值。例如,Case1,3,5。
  表达式 A To表达式B:这种方式用来表示一个数据范围。例如,Case 1 To 10。
  Is比较运算符表达式。例如,Case Is<60表示所有小于60的值。
  以上三种情况的混合。例如,Case 0 To 60,80,Is>90
    
  注意:Select Case结构每次都要在开始处计算表达式的值;If……Then……Else结构为每个ElseIf语句计算不同的表达式。只有当If语句和每一个ElseIf语句计算的表达式相同时,才能用Select Case结构替换If……Then……Else结构。
  例如,将上例中使用“If……Then……ElseIf”语句编写的程序改写为以下形式:
  Select Case Range("职务")
   Case "总经理"
    curPay = 1000
   Case "副总经理"
    curPay = 900
   Case "厂长"
    curPay = 800
   Case "副厂长"
    curPay = 700
   Case "部门主任"
    curPay = 500
   Case Else
    curPay = 0
  End Select
  在Select Case语句中,可以使用Is关键字后面加上比较运算符来对某一个区间进行判断。例如用以下代码计算个人所得税,其中个人所得税的税率如图7-7所示。
  
  Function 计算个人所得税(curPay As Currency)
    Dim curTemp As Currency
                Dim CurPay1 As Currency
    curPay1 = curPay - 1600
    Select Case curPay
     Case Is <= 500
       curTemp = curPay1*0.05
     Case Is <= 2000
       curTemp = (curPay1-500)*0.1+25
     Case Is <= 5000
       curTemp = (curPay1-2000)*0.15+125
     Case Is <= 20000
       curTemp = (curPay1-5000)*0.2+375
     Case Is <= 40000
       curTemp = (curPay1-20000)*0.25+1375
     Case Is <60000
       curTemp = (curPay1-40000)*0.3+3375
     Case Is <80000
       curTemp = (curPay1-60000)*0.35+6375 
     Case Is <100000
       curTemp = (curPay1-60000)*0.4+10375 
     Case Else
       curTemp = (curPay1-100000)*0.45+15375
     End Select
     计算个人所得税 = curTemp
  End Function
  在使用Is关键字进行条件判断时,条件的先后顺序很重要。如本例中,若将Is<100000写在第一个条件位置,程序运行将得不到正确的结果。
  7.3.6 分支结构的嵌套
   在一个分支结构语句中还可以包含另一个分支结构语句,这称为嵌套。例如,以下程序用于判断当前单元格中保存值的类型:
  Sub 判断当前单元格数据类型()
    If IsEmpty(ActiveCell) Then                 '单元格为空
      MsgBox "当前单元格为空,请输入数据后再执行本程序!" 
     Else                             '单元格不为空
     If IsNumeric(ActiveCell.Value) Then             '单元格为数值
       If ActiveCell.Value = 0 Then              '数据为零
                                 ActiveCell.offset(0,1).Value = "零"
       ElseIf ActiveCell.Value > 0 Then                        '数据为正数
        ActiveCell.offset(0,1).Value = "正数"
       Else                           '数据为负数
        ActiveCell.offset(0,1).Value = "负数"
       End If
     Else                             '数据不为数值,则为文本
       ActiveCell.offset(0,1).Validation = "文本"
                           End If
                      End If
  End Sub
  这段代码使用了If语句的嵌套结构,嵌套的层次最多为三层。程序代码的功能在代码后面的注释中都进行了说明,其流程图如图7-8所示。
   
  注意:在块If语句的嵌套中,每一个If语句都需要一个End If语句与之对应,在输入代码时最好采用缩进结构,以便于看清楚嵌套的层次,防止少写End If语句。
  7.4 循环程序结构
  前面介绍了使用分支结构让VBA程序具有判断能力,从而使程序实现一定的智能化。但是这种分支结构的程序都是从代码的开始处按顺序执行,只是路途跳过一些语句不执行。
  在实际需要中,有时还需要反复操作某一个或几个动作。如果将这种操作编写成VBA代码来完成,则表示程序运行到一个位置后,又返回前面的代码来进行操作,这种结构称为循环结构。VBA中提供了多种循环结构控制语句。
  7.4.1 Do……Loop循环
  用Do循环重复执行一语句块,且重复次数不定。“Do……Loop”语句有4种演变形式,但每种都需要计算条件表达式的值,以决定是否继续执行。在Do循环中可以使用“Exit Do”语句中途退出该循环。
  1. Do While……Loop循环
  “Do While”语句属于先测试循环条件的“Do……Loop”语句,其语法格式如下:
  Do While 逻辑表达式
    语句序列1
    [Exit Do]
    [语句序列2]
  Loop
  其中Do While和Loop都是关键字,在Do While和Loop之间的语句称为循环体。
  当VBA执行这个Do循环时,首先判断逻辑表达式:如果为False(或零),则跳过所有语句,执行Loop的下一条语句:如果为True(或非零),则执行循环体,当执行到Loop语句后,又跳回到Do While语句再次判断条件。在循环体中如果包含有Exit Do语句,当执行到Exit Do语句,马上跳出循环,执行Loop的下一条语句。其流程图如图7-9所示。
    
 
  这种形式的循环体可能执行零次或多次。只要条件表达式为True或非零,循环就会重复执行。如果逻辑表达式最初就为False,则不会执行循环语句。
  2. Do……Loop While循环
   “Do……Loop While”语句属于后测试循环条件的“Do……Loop”语句,该结构先执行循环体中的语句,然后再进行条件判断。这种形式的循环体至少执行一次,其语法格式如下:
  Do
   语句序列1
   [Exit Do]
   [语句序列2]
  Loop While 逻辑表达式
  其流程图7-10所示。
  3. Do Until……Loop循环
  该语句为先测试结束条件的“Do……Loop”语句,其语法形式如下:
  Do Until 逻辑表达式
    语句序列1
    [Exit Do]
    [语句序列2]
  Loop
  这种形式与“Do While……Loop”类似,不同的是当逻辑表达式的值为False时才执行循环体,否则退出循环。这种形式的循环体可能执行零次或多次。
  4.Do……Loop Until循环
   这是后测试结束条件的“Do……Loop”语句,其语法形式如下:
  Do
   语句序列1
   [Exit Do]
   [语句序列2]
  Loop Until 逻辑表达式
  这种形式与“Do……Loop While”类似,不同的是当逻辑表达式的值为False时才执行循环体,否则退出循环。这种形式的循环体至少能被执行一次。
  例如,在要求用户输入密码时,一般都要给用户三次机会,每次的输入过程和判断过程都相同,这时就可以使用循环语句。
  Sub 输入密码()
   Dim strPassword As String                                                            '保存密码
   Dim i As Integer                   '输入密码的次数
   Do
                  strPasswor = InputBox("请输入密码")                                 '输入密码
                  If strPassword = "wyh" Then                                                     '判断密码是否正确
     Exit Do                                                                                   '退出循环
     Else
                       MsgBox("请输入正确的密码!")
                  End If
                   i = i + 1
                 Loop While i < 3
                 If i >= 3 Then                                                                             '超过正常输入密码次数
                    MsgBox "未登录用户"
                    End
    Else
                     MsgBox "欢迎你使用本系统!"
                End If
       End Sub
  程序中使用“Do……Loop While”循环让循环体至少执行一次。程序的流程图如图7-11所示。
       
 
  在循环体中,首先是显示一个输入框让用户输入密码;接着对用户输入的密码进行判断,如果密码正确,则执行Exit Do语句退出循环,执行Loop While下面的语句,如果密码错误,将显示一个提示信息,并累计错误次数;最后判断是否继续循环。
  7.4.2 While……Wend循环
  “While……Wend”循环语句的功能与“Do……While”循环相同,是从Basic的早期版本中保留下来的语句,VBA保留它是为了向后兼容,其语法格式如下:
  While 逻辑表达式
    循环体
    ……
  Wend
  如果“逻辑表达式”为True,则所有的“循环体”语句都会执行,一直执行到Wend语句,然后再回到While语句,并再一次检查“逻辑表达式”的值,如果还是为True,则重复执行;如果不为True,则程序会从Wend语句之后的语句继续执行。
  7.4.3 For……Next循环
  “For……Next”语句以指定次数来重复执行循环体。与Do循环不同,For循环使用一个叫做计数器的变量,每重复一次循环之后,计数器变量的值就会增加或减少。在For循环中可以使用Exit For语句随时退出该循环。For循环的语法格式如下:
  For 循环变量=初始值 To 终值 [Step 步长值]
    语句序列1
    [Exit For]
    语句序列2
  Next [循环变量]
  其中:步长值可正可负。如果步长值为正,则初始值必须小于或等于终值才能执行循环体,否则退出循环;如果步长值为负,则初始值必须大于或等于终值,这样才能执行循环体。如果没能设置Step,则步长值默认为1。“For……Next”循环结构的流程图如图7-12所示。
    
  VBA执行For循环时的过程如下:
  步骤1 将初始值赋值给循环变量。
  步骤2 判断循环变量是否超过终值,若为真(True),退出循环,执行Next的下一语句。这里的“超过终值”有两种意思:若步长值为负数时,超过就是循环变量的值小于终值;而当步长值为正数时,超过就是循环变量的值大于终值。
  步骤3 执行循环体。
  步骤4 循环体执行完后到达Next语句时,循环变量累加上步长值。
  步骤5 重复步骤2到步骤4。
  For循环一般都可计算出循环体的执行次数,计算公式如下:
  循环次数=【(终值-初值)/步长值】+1
  这里用中括号表示取整。
  在事先不知道循环体需要执行多少次时,应该用Do循环;而在知道循环体要执行的次数时,最好使用“For……Next”循环。
  例如,要编写代码完成以下工作:在工作表“Sheet2”的前100行中,如果第2列单元格的值为0,则删除所在行。可使用“For……Next”循环语句编写如下代码:
  Sub 使用 For 循环删除为0的行()
    Dim i As Integer
    With Sheets("sheet2")
                      For i = 1 To 100
                           If .Cells(i,2).EntireRow.Delete
           End If
       Next
    End With
  End Sub
  比较两个过程可以看出,使用“For……Next”循环时,不需要开发人员手工编写代码更新循环变量,而使用“Do While……Loop”循环时,必须在循环体中包含更改循环条件的语句,否则循环将一直执行下去,永远退不出来,形成死循环。
  7.4.4 循环的嵌套
  与分支结构类似,循环结构也可进行嵌套,即将一个循环放置在另一个循环中。VBA允许在同一过程里嵌套多种类型的循环。
  在编写嵌套循环程序的代码时一定要注意每个循环语句的配对情况。如图7-13所示,其中(a)是正确的嵌套关系,第一个Next关闭了内层的For循环,而最后一个Loop关闭了外层的Do循环。同样,在嵌套的If语句中,End If语句自动与最靠近的前一个If语句配对。嵌套的Do……Loop结构的工作方式也是一样的,最内圈的Loop语句与最内圈的Do语句匹配。图7-13(b)则是错误的嵌套关系。
     
  第4章中编写的九九乘法表就使用了两个For循环进行嵌套,其代码如下:
  Private Sub cmd99_Click()
   Dim i As Integer
   Dim j As Integer
   Dim StrMsg As String
   For i = 1 To 9
         For j = 1 To 9
      strMsg = strMsg & "*" & j & "=" & i * j & ""
     Next j
     strMsg = strMsg & vbCrLf
   Next i
            MsgBox strMsg , , "九九乘法表"
  End Sub
  分析嵌套循环时,可从最内层的循环开始。以上代码最内层循环的语句为:
  For j= 1 To 9
    strMsg = strMsg & i & "*" & j & "=" & i * j & " "
  Next j
  这部分代码用来生成一行数据,假设i为1,执行完以上代码后,变量strMsg保存的内容如下:
  1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
  将内循环精简为一个命令(如本例中的“输出一行数据”),则九九乘法表的程序变为以下形式:
  Private Sub cmd99_Click()
   Dim i As Integer
   Dim j As Integer
   Dim strMsg As String
   For i = 1 To 9
     输出一行数据
     strMsg = strMsg & vbCrLf
   Next i
   MsgBox strMsg, , "九九乘法表"
  End Sub
  即可得到一个单循环。该单循环执行9次即可得到9行数据,也就得到了需要的乘法表。
  注意:在嵌套结构里的循环结构中使用Exit语句时,退出的只是包含该语句的当前循环结构,而不是整个黄磊结构。
  7.4.5 Goto语句
  使用Goto语句,可无条件地将程序代码跳转到指定的行去执行。VBA中保留Goto语句是为了保持与早期的Basic版本兼容。Goto语句的语法格式如下:
  Goto 行号/标号
  注意:Goto只能跑到它所在过程中的行。
  要使用Goto语句,首先需用了解VBA中语句的行号和标号。在早期的Basic语言中,每一行程序都有一个行号,行号按从小到大的顺序排列,例如:
  Sub 使用Do循环删除为0的行()
  10 Dim i As Integer
  20 i = 1
        30   With Sheets("sheet2")
  40 Do While i <= 100
  50      If .Cells(i,2) = 0 Then
  60            .Cells(i,2).EntireRow.Delete
  70  End If
  80  i = i + 1
  90 Loop
  100 End With
  End Sub
  在VBA中,执行这样的代码也不会出错。为程序添加行号的目的就是方便使用Goto语句跳转到相应的语句去执行。
  随着结构化程序设计方法的使用,使用Goto语句跳转的方式已经不常用了,也就不再需要为每行代码添加行号了。
  为了使Goto跳转到需要的地方,可在程序中添加标号。标号是以英文字母开头的一个标识符后加上一个冒号构成的。在程序代码中输入的标号始终是靠左对齐的。
  例如,以下代码使用Goto语句来进行循环操作,删除单元格为0的行。
  Sub 使用Goto语句删除为0的行()
    Dim i As Integer
    i = 1
  linel:
   With Sheets("sheet2")
    If .Cells(i,2) = 0 Then
      .Cells(i,2).EntireRow.Delete
    End If
    i = i + 1
    If i <= 100 Then GoTo linel
   End With
  End Sub
  注意:这里只是演示Goto语句的用法,不建议读者在程序中使用太多的Goto语句,因为使用Goto语句会使程序代码不容易阅读及调试。应尽可能使用结构化控制语句(Do……Loop,For……Next,If……Then……Else和Select Case)。
 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多