第6章 C语言控制语句:循环

发布于 2021-04-12  500 次阅读


对于计算机科学而言,一门语言应该改提供以下三种形式的程序流:

  • 执行语句序列;
  • 如果满足某些条件就重复执行语句序列(循环)
  • 通过测试选择执行哪一个语句序列(分支)

6.1 再探while循环

//  summing.c       根据用户键入的整数求和
#include<stdio.h>
int main(void)
{
    long num;
    long sum = 0L;              //把sum初始化为0
    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;
}

6.1.1 程序注释

status == 1;
==运算符是C的相等运算符(equality operator)该表达式判断status是否等于1.scanf会返回成功读取数量。如果用户输入的不是数字,则返回1.

//该程序的答题思路
把sum初始化为0
提示用户输入数据
读取用户输入的值
当输入的数据为整数时,
    输入的值添加给sum,
    提示用户进行输入,
    然后继续读取下一个输入
输入完成以后,打印sum的值

上面这种表达形式叫做伪代码(pseudocode),简单句子表达程序思路的方法。伪代码有助于设计程序的逻辑。

//while
获得第一个用于测试的值
当测试为真时
    处理值
    获取下一个值

6.1.2 C风格读取循环

//  伪代码
status = scanf("%ld",&num);
while(status==1)
{
    //循环
    status = scanf("%ld",&num);
}
//可以下代替
whlie(scanf("%ld",&num)==1)
{
    //循环
}

C语言特性:
当获取值和判断值都成功
处理该值

#include<stdio.h>
int main()
{
    int s,n,p;
    p=0;
    printf("Enter a num(q to quit):");
    while(scanf("%d",&n)==1)
    {   
        p = p+n;
        printf("Enter a num(q to quit):");
    }
    printf("sum = %d\n",p);

    return 0;
}

6.2 while语句

while循环的通用形式如下:
while(expression)
statement
statement部分可以使以分号结尾的简单语句,也可以是花括号括起来的复合语句。

6.2.1 终止while循环

while循环最终目的是要跳出去(即条件为假)

6.2.2 何时终止循环

只有对测试条件求值时,才决定是终止还是继续。

//  when.c  -- 何时退出循环
#include<stdio.h>
int main(void)
{
    int n = 5;

    while(n<7)
    {
        printf("n = %d\n",n);
        n++;
        printf("Now n =%d\n",n);
    }
    printf("The loop has finished.\n");

    return 0;
}

file

6.2.3 while:入口条件循环

