7.0.0 程序的调试
- 使用调试功能可以让CPU在执行程序的时候一句代码一句代码的执行。
- 断点:在代码的行号的地方单击一下,就会产生一个断点。当我们执行程序的时候,当CPU执行代码执行到断点行的代码的时候,CPU就会暂停执行,并且高亮显示断点行代码。高亮显示的代码表示这句代码立即就要执行,但是还没有执行,等我们的指令才执行。按下step over就会将高亮显示的代码执行,并且高亮显示下一句要执行的代码,继续等待我们的指令。
- 这样做可以跟踪CPU执行代码的步骤,可以清晰看到CPU在执行代码的时候先执行哪一句后执行哪一句。
- 程序调试的主要作用是用来监视程序执行时变量的值是如何变化的。
- 在调试窗口可以看到变量的值的变化
- 用鼠标指向变量也可以看到值的结果
- 要退出调试模式需按下Continue program execution按钮即可。
8.0.0 循环结构
- 同一件事反复不停的去做,这样的情况我们就叫做循环。
- 循环的特点:
- 同一件事事情
- 反复不停的做,中间不能停
- 循环也有结束的时刻
- 在代码世界中,也有类似的需求:有一段代码,需要反复不停的执行指定的次数。
- 循环结构:
- 作用:同一段代码反复不停的执行指定的次数。
- 语法结构:
- while循环结构
- do-while循环结构
- for循环结构
无论是哪一种循环结构他们都是将同一段代码反复不停的执行指定的次数,唯一的区别就是语法不同,写法不一样。
8.1.0 while循环结构
8.1.1 while循环结构的语法
- 语法:
while(条件表达式)
{
那段需要被反复不停执行的代码;(循环体)
}
8.1.2 执行步骤
- 先判断while后面的条件表达式的真假;
- 如果为真,就执行循环体,执行完循环体之后,再跳回第一步骤继续执行;
- 如果为假,就立即结束while循环往下执行。
8.1.3 死循环
每次判断循环条件,每次得到的都是结果真,循环体就会一直反复不停的执行下去,这样的循环就做死循环。因尽量避免死循环。
8.1.4 使用while循环的注意事项
- while后面的表达式可以是任意表达式,反正0为假,非0为真。
- 永真和永假。
while(0)
while(1)
- 循环体可以有任意行的代码。
- 写循环的时候,务必要确定如下两点:
- 先确定循环体,必须要知道是哪一段代码需要被反复不停的执行
- 必须要知道循环继续或者结束的条件
8.1.5 循环应用场景
- 循环体确定,循环次数也确定的循环。
- 解决步骤:
- 先声明一个int类型的变量i并赋值为0,这个变量叫做循环增量;
- while循环条件,写上i < 次数;
- 在循环体中记得要写i++; 来改变循环增量的值。
- 解决步骤:
例如:有一段代码需要执行n次
int i = 0;
while (i < n)
{
循环体;
i++;
}
- 循环体确定,循环的次数不确定的,但是循环继续的条件是确定的。
- 解决步骤
- 先把循环的架子搭出来,因为确定是循环结构;
- 把循环体写出来;
- 在循环条件中写上循环继续的条件;
- 这个时候你会发现循环条件用到的变量声明在循环体中,将其声明在循环结构外即可。
- 解决步骤
例如:如果输入的密码不是888888,就要求用户再输入一次,直到正确为止。
int pwd = 0;
printf(“Please insert the password:”);
scanf(“%d”,&pwd);
while (pwd != 888888)
{
printf(“Your password is not correct! Please try again!\n”);
scanf(“%d”,&pwd);
}
printf(“Your password is correct! Thank you!\n”);
- 注意:
- 参与循环条件表达式的变量的默认值不要让第一次的循环判断就不成立。
- 遍历指定范围的数
- 实现步骤:
遍历n-m之间的每一个整数
- 先声明一个循环增量i,默认值是n;
- 循环条件写i<=m;
- 在循环体中循环增量i的值就是n-m之间的每一个整数;
- 一定要记得在循环体后面自增循环增量。
int i = n;
while (i <= m)
{
i的值就是n-m之间的整数
i++;
}
- 找出指定范围中符合特定条件的数
- 案例:找出1-100之间可以被8整除的数。
- 实现步骤
- 先遍历n-m的每一个整数;
- 判断遍历出来的数是否符合特定条件,如果符合就取出来,否则就不操作。
int i = n;
while (i <= m)
{
if (i符合特定条件)
{
把i取出来;
}
i++;
}
- 请找出1000到5000之间各位数之和为5的数。
int i = 1000;
while (i <= 5000)
{
int qianWei = i / 1000;
int baiWei = i % 1000 / 100;
int shiWei = i % 100/ 10;
int geWei = i % 10;
int sum = qianWei + baiWei + shiWei + geWei;
if (sum == 5)
{
printf(“%d\n”,i);
}
i++;
}
- 求累加和与平均值
- 实现步骤:求n-m之间的每一个整数的累加和。
- 先准备一个框变量,用来保存累加和;(框变量应该声明在循环体之外)
- 再遍历n-m之间的每一个整数;
- 将遍历出来的每一个数累加到框变量中;
- 当遍历完成以后,框变量中的数据就是n-m之间的每一个整数的累加和。
- 实现步骤:求n-m之间的每一个整数的累加和。
int sum = 0;
int i = n;
while (i <= m)
{
sum += i;
i++;
}
printf(“sum = %d\n”,sum);
- 求一堆数的最大值或最小值
- 案例:请用户输入n个数,求最大数或最小数。
- 实现步骤:
- 声明一个擂台变量;
- 拿到这n个数的每一个数,将这些数每一个遍历出来;
- 将遍历出来的数和擂台变量进行比较,符合条件的就赋值给擂台变量,不符合条件的就跳过;
- 当遍历完成以后,擂台变量的值就是符合条件的数。
int max = 0;
int i = 0;
while (i < n)
{
printf(“Please insert No. %d number:”, i + 1);
int num = 0;
scanf(“%d”,&num);
if (i == 0)
{
max = num;
}
else if (num > max)
{
max = num;
}
i++;
}
printf(“The Max one is %d.\n”,max);
或者直接在一开始将max赋值为INT32_MIN
- 计数
- 记录循环了多少次;
- 记录某个条件满足了多少次。
声明一个整型的变量,用来记录循环的次数,每循环一次自增。
- 穷举
- 一个一个的挨个试
例子:
#include <stdlib.h>
int num = arc4random_uniform(100)+1;
int i = 1;
while (1)
{
if (num == i)
{
printf(“%d\n”,i);
break;
}
i++;
}
8.1.6 break与continue
- break
- 可以使用在switch-case的case块结构中,表示立即结束该switch-case结构;
- 还可以使用在循环体中,将break写在循环体内部中,表示立即结束该循环结构。
- continue
- 只能使用在循环体中
- 在循环体中遇到了continue,会立即结束本次循环,然后返回判断循环条件。
- 有时候需要判断循环结束的方式,是自然结束的还是通过break结束的。
- 第一种方法可以通过判断循环增量的值是不是最后一个值来判断循环结束的方式;
- 第二种方法,有时候在循环结束以后无法访问循环增量。就可以声明一个旗帜变量,旗帜变量的值只在break的时候改变,循环结束以后,就可以判断旗帜的值来判断循环是如何结束的。
8.2.0 do-while循环结构
8.2.1 do-while循环结构的作用和语法
作用:将同一段代码反复不停的执行指定的次数。
语法:
do
{
循环体;
}while (条件表达式);
8.2.2 执行步骤
执行步骤
- 不管任何条件,先执行一次循环体;
- 计算while后面的条件表达式的结果,如果结果为真,就执行循环体,循环体执行完毕之后,再跳回第二步继续执行;
- 如果结果为假,结束do-while循环结构。
8.2.3 特点
特点
- 循环体无论如何都会至少执行一次
8.2.4 do-while和while循环的异同点
- 相同点:都是循环结构,都可以将一段代码反复不停的执行指定的次数;
- 不同点:
- do-while循环结构先执行再判断条件,而while循环结构是先判断再执行;
- 在条件不成立的情况下,while循环结构一次都不会执行,但是do-while结构会执行一次循环体
8.3.0 for循环
8.3.1 for循环的作用和语法
- for循环和while循环本质上没有差别。
- 语法:
for (初始化表达式;循环条件表达式;循环后操作表达式)
{
循环体;
}
注意:for的小括号内是要写3个表达式的。
8.3.2 执行步骤
执行步骤:
- 先执行初始化表达式;
- 判断循环条件表达式的真假,如果为真,就执行循环体,循环体执行完毕之后,再执行循环后操作表达式,然后跳回第二步的开始继续执行;
- 如果为假,就结束for循环。
8.3.3 for循环结构和while循环结构
- 对于一个while循环结构而言,最重要的三句代码是:
- 循环增量的声明;
- 循环条件;
- 循环结束前修改循环增量的值。
- 实际上,for循环结构也有这三句代码:
- 循环增量的声明:声明在第一个表达式中,就是初始化表达式;
- 循环条件:写在第二个表达式中,也就是循环条件表达式;
- 修改循环增量的值:写在第三个表达式中,也就是循环后操作表达式。
- 所以,for循环做的事情,只是为这三句代码设计了一个专门的位置而已。
8.3.4 注意事项
- 在for循环结构中循环后操作表达式后是没有分号的;
- 注意修改循环增量的值的表达式的位置,不要放错位置或重复放置;
- 三个表达式的位置是固定的,不可以更换顺序;
- 三个表达式可以省略,但是分号不可以省略,如果第二个表达式省略,那么循环条件就成立,是死循环;
- 这三个表达式其实任意的C语句都是可以的,但是只能是三句语句。
- break和continue一样可以用在for循环结构中:
- break会立即结束循环,后面在循环体中的代码都不会执行,包括写在循环体中的计数代码i++;
- continue会立即结束本次循环,但是不会结束计数i++。
- 能用while循环结构实现的代码,一定可以用for循环来实现,反之亦然。
- 使用建议:
- 当循环次数确定的情况下,一般我们使用for循环;
- 当循环次数不确定的情况下,一般使用while循环;
8.4.0 嵌套循环
8.4.1 什么是嵌套循环
一个循环的循环体代码中又包括1个循环结构,这样的循环就叫做嵌套循环。
8.4.2 嵌套循环的特点
外层循环循环一次,内层循环要循环所有次。
例子:
for (int i = 0;i < 5;i++)
{
printf(“==========\n”);
for (int j = 0;j < 3;j++)
{
printf(“I’m coming!\n”);
}
printf(“==========\n”);
}
8.4.3 什么时候要使用嵌套循环?
A事情完成一次,B事情就必须要完成n次,而A也需要完成一定的次数,这样的时候就可以使用嵌套循环。
A就是外层循环,B就是内层循环。
8.4.4 几个案例
案例一:要打印1个10行,每一行都有10颗星的图案。
代码:
for (int i = 0;i < 10;i++)
{
for (int j = 0; j < 10;j++)
{
printf(“*”);
}
printf(“\n”);
}
案例二:要打印1个10行,从第一行开始,每行增加一颗星的图案:
*
**
***
****
*****
******
*******
********
*********
**********
分析:第一行打印一颗星,第二行是两颗星,那么第i行就是i颗星。
所以代码如下:
for (int i = 1;i <= 10; i++)
{
for (int j = 1;j <= i; j++)
{
printf(“*”);
}
printf(“\n”);
}
案例三:要打印一个19行,从第一行开始每行递增一颗星,到第十行达到10颗星后再每行递减的图案。
*
**
***
****
*****
******
*******
********
*********
**********
*********
********
*******
******
*****
****
***
**
*
分析:前十行与上一个案例相同,但是后面九行则是从第一行开始,打印9颗星,而第二行打印8颗星,可以发现行数与星数的关系是:行数+星数=10,反过来就是星数=10-行数。
所以代码如下:
for (int i = 1;i <= 10;i++)
{
for (int j = 1; j <= i; j++)
{
printf(“*”);
}
printf(“\n”);
}
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 10 – i; j++)
{
printf(“*”);
}
printf(“\n”);
}
案例四:打印如下图案:
*
**
***
****
*****
******
*******
********
*********
**********
分析:可以发现每一行所打印的内容是n个空格+m个*,而n+m=10。而每一行的空格数是10-行数i。
所以可以写出以下代码:
for (int i = 1; i <= 10; i++)
{
for (int n = 1; n <= 10-i; n++)
{
printf(“ “);
}
for (int m = 1; m <= i; m++)
{
printf(“*”);
}
printf(“\n”);
}
案例五:打印九九乘法口诀表
分析:九九乘法口诀表有九行,所以应该写一个循环,循环九次,每次打印一行。每一行的表达式的个数不一样。
第一行 1个
第二行 2个
……
第i行 i个
代码如下:
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= i; j++)
{
printf(“%d * %d = %d\t”,j,i,i*j);
}
printf(“\n”);
}
“\t”代表一个制表符,tab键的效果。
8.4.5 代码结构总结
- 顺序结构
代码从上到下的一句一句的逐句执行,每一句代码都要执行,这样的代码结构我们叫做顺序结构。
- 分支结构
代码的执行存在分支执行的情况,叫做分支结构。如if结构和switch-case结构。它可以让代码出现很多分支,然后选择其中一个分支来执行。
- 循环结构
同一段代码反复不停的执行指定的次数。如while结构、do-while结构和for结构都是循环结构。
8.4.6 goto跳转语句
goto语句可以将CPU的执行跳转到当前函数的别的地方继续执行。
- 如何使用
- 先为想要跳转到的地方做一个标记,为这个地方去一个标签名。标签名随意,但是要符合标示符的命名规范。
标签名:
- 想要再什么地方跳转到做标记的地方,就在哪个地方写上。
goto 标签名;
当执行到goto语句时,CPU就会跳转到指定的标签的地方继续往下执行。
- goto语句也可以实现循环操作。
- 要注意不要造成死循环。
- 注意:
- 标签名可以随意,但是要符合标示符的命名规则和规范;
- goto可以往前跳,也可以往后跳;
- 只能在当前函数中跳转;
- 取标签名下面的第一行代码不能是声明变量。