文章目录
第五章 循环
while
初识while
while 语法结构:
while(表达式)
循环语句;
举例:
while就像这张图,去考试就是while的判断条件,而继续学习则是循环内容
我们来演示一下while的用法大家就明白了
在屏幕上打印1-10的数字:
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
printf("%d ", i);
i = i+1;
}
return 0;
}
执行步骤:
-
当函数执行到第四行,先将1的值赋予给i
-
到第五行的时候,先判断 i 里面的值是否小于等于10
-
当条件成立时,执行第七和第八行的循环语句
-
执行完循环语句之后呢,再返回第五行再进行判断i 里面的值是否小于等于10。
-
然后步骤3,4循环,直到当条件不成立时跳出,继续向下执行第10行
我们只要写好控制语句,每次执行循环体前就会先判断下循环控制表达式是否为真,为真就继续执行循环,否则就结束循环。
注意:如果在循环体内忘了对影响循环控制表达式的变量(就是这个 n)进行改变,就会使这个循环变成死循环(一直执行)
while介绍
#include <stdio.h>
int main(void)
{
long num;
long sum = 0L;
int status;
printf("Please enter an integer to be summed ");
printf("(q to quit): ");
status = scanf("%ld", &num);
while (status == 1)
{
sum = sum + num;
printf("Please enter next integer (q to quit): ");
status = scanf("%ld", &num);
}
printf("Those integers sum to %ld.\n", sum);
return 0;
}
status ==1
==运算符是C的相等运算符,该表达式判断 status 是否等于 1。
不要把 status==1与status =1混淆,后者是把1赋给 status。根据测试条件 status == 1,只要 status 等于 1,循环就会重复。每次循环,num的当前值都被加到 sum 上,这样 sum 的值始终是当前整数之和。当status的值不为1时,循环结束。然后程序打印sum的最终值。
要让程序正常运行,每次循环都要获取 num的一个新值,并重置status。程序利用 scanf()的两个不同的特性来完成。首先,使用scanf()读取 num 的一个新值:然后,检査 scanf()的返回值判断是否成功获取值。scanf()返回成功读取项的数量。如果scanf()成功读取一个整数,就把该数存入 num 并返回 1,随后返回值将被赋给 status(注意,用户输入的值储存在 num 中,不是 status中)。这样做同时更新了num和 status 的值,while循环进入下一次迭代。如果用户输入的不是数字(如,q),scanf()会读取失败并返回0。此时,status的值就是0,循环结束。因为输入的字符q不是数字所以它会被放回输入队列中(实际上,不仅仅是q,任何非数值的数据都会导致循环终止,但是提示用户输入q退出程序比提示用户输入一个非数字字符要简单)。
如果 scanf()在转换值之前出了问题(例如,检测到文件结尾或遇到硬件问题),会返回一个特殊值EOF(其值通常被定义为-1)。这个值也会引起循环终止。
总之,因为 while循环是入口条件循环,程序在进入循环体之前必须获取输入的数据并检查 status的值,所以在 while前面要有一个 scanf()。要让循环继续执行,在循环内需要一个读取数据的语句,这样程序才能获取下一个 status 的值,所以在 while 循环末尾还要有一个 scanf(),它为下一次迭代做好了准备。
简洁版:
第二种形式同时使用scanf()的两种不同的特性。首先,如果函数调用成功,scanf()会把一个值存入num。然后,利用scanf()的返回值(0或 1,不是num 的值)控制 while 循环。因为每次迭代都会判断循环的条件,所以每次迭代都要调用 scanf()读取新的num值来做判断。换句话说,C的语法特性让你可以用下面的精简版本替换标准版本:
#include <stdio.h>
int main(void)
{
long num;
long sum = 0L;
int status;
printf("Please enter an integer to be summed ");
printf("(q to quit): ");
while (scanf("%ld", &num) == 1)
{
sum = sum + num;
printf("Please enter next integer (q to quit): ");
}
printf("Those integers sum to %ld.\n", sum);
return 0;
}
while中的真与假
这是一个古老的问题,但是对C而言还不算难。在C中,表达式一定有一个值,关系表达式也不例外。我们用一个例子来表达什么是真,什么是假
#include <stdio.h>
int main(void)
{
int true_val, false_val;
true_val = (10 > 2);
false_val = (10 == 2);
printf("true = %d; false = %d \n", true_val, false_val);
return 0;
}
所以由上例可知,我们目前可以得知对于 c 语言而言,
真为1假为0
又因为 while 中的判断是判断它是否为真还是为假,所以如果是while(1),则程序会一直执行下去,也就是我们所说的死循环
while(1)
{
//任务语句
}
注意:当表达式成立时,为真表达式不成立时为假
例如:
2 > 1 //成立,为真
a = 1 //成立,为真
1 > 2 //不成立,为假
...
那如果我们在while循环中填写,其他值会怎么样,是否含是为真,还是为假?
#include <stdio.h>
int main(void)
{
int n = 3;
while (n)
printf("%2d is true\n", n--);
printf("%2d is false\n", n);
n = -3;
while (n)
printf("%2d is true\n", n++);
printf("%2d is false\n", n);
return 0;
}
那从上面的代码我们可以知道,当循环条件为真时,也就是while成立,则会一直输出该值为真,当循环条件为假时,则会输出为假
然后我们从上述可以知道,如果值等于零的话,那则条件为假。如果数字为其他数的话,则条件为真
所以我们可以总结出来:
非零值为真,值是零则为假
所以我们可以很好的利用这一特性
例如:用while(goats)替换 while(goats!=0)
因为表达式goats!=0和 goats都只有在 goats的值为0时才为0或假。第1种形式(while(goats!= 0))对初学者而言可能比较清楚,但是第2种形式(while(goats))才是比较常用的。
for
for 介绍
for循环把上述3个行为(初始化、测试和更新)组合在一处。
for (表达式1; 表达式2; 表达式3)
{
语句;
}
首先要强调两点:
-
表达式1、表达式2和表达式3之间是用分号
;
隔开的,千万不要写成逗号。 -
for(表达式1;表达式2;表达式3)的后面千万不要加分号,很多新手都会犯这种错误——会情不自禁地在后面加分号。
因为 for 循环只能控制到其后的一条语句,而在C语言中分号也是一个语句——空语句。所以如果在后面加个分号,那么 for 循环就只能控制到这个分号,下面大括号里面的语句就不属于 for 循环了。
下面来看看它的执行过程:
求解表达式1。
求解表达式2。若其值为真,则执行 for 语句中指定的内嵌语句,然后执行第3步;若表达式2值为假,则结束循环,转到第5步。
求解表达式3。
转回上面第2步继续执行。
循环结束,执行 for 语句下面的语句。
从这个执行过程中可以看出,“表达式1”只执行一次,循环是在“表达式2”“表达式3”和“内嵌语句”之间进行的。
例子
#include <stdio.h>
int main(void)
{
const int NUMBER = 22;
int count;
for (count = 1; count <= NUMBER; count++)
printf("Be my Valentine!\n");
return 0;
}
关键字 for 后面的圆括号中有3个表达式,分别用两个分号隔开。
第1个表达式是初始化,只会在 for循环开始时执行一次。
第2个表达式是测试条件,在执行循环之前对表达式求值。如果表达式为假(本例中,count 大于 NUMBER时),循环结束。
第3个表达式执行更新,在每次循环结束时求值。
上述程序用这个表达式递增 count 的值,更新计数。完整的 for 语句还包括后面的简单语句或复合语句。for 圆括号中的表达式也叫做控制表达式,它们都是完整表达式,所以每个表达式的副作用(如,递增变量)都发生在对下一个表达式求值之前。
例子2:
# include <stdio.h>
int main(void)
{
int i;
int sum = 0; //sum的英文意思是“总和”
for (i=1; i<=100; ++i) //++是自加的意思, ++i相当于i = i + 1
{
sum = sum + i; /*等价于sum += i;但是不建议这么写, 因为sum = sum + i看起来更清楚、更舒服*/
}
printf("sum = %d\n", sum);
return 0;
}
输出结果是:
sum = 5050
这个程序的功能是实现求 1+2+3+4+…+100 的和,如果不用循环,加一次就要一条语句,加 100 次就要 100 条语句。这里是从 1 加到 100,要是从 1 加到 10000 那就要 10000 条语句。但有了循环就很方便了,你想加到多少就加到多少,只要改一个参数就可以了。所以循环很重要。
步骤解析:
首先求解表达式1,即给变量i赋初值,i=1;表达式1只执行这一次,下面都不会再执行了。
然后求解表达式2,若 1<=100 成立,则执行 for 循环中的内嵌语句,即 sum=0+1。
然后执行第3步,变量 i 自加 1,即变量 i 由 1 变为 2。
然后再求解表达式2,2<=100 成立,则执行 for 循环中的内嵌语句,sum=0+1+2。
然后再执行第3步,变量 i 自加 1,即变量 i 由 2 变为 3。
然后再求解表达式2,即 3<=100 成立,则执行 for 循环中的内嵌语句,sum=0+1+2+3。
……
for的灵活性
递减运算符来递减计数器
#include <stdio.h>
int main(void)
{
int i;
for(i=5;i>0;i--)
{
printf("现在输出的是%d\r\n",i);
}
return 0;
}
计数器递增倍数
#include <stdio.h>
int main(void)
{
int i;
for(i=0;i<20;i=i+2)
{
printf("现在输出的是%d\r\n",i);
}
return 0;
}
可以用字符代替数字计数
#include <stdio.h>
int main(void)
{
char i;
for(i='a';i<='z';i++)
{
printf("现在输出的是%c\r\n",i);
}
return 0;
}
测试多样条件
#include <stdio.h>
int main(void)
{
int i;
//for(i=0;i<=6;i++) 替换
for(i=0;i*i*i<=216;i++)
{
printf("现在输出的是%d\r\n",i);
}
return 0;
}
递增的量几何增长
#include <stdio.h>
int main(void)
{
double i;
for(i =100.0;i<150.0;i=i*1.1)
{
printf("现在输出的是%.2f\r\n",i);
}
return 0;
}
双条件
#include <stdio.h>
int main(void)
{
int x;
int y=55;
for(x = 1; y <= 75; y = (++x * 5) + 50)
{
printf("现在输出的x是%d, y是%d\r\n",x,y);
}
return 0;
}
省略表达式
可以省略一个或多个表达式(但是不能省略分号),只要在循环中包含能结束循环的语句即可。
注意:不要造成死循环
省略第一个条件
#include <stdio.h>
int main(void)
{
int x = 1;
for(; x <= 5; ++x)
{
printf("现在输出的x是%d\r\n",x);
}
return 0;
}
省略第二个条件
#include <stdio.h>
int main(void)
{
int x;
for(x = 1;; ++x)
{
printf("现在输出的x是%d\r\n",x);
if(x == 5)
return ;
}
return 0;
}
省略第三个条件
#include <stdio.h>
int main(void)
{
int x;
for(x = 1; x <= 5; )
{
printf("现在输出的x是%d\r\n",x);
++x;
}
return 0;
}
死循环
#include <stdio.h>
int main(void)
{
for(;;);
return 0;
}
初值选择
#include <stdio.h>
int main(void)
{
int x = 1;
for(printf("这是一个表达式\r\n");x<5;++x)
{
printf("x的值是%d\r\n",x);
}
return 0;
}
简易控制循环值
#include <stdio.h>
int main(void)
{
int x = 1;
int num,val;
printf("本次循环最大值为:\r\n");
scanf("%d",&val);
printf("每次循环递增值为:\r\n");
scanf("%d",&num);
for(printf("这是一个表达式\r\n");x<val;x=x+num)
{
printf("x的值是%d\r\n",x);
}
return 0;
}
逗号运算符
逗号运算符扩展了for循环的灵活性,以便在循环头中包含更多的表达式。
例如演示了一个打印一类邮件资费。
#include <stdio.h>
int main(void)
{
const int FIRST_OZ = 46; // 2013 rate
const int NEXT_OZ = 20; // 2013 rate
int ounces, cost;
printf(" ounces cost\n");
for (ounces=1, cost=FIRST_OZ; ounces <= 16; ounces++,
cost += NEXT_OZ)
printf("%5d $%4.2f\n", ounces, cost/100.0);
return 0;
}
do while
while循环和 for循环都是入口条件循环,即在循环的每次迭代之前检查测试条件,所以有可能根本不执行循环体中的内容。C语言还有出口条件循环,即在循环的每次迭代之后检查测试条件,这保证了至少执行循环体中的内容一次。这种循环被称为do while循环。
do while 语句创建一个循环,在expression为假或0之前重复执行循环体中的内容。do while语句是一种出口条件循环,即在执行完循环体后才根据测试条件决定是否再次执行循环。因此,该循环至少必须执行一次。
格式:
do
{
statement;
}While(expression );
在expression为假或0之前,重复执行statement部分。
例子:
#include <stdio.h>
int main()
{
int i=1,sum=0;
do
{
sum+=i;
i++;
}while(i<=24);
printf("%d",sum);
return 0;
}
如果是while写的
#include <stdio.h>
int main(void)
{
const int secret_code = 13;
int code_entered;
printf("To enter the triskaidekaphobia therapy club,\n");
printf("please enter the secret code number: ");
scanf("%d", &code_entered);
while (code_entered != secret_code)
{
printf("To enter the triskaidekaphobia therapy club,\n");
printf("please enter the secret code number: ");
scanf("%d", &code_entered);
}
printf("Congratulations! You are cured!\n");
return 0;
}
如果是do while写的:
#include <stdio.h>
int main(void)
{
const int secret_code = 13;
int code_entered;
do
{
printf("To enter the triskaidekaphobia therapy club,\n");
printf("please enter the secret code number: ");
scanf("%d", &code_entered);
} while (code_entered != secret_code);
printf("Congratulations! You are cured!\n");
return 0;
}
do while循环在执行完循环体后才执行测试条件,所以至少执行循环体一次;而 for 循环或 while循环都是在执行循环体之前先执行测试条件。do while循环适用于那些至少要迭代一次的循环。例如,下面是一个包含do while循环的密码程序伪代码:
如何选择循环
如何选择使用哪一种循环?首先,确定是需要入口条件循环还是出口条件循环。通常,入口条件循环用得比较多,有几个原因。其一,一般原则是在执行循环之前测试条件比较好。其二,测试放在循环的开头,程序的可读性更高。另外,在许多应用中,要求在一开始不满足测试条件时就直接跳过整个循环。
那么,假设需要一个入口条件循环,用for循环还是while循环?这取决于个人喜好,因为二者皆可要让for循环看起来像while循环,可以省略第1个和第3个表达式。例如:
for ( ; test ; )
与下面的while效果相同: while ( test )
要让while循环看起来像for循环,可以在while循环的前面初始化变量,并在while 循环体中包含更新语句。例如:
初始化;
while (测试)
{
其他语句
更新语句
}
与下面的for循环效果相同:
for(初始化 ;测试;更新)
其他语句
一般而言,当循环涉及初始化和更新变量时,用f循环比较合适,而在其他情况下用while循环好。对于下面这种条件,用while循环就很合适:
while (scanf("%d",&num) == 1)
对于涉及索引计数的循环,用for循环更适合。
例如: for (count = 1; count <= 100; count++)
嵌套循环
嵌套循环指在一个循环内包含另一个循环。嵌套循环常用于按行和列显示数据,也就是说一个循环处理一行中的所有列,另一个循环处理所有的行。
#include <stdio.h>
#define ROWS 6
#define CHARS 10
int main(void)
{
int row;
char ch;
for (row = 0; row < ROWS; row++)
{
for (ch = 'A'; ch < ('A' + CHARS); ch++)
printf("%c", ch);
printf("\n");
}
return 0;
}
第 9行开始的 for 循环被称为外层循环
第11行开始的for 循环被称为内层循环(innerloop)。
外层循环从row为0开始循环,到row为6时结束。
因此,外层循环要执行6次,row的值从 0变为 5。每次迭代要执行的第1条语句是内层的 for 循环,该循环要执行 10 次,在同一行打印字符 A~J:第2条语句是外层循环的 printf(“\n”);
该语句的效果是另起一行,这样在下一次运行内层循环时,将在下一行打印的字符。
注意,嵌套循环中的内层循环在每次外层循环迭代时都执行完所有的循环.内层循环一行打印10个字符,外层循环创建6行。
#include <stdio.h>
int main(void)
{
const int ROWS = 6;
const int CHARS = 6;
int row;
char ch;
for (row = 0; row < ROWS; row++)
{
for (ch = ('A' + row); ch < ('A' + CHARS); ch++)
printf("%c", ch);
printf("\n");
}
return 0;
}
因为每次迭代都要把 row的值与’'相加,所以 ch在每一行都被初始化为不同的字符。然而,测试条件并没有改变,所以每行依然是以F结尾,这使得每一行打印的字符都比上一行少一个。