入口条件(entry condition

6.2.4 语法要点

//while1.c --   注意花括号的使用
//  糟糕的代码创建了一个无限的循环
#include<stdio.h>
int main(void)
{
    int n = 0;

    while(n < 3)
        printf("n is %d\n",n);
        n++;
    printf("That's all this program does\n");

    return 0;
}

无限循环(infinite loop

//  while2.c    --注意分号的位置
#include<stdio.h>
int main(void)
{
    int n;

    while(n++<3);
        printf("n is %d\n",n);
    printf("That's all this program does.\n");

    return 0;
}

file
再while后加分号,while也被认为是一条语句。为假以后,执行一次while再进入下一个语句!!!
空语句(null statement)在C语言中,单独的分号表示空语句。

//  跳过整数输入
while(scanf("%d",&num)==1)

6.3 用关系运算符和表达式比较大小

关系表达式(relational expression)
关系运算符(relation operator)
file

while(number<6)
{
    printf("Your number is too small.\n");
    scanf("%d",&number);
}
while("ch!='$'")
{
    count++;
    scanf("%c",&ch);
}
while(scanf("%f",&num) == 1)
{
sum = sum+1;
}

注意:比较浮点数时,尽量只使用<和>.因为浮点数的舍入误差会导致在逻辑上应该相等的两数不相等。例如:

3乘1/3的积为1.0。如果把1/3表示成小数点后6位数字,乘积则是.999999.不等于1.使用fabs()函数(math.h)可以方便的比较浮点数,该函数返回一个浮点数的绝对值(即,没有代数符号的值)

//  cmpflt.c    --浮点数比较
#include<stdio.h>
#include<math.h>
int main(void)
{
    const double ANSWER = 3.14159;
    double response;

    printf("What is the value of pi?\n");
    scanf("%lf",&response);
    while(fabs(response - ANSWER)>0.0001)
    {
        printf("Try again!\n");
        scanf("%lf",&response);
    }
    printf("Close enough!\n");

    return 0;
}

file

6.3.1 什么是真?

//  t_and_f.c   --C中的真和假的值
#include<stdio.h>
int main(void)
{
    int true_val;
    int false_val;

    true_val=(2<10);
    false_val=(2 == 10);

    printf("t=%d f=%d",true_val,false_val);

    return 0;
}

file
一直循环的结构

while(1)
{
...
}

6.3.2 其他真值

//  truth.c --哪些值位真值
#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);

    return 0;
}

file
熟悉while(goats)

6.3.3 真值的问题

//  trouble.c   --无用=会导致无线循环
#include<stdio.h>
int main(void)
{
    long num;
    long sum=0;
    printf("Enter num(q to quit):");
    while(scanf("%ld",&num)==1)
    {
        sum=sum+num;
        printf("%d\n",sum);
    }
    printf("%d",sum);

    return 0;
}

当while中的为等号时,为赋值语句,在执行一次真后就变成while(1)了。。。

canoes = 5 //赋值,把5赋给canoes
canoes == 5 //检查canoes的值是否为5
5 = canoes //语法错误
5 == canoes //检查canoes的值是否为5

非零为真,零为假

6.4.4 新的_BOOl类型

C99专门针对真假新增加了_Bool类型
表示真假的变量称为布尔变量(Boolean variable
_Bool类型的变量只能存储0或1,其他非0数字传给_Bool,该变量会被设置为1.

//  boolean.c   --使用\_Bool类型的变量variable
#include<stdio.h>
int main(void)
{
    long num;
    long sum=0;
    _Bool input_is_good;

    printf("Please Enter num(q to quit):");
    input_is_good=scanf("%d",&num);
    while(input_is_food)
    {
    ...
    input_is_good=scanf("%d",&num);
    }
    printf("%d",sum);
    return 0;
}

C99提供了stdbool.h头文件,该头文件让bool称为_Bool的别名,而且还把true和false分别定义为0和1的符号常量,且写出来的代码与c++兼容。在c++中bool、true、false为关键字。

6.3.5 优先级和关系运算符

关系运算符的优先级比算术运算符低,比赋值运算符高。意味着:
x>y+2和x>(y+2)相同
x=y>2和x=(y>2)如果y>2赋1给x否则赋给x=0。
高优先级组:<\<= >>=
低优先级组:== !=
ex != wye ==zee与(ex !=wye)==zee相同
file

6.4 不确定循环和技术循环

不确定循环(indefinite loop)
计数循环(counting loop)

//  sweetie1.c      --一个计数循环
#include<stdio.h>
int main(void)
{
    const int MUMBER = 22;
    int count = 1;

    while(count<=MUMBER)
    {
        printf("be my valentine!\n");
        count++;
    }
    return 0;
}

在创建一个重复执行固定次数的循环中涉及了3个行为:

  1. 必须初始化计数器
  2. 计数器与有限的值做比较
  3. 每次循环时递增计数器

6.5 for循环

//  sweetie2.c  --使用for循环的计数循环
#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 圆括号中的表达式也叫控制表达式,它们都是完整表达式,所以每个表达式的副作用(如,递增变量)都发生在对下一个表达式求值之前。
file

//  for_cube.c  --使用for循环创建一个立方表
#include<stdio.h>
int main(void)
{
    int num;

    printf("n    n cubed\n");
    for(num=1;num<=6;num++)
    {   
        printf("%-4d %-4d\n",num,num*num*num);
    }
    return 0;
}

file

6.5.1 利用for的灵活性

  • 可以使用递减运算符来递减计数器

    //  for_down.c
    #include<stdio.h>
    int main(void)
    {
    int secs;
    
    for(secs=5;secs>0;secs--)
    {
        printf("%d secondes!\n",secs);
    }
    printf("We have ignition!\n");
    return 0;
    }

    file

  • 可以让计数器递减2、10等

    //  for_13s.c
    #include<stdio.h>
    int main(void)
    {
    int n;
    
    for(n=2;n<60;n=n+13)
    {
        printf("%d\n",n);
    }
    return 0;
    }

    file

  • 可以让字符串代替数字

    //  for_Char.c
    #include<stdio.h>
    int main(void)
    {
    char ch;
    
    for(ch='a';ch<='z';ch++)
    {
    printf("The ASCII value for %c is %d.\n",ch,ch);
    }
    return 0;
    }

    file

  • 除了测试迭代次数外,还可以测试其他条件。

    for(num = 1;num<=6;num++)
    //替换成
    for(num = 1;num*num*num<=216;num++)

    如果与控制循环次数相比,你更关心限制立方的大小,就可以使用这样的测试条件。

  • 可以让递增的量几何增长,而不是算术增长。

    //  for_geo.c
    #include<stdio.h>
    int main(void)
    {
    double debt;
    
    for(debt=100.0;debt<150.0;debt=debt*1.1)
    {
        printf("Your debt is now $%.2f.\n",debt);
    }
    
    return 0;
    }

    file

  • 第3个表达式可以使用仍以合法的表达式。无论是什么表达式,每次迭代都会更新该表达式的值。

    //  for_wild.c
    #include<stdio.h>
    int main(void)
    {
    int x;
    int y = 55;
    
    for(x=1;y<=75;y=(++x*5)+50)
    {
    printf("%10d %10d\n",x,y);
    }
    return 0;
    }

    file

  • 可以省略一个或多个表达式(不能省略分号),只要在循环中包括能结束循环的语句即可

    #include<stdio.h>
    int main(void)
    {
    int ans,n;
    ans = 2;
    for(n = 3;ans<=25;)
    {
        ans=ans*n;
    }
    printf("n = %d.ans=%d.\n",n,ans);
    
    return 0;
    }

    file

下面的循环会一直运行

    for( ; ; )
{
    printf("im so boring");
}
  • 第1个表达式不一定是给变量赋初值,也可以使用printf()

    //  for_show.c
    #include<stdio.h>
    int main(void)
    {
    int num = 0;
    
    for(printf("Keep entering numbers!\n);num!=6;)
    {
        scanf("%d",&num);
    }
    printf("That's the one I want!\n");
    
    return 0;
    }

    file

  • 循环体中的行为可以改变循环头中的表达式

for(n = 1;n<10000;n \= n+delta)
经过几次的带以后发现delta太小,循环语句中的if可以改变delta的大小。

小结

file

6.6 其他赋值运算符

file
更加复杂:

x*=3*y+12与x = x*(3*y+12)
以上提到的赋值运算符与=的优先级相同
优点:让代码紧凑。组合形式的赋值运算比一般形式赋值运算生成的机器代码更高效。
当需要在for循环中塞一些复杂的表达式时,这些赋值运算符都特别有用。

6.7 逗号运算符

//  postage.c   --一类邮咨
#include<stdio.h>
int main(void)
{
    const int FIRST_OZ = 46;
    const int NEXT_OZ = 20;
    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;
}

file
逗号保证了表达式从左往右求值。
file
其次,整个表达式的值是右侧的值:
x = (y=3,(z=++y+2)+5)
效果:先把3赋给y,++y=4,+2=6,z=6,x=6+5=11;
houseprise =249,500
表示houseprise =249;
500;

houseprise =(249,500)
表示为:houseprise =500
逗号也可以作为分隔符,在下面语句中的逗号都是分隔符,不是逗号运算符:
char ch,date;
printf("%d %d\n",a,b);

小结

file
file

6.7.1 当Zero遇到for循环

//  zeno.c  --求序列的和
#include<stdio.h>
int main(void)
{
    int t_ct;
    double time,power_of_2;
    int limit;

    printf("Enter the number of term you want:");
    scanf("%d",&limit);
    for(time=0,power_of_2=1,t_ct=1;t_ct<=limit;t_ct++,power_of_2*=2.0)
    {
        time +=1.0/power_of_2;
        printf("time = %f when terms =%d.\n",time,t_ct);
    }

    return 0;
}

file
file


擦肩而过的概率