前文已经对CAPL中的运算符和程序是如何执行的进行了讲解,接着我们聊一下CAPL代码中的流程控制
目录
一、流程控制是什么
流程控制指的是代码执行顺序,其中有三种结构,分别是顺序结构、分支结构(又叫选择结构)、循环结构。
前文中出现的代码全部都是顺序结构,即在每一个代码块内部,代码按照行号的顺序,从上到下依次执行,在这里也不再进行赘述了。
二、分支结构(选择结构)流程
分支结构(选择结构)常用于代码的执行拥有多种情况时,用于满足不同的条件时,执行不同的代码。
1、if语句
if语句的作用在于,满足if的判断条件时,才执行if代码块中的代码。
其语法如下
if(判断条件)
{
满足条件后执行的代码;
}
on start
{
int a = 0;
if(a > 10)
{
write("a的值大于10");
}
write("a的值是%d",a);
}
我们定义一个变量a,并初始化为0,执行代码看看结果
可以看到,write窗口中只打印了a的值,并没有输出 “a的值大于10”这句话。
这就是if语句的作用,要满足if中的条件(a>10)才能执行{ }中的语句。
接着,我们修改一下a的初值,修改为一个大于10的值看看
on start
{
int a = 50;
if(a > 10)
{
write("a的值大于10");
}
write("a的值是%d",a);
}
当我们修改a的初值为50之后,因为50大于10,所以{ }中的代码被执行了。
2、if-else语句
if-else语句有些类似于上一篇文章所讲的三目运算符,它的作用的,当满足if的条件时,执行if中的语句,如果不满足,则执行else中语句。
其语法如下
if(条件)
{
满足后执行的语句;
}
else
{
不满足条件执行的语句;
}
接着我们看一下例子。
on start
{
int a = 5;
if(a > 10)
{
write("a的值大于10");
}
else
{
write("a的值小于等于10");
}
write("a的值是%d",a);
}
执行代码,看看现象。
这次的write窗口中打印了“a的值小于等于10”这句话
我们的变量a被初始化为5,随后判断5是否大于10?如果大于10,则执行if里的语句,显然,5是小于10的,所以if条件不成立,执行了else里面的程序。打印了”a的值小于等于10“这句话。
3、if-else if-else语句
if-else if-else语句是if-else的补充,且else if是没有数量限制的,可以不断地进行else if,适用于被判断的条件有多种可能的情况,而上文的if-else语句只能表示两种可能。
else if用于对上一个条件的否定,并且重新进行if
常用于以下情况:
如果条件a,不是条件a那么如果是条件b,不是条件a也不是条件b那么如果是条件c....直到else表示不是以上所有的情况
以下是它的语法
/*
三种情况下的写法
*/
if(条件a)
{
语句1;
}
else if(条件b)
{
语句2;
}
else
{
语句3;
}
/*
如果条件具有非常多的可能,可以多次使用else if继续进行条件枚举。
*/
if(条件a)
{
语句1;
}
else if(条件b)
{
语句2;
}
else if(条件c)
{
语句3;
}
else
{
语句4;
}
下面对这两种用于进行具体举例。
on start
{
int a = 6;
if(a > 10)
{
write("a的值大于10");
}
else if(a >5)
{
write("a大于5但小于等于10");
}
else
{
write("a的值不大于5");
}
write("a的值是%d",a);
}
看下代码执行的结果,write窗口打印了”a大于5但小于等于10“这句话
分析一下:首先我们定义并初始化了a为6
先判断a是否大于10,显然6是不大于10的,所以走到了else if这里,并进行判断,a是否大于5,显然,6大于5,所以代码就走进了else if的代码块中,执行了里面的语句,由于执行了else if,那么就没有else什么事了,因为上面的条件已经满足,就会结束这轮判断,就不会继续再判断其他的else if和else,也就不会再执行后面的else里面的语句了。
接着,我们继续看看多个else if的情况。
on start
{
int a = 4;
if(a > 10)
{
write("a的值大于10");
}
else if(a >5)
{
write("a大于5但小于等于10");
}
else if(a <3)
{
write("a的值小于3");
}
else
{
write("a是3或者4或者5");
}
write("a的值是%d",a);
}
运行代码
打印了“a是3或者4或者5”
我们定义的a初始化为4
第一次判断,a是否大于10,由于a是4所以不满足,所以走到了第一个else if判断,a是否大于5,由于a是4也不满足,于是继续走到第二个else if,a的值是否小于3,a是4显然不小于3,于是也不满足,程序就走到了else里面,执行了else里的代码,打印了”a是3或者4或者5“。
以上,就是if-else if-else的语法的基本使用。
4、switch case语句
switch case也是一种分支语句,常常用在被判断的条件可能的结果比较多的情况,其与if -else if-else语句,都可以用于判断多种情况,区别主要在于,如果使用if-else if....代码会一直往下判断,直到符合结果才停止判断。如果有20种情况,且被判断的结果是符合的最后一种情况,那么代码就会经过19次的判断才能停止下来并且执行代码,效率低。
而switch case语句则不同,它只在收到参数时进行一次判断,而后就根据收到的参数去在索引里面寻找对应的参数并执行里面的代码即可。
以下是它的语法
switch(变量)
{
case 结果1:
break;
case 结果2:
break;
case 结果3:
break;
default:
break;
}
/*在每一个case结束后加上break语句,即可在找到对应的索引并执行完毕后
就跳出switch的判断,不会再继续往下走其他的case
*/
/*
//default:
break;
这个语句不是语法中必须的,但为了防止出现未定义的情况,建议加上。
除非你能保证你的case中已经把所有可能的情况都已经列举了出来,否则一般建议加上default语句
如果没有将全部可能的情况列出来,也没有default语句,switch语句可能不会执行任何结果。
*/
on start
{
char aChar = '*';
int a=6,b=3;
int result;
switch(aChar)
{
case '+':
result = a+b;
break;
case '-':
result = a-b;
break;
case '*':
result = a*b;
break;
case '/':
result = a/b;
break;
case '%':
result = a%b;
break;
default:
write("收到的字符不是一个有效的运算符");
break;
}
write("result的结果是%d",result);
}
执行程序,可以看到,最后输出的result的结果是18。
由于我们定义的aChar这个字符为'*',随后进行aChar这个字符的判断,匹配上了case '*'这行语句
所以执行了result = a*b;得到的结果就是18。
我们重新修改以下aChar的初始值为字符‘/’,看下结果
打印出来了result的结果是2
6和3怎么能得到2呢?显然,执行的是6/3的语句。即执行的是case ' / ' :后面的语句
与我们的aChar的初始值'/'实现了对应。
最后,我们修改以下aChar为其他的字符 ' # '看看
由于'#'字符无法与代码中任何一个case 的值匹配上,所以执行了default下面的代码,即打印了”收到的字符不是一个有效的运算符“这句话,并且由于default中没有对result进行计算的操作,所以result仍旧是默认值0。
以上可以看出,switch case也是一种用判断的语句,它会根据switch( )括号里的变量,去与case后面的结果进行匹配,匹配成功则执行对应的case后面的语句,匹配失败则执行default的语句。
注意!!!!!
switch case语句中,在每一个case后面,如没有特殊需求,请都跟上break;语句用于结束switch的判断,否则代码会继续往后面的case中执行
以下是一个错误示范
on start
{
char aChar = '+';
int a=6,b=3;
int result;
switch(aChar)
{
case '+':
result = a+b;
write("1");
case '-':
result = a-b;
write("2");
case '*':
result = a*b;
write("3");
case '/':
result = a/b;
write("4");
case '%':
result = a%b;
write("5");
default:
write("收到的字符不是一个有效的运算符");
write("6");
}
write("result的结果是%d",result);
}
在这段示范代码中,我删掉了每一个case中的用于跳出的break语句,我们来看看结果。
有些朋友可能会觉得很奇怪,明明初始化定义的aChar被定义为了'+'字符,为什么最后代码还是执行到了default里面,打印了不是一个有效的运算符?
这就是由于我删除了break语句造成了,如果switch case中的case语句最末尾没有break用于跳出判断的话,代码会在执行完case后,继续往下执行其他的case,直到最后一行代码执行完毕后结束switch语句。
所以,即使一开始我们的字符'+'就匹配成功,但由于没有break让其结束,它会继续执行下一个case中的代码,一直到switch case语句末尾。
从write窗口中打印了1-2-3-4-5-6也可以看出来,每一个case后面的语句都被执行了。
这种行为在编程中被称为case透穿,极其容易造成未定义的问题,代码的执行结果有可能会出错,为避免这种情况,请在每一个case条件结束后,加上break语句用于跳出判断!!!
三、循环结构
循环结构常用于在满足某些条件下,需要反复执行的代码。使用循环语法可以缩减代码量,精简代码。
1、while循环
while
循环是编程中常用的一种循环结构,它允许代码块根据给定的条件重复执行。只要条件为真(true),循环体内的代码就会不断执行。当条件变为假(false)时,循环结束,程序继续执行循环之后的代码。
以下是while循环的基本语法
while (条件) {
条件为真时重复执行的代码块;
}
on start
{
int i = 0;
while(i < 10)
{
write("你好世界);
i+=1;
}
}
执行代码,可以看到write窗口中打印了10句话。我定义了一个变量i并且初始化为0,当i<10的时候,我们就打印一次”你好世界“,并且每次执行完毕后给i的值进行了加一操作。
第一次执行循环时,i=0,i<10,所以打印了第一次,随后给i进行+1操作
第二次:i由于上一次进行了+1,所以这次i=1,i<10,所以打印第二次
第三次:i = 2,i <10,打印了第三次
......
第十次时,i = 9,i <10,打印了第十次
第十一次时,i = 10, i=10,并不小于10了,条件不成立,所以不执行循环体里面的代码了,也就不继续进行打印了。
所以我们的write窗口上只打印了十次”你好世界“。
怎么样?循环语句是不是十分方便
如果没有循环语句,我们要打印十次”你好世界“要怎么办?
只能是连着写十遍write了。
像这样
/*
没有循环语句的写法,代码会变得非常的长
*/
write("你好世界");
write("你好世界");
write("你好世界");
write("你好世界");
write("你好世界");
write("你好世界");
write("你好世界");
write("你好世界");
write("你好世界");
write("你好世界");
/*
循环语句写法,简介明了,使用三行代码就实现了原先需要十行才能实现的功能
*/
while(i < 10)
{
write("你好世界");
i+=1;
}
如果需要打印的次数比较少,十次二十次,采取复制的办法好像也没什么大不了的,就多写几行。但是如果要打印十几万次呢?就需要复制十几万行了,这样子的话这个代码已经不用看了,光是打印这句话就写了十几万行。
而循环语句就不一样了,如果要打印十万次,我们只需要把限定条件改为i<100000即可,高下立判。
细心的读者可能看到,我在while循环里面加了i+=1这句话,即每次循环完毕就让i的值加一,使得循环的次数被限定住了,不会一直循环下去。
如果要一直循环的话,怎么办呢?
很简单,只需要让循环的条件变成永远为真的即可。
比如
while(1)
{
}
前文我们讲过,1就是真,那么这样就表示永远为真了,循环体里面的语句会一直执行,在CAPL中通常不建议这么做,这样子会导致程序卡死,无法停止也无法关闭,只能强杀进程。为了避免这个情况,在CAPL中使用循环语句时,请为循环设置条件,并每次修改循环变量,避免死循环的产生!!
2、do while循环
do while循环和while循环一样,都是当满足条件时就会不停的循环,区别仅在于,while循环中的代码有可能一次都不会执行,而do while循环中的代码,至少会执行一次。
//while循环的写法,先判断再进行循环
while(条件)
{
语句;
}
// do while循环的写法,先执行一次循环体,执行完毕后再判断条件,如果为真则继续执行
do
{
语句;
}while(条件);
//从两种循环条件所放置的位置也能看得出来,
//while循环的循环条件放置再最开头,
//而do while循环的循环条件放置再最末尾
以下是一个do while循环的使用示例
on start
{
int i = 10;
do{
write("hello world");
i+=1;
}while(i < 10);
}
可以看到,打印了一次hello world
我定义的i初值就是10,10并不小于10,不满足循环体条件。
但由于do while循环的特性,即使是条件不满足,代码也会执行一次。
除了这个特性以外,while和do while在使用上几乎没有区别。
3、for循环
for
循环是编程中最常用且强大的循环结构之一,它允许你指定一个循环的开始条件、循环的结束条件以及循环体中每次迭代后需要执行的更新操作。for
循环非常适合当你需要遍历一系列值(如数组、列表、字符串等)或重复执行固定次数的操作时。
for循环的基本语法如下
for (初始化表达式; 循环条件表达式; 更新表达式) {
循环需要执行的语句;
}
/*
初始化表达式:在循环开始前执行,通常用于初始化一个或多个循环控制变量。
循环条件表达式:在每次循环开始前评估。如果条件为真(true),则执行循环体;如果条件为假(false),则退出循环。
更新表达式:在每次循环体执行完毕后执行,通常用于更新循环控制变量的值,以改变循环条件。
*/
- 初始化表达式:在循环开始前执行,通常用于初始化一个或多个循环控制变量。
- 循环条件表达式:在每次循环开始前评估。如果条件为真(true),则执行循环体;如果条件为假(false),则退出循环。
- 更新表达式:在每次循环体执行完毕后执行,通常用于更新循环控制变量的值,以改变循环条件。
以下是一个for循环使用的简单例子
on start
{
int i = 0;
for(i=0;i<5;i++)
{
write("hello world");
}
}
这个例子使用for循环实现打印五句hello world的功能
我们以i这个变量作为循环变量,以 i=0作为初始化表示式,即在这个循环中把i初始化为0,
以i < 5作为循环条件表达式 只要i < 5成立,就执行循环中的代码
以i++作为更新表达式,每次循环执行结束后,将循环变量更新。
四、嵌套结构
嵌套结构指的是在一个代码块内部再定义另一个或多个代码块的结构。这种结构在编程中非常常见,特别是在处理循环、条件判断、函数定义等复杂逻辑时。嵌套结构允许你将代码组织成更小的、更易于管理的部分,同时也使得程序能够执行更复杂的任务
由于嵌套结构可以由程序员进行自行组合,具有非常多非常多的形态,本文只进行几个简单举例
1、嵌套的分支结构
①if语句之间的嵌套
on start
{
int Grade = 85;//成绩
if(Grade >= 60)
{
write("这个成绩及格了");
if(Grade >= 90)
{
write("你的成绩非常优秀");
}
else if(Grade >= 80)
{
write("你的成绩较为良好");
}
else
{
write("虽然及格了,但成绩较为一般哦,继续努力吧!");
}
}
else
{
write("哎呀,你的成绩没有及格呢,要多加油了");
}
}
第一层if语句,用于判断成绩是否及格
如果成绩及格,那么第二层判断 再次判断这个成绩是优秀,还是良好,或者一般
随后再次修改一下成绩为58,运行程序看看结果
可以看到,当成绩小于60,即不满足第一层if的条件时,程序执行第一层else的结果。
②if与switch嵌套
on start
{
int Grade = 69;//成绩
int Subject = 2;//科目
enum SubjectCode{Chinese = 1,Math = 2,English = 3,Physics};//科目代号枚举
if(Grade >= 60)
{
switch(Subject)
{
case Chinese:
write("语文成绩及格了");
break;
case Math:
write("数学成绩及格了");
break;
case English:
write("英语成绩及格了");
break;
case Physics:
write("物理成绩及格了");
break;
default:
write("未知的科目");
break;
}
}
}
这个嵌套结构中,先判断成绩是否大于等于60,当条件满足后,再次判断是哪个科目,并根据对应的科目打印哪个科目及格。
2、嵌套的循环结构
嵌套的循环结构是编程中常用的一种结构,它指的是在一个循环体内再嵌套另一个循环结构。这种结构可以用于处理二维数组(如矩阵)、执行多重迭代任务(如遍历所有可能的组合)、或者进行更复杂的逻辑处理。
以下分别使用几种嵌套循环用于在write窗口实现一个9*9乘法口诀表。使用writeex打印则不会自动换行,然后在每一列打印完毕后使用write换行即可
①、嵌套while循环
on start
{
int i = 1,j = 1;//循环变量
while(i <= 9)
{
while(j <= 9)
{
writeEx(0,0,"%d * %d = %d ",i,j,i*j);
j++;
}
i++;
j = i;
write("");//换行
}
}
可以看到,write窗口上打印了乘法口诀表。
②、do while嵌套
on start
{
int i = 1,j = 1;//循环变量
do
{
do
{
writeEx(0,0,"%d * %d = %d ",i,j,i*j);
j++;
}while(j <= 9);
i++;
j = i;//让j=i,即可不重复打印之前已经算过的
write("");//使用write进行换行
}while(i <= 9);
}
③for循环嵌套
on start
{
int i = 1,j = 1;//循环变量
for(i = 1; i<= 9;i++)
{
for(j = i;j <= 9;j++)
{
writeEx(0,0,"%d * %d = %d ",i,j,i*j);
}
write("");//换行
}
}
④、其他嵌套循环
嵌套循环可以无限层次多层嵌套(虽然实际使用中不建议这么做),也就是说嵌套循环的结构是不定的,只需要在每个循环中遵守循环的语法即可,只要基础语法掌握了,不管嵌套多深,都是很一样的。可以while、do while、for互相嵌套都可以。
3、分支与循环嵌套
分支与循环嵌套是编程中非常常见的情况,可以用于处理一些复杂的逻辑,它的嵌套方式也是不固定的,可以在if、if-else、if-else if-else、switch case、while、do while、for这些语句中根据需要进行自定义的嵌套。
由于该类嵌套行为是由程序员根据需要自定义的,没法全部列举用以说明,以下仅作一个例子。
使用此类嵌套结构,计算1~50中所有偶数的平方和。
on start
{
byte Num;//定义字节型整数Num
qword Sum;//定义平方和
for(Num = 1;Num <= 50;Num++)//从1到50遍历
{
if(Num % 2 == 0)//如果Num对2取余为0,即Num可以整除2
{
Sum = Num * Num;//计算Num的平方并赋值给Sum
write("%d的平方是%d",Num,Sum);//打印结果
}
}
}