学习编程语言时总是避免不了遇到循环结构的使用,因为只有循环结构才能使我们的程序长久的运行下去。常见的循环结构主要有for 循环和while循环,对于这两种循环结构大家应该都非常的熟悉,并且在使用上应该也没有质疑。但是,当你进入C++的程序编写时,你还会遇到一个循环结构:Do...While...。
do...while..与while循环有一个明显的区别:while循环时先判断循环条件,只有满足循环条件之后才进入循环;而do...while...是先执行一次循环后,再判断是否满足循环条件。区分点很明晰,但是相信很多人在面对这两种循环时都是一种懵逼的状态——do...while...有个卵用?我为什么需要先执行一次循环再进入判断呢?还是用while循环吧,while循环都可以解决。
的确,当你单独对比两个循环结构时确实会感觉两种循环结构是等同的,几乎任何情况下均可以进行相互转换,因此好多人认为根本没有do...while...循环的场景,并且将此循环结构也就作为一种附属的存在。但果真如此吗?那C++发展了这么多年,为什么不把这个附属品去掉呢?
这个问题也困扰了我很长时间,尤其是想要找到一个合适的案例告诉学生需要在什么场景下使用do...while循环结构,可是找到每个应用场景都可以将其无缝的转入while循环中,并且毫无违和感。但是当你将while 和do...while...嵌入到内层循环时,也许你会发现一些不同之处。下面先看个例子吧~
while (True){
int a = 0;
int b = 2;
while (a > 1){
cout << b+2;
}
}
//这是一个最简单的循环嵌套结构,外层循环不断执行以维持整个程序的存活状态,内存循环会不断输出一个数值。然而在此种情况下,内层循环是永远不会执行的,因为a的值不满足大于1。那想要让内层循环执行该怎么办呢? //想要让内层循环执行必须让其条件满足,因此我们可以在内层循环外改变一下a的值,使其满足循环的条件。此时我们可以有几种方式改变循环条件a的值呢?
//方法一:
while (True){
int a = 2;
int b = 2;
while (a > 1){
cout << b+2;
}
}
//方法二:
while (True){
int a = 0;
int b = 2;
a = 2;
while (a > 1){
cout << b+2;
}
}
//方法三:
while (True){
int a = 0;
int b = 2;
while (a > 1){
cout << b+2;
}
a = 2;
}
//以上三种方法可以改变a的值,但是一定会有人说,你是不是傻,这是三种方法吗?明明一种方法呀。好,我们暂时先不考虑这是不是三种方法,但是起码我们可以达成一个共识,那就是必须要在内层循环的外边改变循环条件的值,这样才能进入内层循环。能达成共识的话,我们就继续往下~ //当前a只是一个我们虚拟的值,现在我们将其换成传感器的值,比如就是超声波传感器吧。因此,我们的程序需要修改下
//方法一:
while (True){
int a = read_Ultra();
int b = 2;
while (a > 1){
cout << b+2;
}
}
//方法二:
while (True){
int a = 0;
int b = 2;
a = read_Ultra();
while (a > 1){
cout << b+2;
}
}
//方法三:
while (True){
int a = 0;
int b = 2;
while (a > 1){
cout << b+2;
}
a = read_Ultra();
}
//现在来看,三种方法还是一样的吗?是不是起码可以区分出第一种和第二种方法了,在C++中还是比较推荐使用第二种方法吧。至于第三种方法还没区分出来,继续往下看吧。 //之前循环的条件a是一个无意义的值,但是修改为传感器的值那就不同了,a的值具有实际意义,并且是随时发生改变的,因此内层循环应该是可以跳出的。然而我们的程序可以跳出内层循环吗?肯定是不可以的,因为在循环的内部并没有再次读取传感器的值,因此a的值不再发生变化,自然会一直处于循环的状态。所以,想要让其可以在不满足条件的情况下可以跳出循环,我们还需要在循环的内部增加一条语句用来读取超声波传感器的值。
//方法一:
while (True){
int a = read_Ultra();
int b = 2;
while (a > 1){
cout << b+2;
a = read_Ultra();
}
}
//方法二:
while (True){
int a = 0;
int b = 2;
a = read_Ultra();
while (a > 1){
cout << b+2;
a = read_Ultra();
}
}
//方法三:
while (True){
int a = 0;
int b = 2;
while (a > 1){
cout << b+2;
a = read_Ultra();
}
a = read_Ultra();
}
//现在我们基本上已经完全将一个实际生活中通过判断距离而执行一些动作的逻辑了,并且你肯定会问,不是说将while与do...while...的区别吗?现在可以开始引入do...while...,那如果将上面的结构修改成do...while...你会怎么做呢?思考一下
//do...while...实现
while (True){
int a ;
int b = 2;
do{
cout << b+2;
a = read_Ultra();
}while (a>1);
}
//你是否也是这样修改的呢?如果你也是这样修改的应该就能看出一些端倪了,使用 do...while...修改时只有一种方法,并且你会发现这种结构可以比while结构少写一句语句。现在我们再根据实际应用理解一下do...while...的结构。首先,我们定义了一个整形变量a,然后执行do中的内容,此时就相当于计算机先尝试第一次传感器的值,然后,将读到的值与设定值进行比较,如果满足,说明此时此刻都是我们需要的值,则继续执行do的内容,然而,如果不满足与设定值的比较,说明这些值不是我们想要的,那就直接退出循环,不再读取。
while (True){
int a ;
int b = 2;
try{
cout << b+2;
a = read_Ultra();
}while (a>1);
}
//这样来看,do...while...其实是有一个预测试的过程,那么使用这样的结构,你是不是就更好理解了呢?这样看来,Python中的try似乎是继承了C++的do...while...结构。
现在是不是对while和do...while...有一些不同的认识了呢?其实使用do...while不单单是帮助你节省一句代码,还可以解决一些顺序结构中的延迟问题。这主要就涉及到了刚才的第三种方法。
//当前这种程序逻辑其实是很少发生的,一般至少是下面的这些写法
while (True){
int a = 0;
int b = 2;
while (a > 1){
cout << b+2;
}
a = read_Ultra();
}
//一般都是几种动作混合在一起的,我使用了一个delay模仿了一些其他动作的阻塞,那么现在你还认为与前两个方法相同吗?此时肯定是不同的,因为当a的值发生更新后,至少还需要等待1秒才能进入循环的判断。想象一下,就这1秒钟你可能错过多少有用的数据,并且很可能1s后,传感器的值很可能已经不再满足判断条件,所以,最后的结果是你可能只拿到一个值,这一个值能做什么呢?只能当做误差处理了,但事实真的是如此吗?
while (True){
int a = 0;
int b = 2;
while (a > 1){
cout << b+2;
a = read_Ultra();
}
a = read_Ultra();
delay(1000);
printf("hello,world");
}
//此种情况下,似乎使用do...while...会更好一些,因为当期发现符合的数据时不需要等待,而直接进入循环体,这样应该会比while收集到更多的数据。
while (True){
int a = 0;
int b = 2;
do{
cout << b+2;
a = read_Ultra();
}while (a > 1);
delay(1000);
printf("hello,world");
}