第6章 C控制语句:循环

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_24990189/article/details/90081972

关键字:for、while、do while

运算符:<、>、>=、<=、!=、==、+=、*=、-=、/=、%=

函数:fabs()

C语言有3中循环:for、while、do while

使用关系运算符构建控制循环的表达式

其他运算符

循环常用的数组

编写有返回值的函数

一种语言应该提供以下3种形式的程序流

执行语句序列

如果满足某些条件就重复执行语句序列

通过测试选择执行哪一个语句序列(下一章)

目录

6.1 再探while循环

6.1.1 程序注释

6.1.2 C风格读取循环

6.2 while语句

6.2.1 终止while循环

6.2.2 何时终止循环

6.2.3 while: 入口条件循环

6.2.4 语法要点

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

6.3.1 什么是真

6.3.2 其他真值

6.3.3 真值的问题

6.3.4 新的Bool类型

6.3.5 优先级和关系运算符

6.4 不确定循环和计数循环

6.5 for循环

6.6 其他赋值运算符:+=、-=、*=、/=、%=

6.7 逗号运算符

6.8 出口条件循环

6.9 如何选择循环

6.10 嵌套循环

6.10.1 程序分析

6.10.2 嵌套变式

6.11 数组简介

6.12 使用函数返回值的循环示例

6.12.1 程序分析

6.12.2 使用带返回值的函数

6.13 关键概念

6.14 本章小结


6.1 再探while循环

6.1.1 程序注释

6.1.2 C风格读取循环

/* summing.c -- sums integers entered interactively */
#include <stdio.h>
int main(void)
{
    long num;
    long sum = 0L;      /* initialize sum to zero   */
    int status;
    
    printf("Please enter an integer to be summed ");
    printf("(q to quit): ");
    status = scanf("%ld", &num);
    while (status == 1) /* == means "is equal to"   */
    {
        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;
}
[wlsh@wlsh-MacbookPro] ch06$ clang summing.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
Please enter an integer to be summed (q to quit): 44
Please enter next integer (q to quit): 33
Please enter next integer (q to quit): 88
Please enter next integer (q to quit): 121
Please enter next integer (q to quit): q
Those integers sum to 286.

第4章介绍过,scanf()返回成功读项的数量。若果scanf()成功读取一个整数,就把该数存入num并返回1,随后返回值被赋值为status。这样做同时更新了num和status的值,while循环进入下一次迭代。

如果用户输入的字符q不是数字,scanf()就读取失败并返回0。如果scnf()在转换值之前出了问题(检测到文件结尾或遇到硬件问题),会返回一个特殊值EOF(其值为-1),也会引起循环终止。

总之,该程序利用scanf()的双重特性避免了在循环中交互输入时这个棘手的问题。伪代码(preudocode),while循环是入口条件循环。

while(status == 1){
    /*循环行为*/
    status = scanf("ld",&num);
}

while(scanf("ld",&num) == 1){
    /*循环行为*/
}

 

6.2 while语句

通用形式:expression部分使用关系表达式。如果expression为真,即非0,执行statement部分一次,然后再次判断expression,在expression为假之前,循环的判断和执行一直重复进行。每次循环都是一次迭代(iteration)

while(expression)
    statement  //分号结尾简单语句;或者花括号扩起来的复合语句

6.2.1 终止while循环

6.2.2 何时终止循环

// when.c -- when a loop quits
#include <stdio.h>
int main(void)
{
    int n = 5;
    
    while (n < 7)                    // line 7
    {
        printf("n = %d\n", n);
        n++;                         // line 10
        printf("Now n = %d\n", n);   // line 11
    }
    printf("The loop has finished.\n");
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch06$ clang when.c
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
n = 5
Now n = 6
n = 6
Now n = 7
The loop has finished.

6.2.3 while: 入口条件循环

入口条件(entry condition)、无限循环(infinite loop)、空语句(null statement)

6.2.4 语法要点

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

while循环依赖关系表达式(relational expression)作比较,出现在关系表达式中间的运算符叫关系运算符(relational operator)

while(ch != '$')
{
    count++;
    scanf("%c",&ch);
}

while(scanf("%f",&num)==1)
    sum = sum + num;

比较时使用的是机器字符码(假定为ASCII)。不能用关系运算符比较字符串,第11章会介绍如何比较字符串。

// cmpflt.c -- floating-point comparisons
#include <math.h>
#include <stdio.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;
}
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
What is the value of pi?
3.14
Try again!
3.14159
Close enough!
#include <math.h>

double
fabs(double x);

long double
fabsl(long double x);

float
fabsf(float x);

浮点数的舍入误差会导致在逻辑上应该相等的两数却不相等。例如3 * 1/3 = 1,但是把1/3表示成小数点后6位数字,则是.999999,不等于1。使用fabs()函数返回一个浮点值的绝对值,可以方便地比较浮点数。

6.3.1 什么是真

/* t_and_f.c -- true and false values in C */
#include <stdio.h>
int main(void)
{
    int true_val, false_val;
    
    true_val = (10 > 2);    // value of a true relationship
    false_val = (10 == 2);  // value of a false relationship 
    printf("true = %d; false = %d \n", true_val, false_val);
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch06$ clang t_and_f.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
true = 1; false = 0 

6.3.2 其他真值

// truth.c -- what values are true?
#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;
}
[wlsh@wlsh-MacbookPro] ch06$ clang truth.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
 3 is true
 2 is true
 1 is true
 0 is false
-3 is true
-2 is true
-1 is true
 0 is false

从数值方面而不是从真/假方面来看测试条件。以下两种情况都是goal是0时才为假。

while(goats != 0) //初学者
while(goats) //常用

6.3.3 真值的问题

// trouble.c -- misuse of =
// will cause infinite loop
#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;
}
[wlsh@wlsh-MacbookPro] ch06$ clang trouble.c 
trouble.c:13:19: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
    while (status = 1)
           ~~~~~~~^~~
trouble.c:13:19: note: place parentheses around the assignment to silence this warning
    while (status = 1)
                  ^
           (         )
trouble.c:13:19: note: use '==' to turn this assignment into an equality comparison
    while (status = 1)
                  ^
                  ==

分析:while(status = 1)实际上相当于while(1),即循环不会退出,虽然用户输入q,status被设置为0,但是循环的测试条件把status又重置为1,进入下一代迭代。

canoes = 5  //把5赋给canoes
canoes == 5 //检查canoes的值是否为5

5 = canoes  //语法错误
5 == canoes //检查canoes的值是否为5

C语言不允许给常量赋值,编译器会把赋值运算符的这种用法作为语法错误标记出来。经验丰富的程序员在构建比较是否相等的表达式时,习惯把常量放在左侧。

6.3.4 新的Bool类型

// boolean.c -- using a _Bool variable
#include <stdio.h>
int main(void)
{
    long num;
    long sum = 0L;
    _Bool input_is_good;
    
    printf("Please enter an integer to be summed ");
    printf("(q to quit): ");
    input_is_good = (scanf("%ld", &num) == 1);
    while (input_is_good)
    {
        sum = sum + num;
        printf("Please enter next integer (q to quit): ");
        input_is_good = (scanf("%ld", &num) == 1);
    }
    printf("Those integers sum to %ld.\n", sum);
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch06$ clang boolean.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
Please enter an integer to be summed (q to quit): 123
Please enter next integer (q to quit): 23
Please enter next integer (q to quit): q
Those integers sum to 146.

在C语言中,用int类型的变量表示真/假。C99专门针对这种类型的变量新增_Bool类型。表示真或假的变量称为布尔变量(Boolean variable),如果把其他非零数值赋值给_Bool类型的变量,该变量设置为1。

C99提供stdbool.h头文件,该文件让bool成为_Bool的别名,而且还把true和false分别定义为1和0的符号常量,包含该文件后,写出的代码可以与C++兼容。

6.3.5 优先级和关系运算符

6.4 不确定循环和计数循环

不确定循环(indefinite loop)

计数循环(counting loop)

// sweetie1.c -- a counting loop
#include <stdio.h>
int main(void)
{
    const int NUMBER = 22;
    int count = 1;                     // initialization
    
    while (count <= NUMBER)            // test
    {
        printf("Be my Valentine!\n");  // action
        count++;                       // update count
    }
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch06$ clang sweetie1.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
Be my Valentine!
Be my Valentine!
Be my Valentine!
Be my Valentine!
Be my Valentine!
while (count++ <= NUMBER)

初始化计数器;计数器与有限值比较;每次循环递增计数器

递增发生在循环的末尾 vs 测试和更新放在一起

6.5 for循环

// sweetie2.c -- a counting loop using 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循环把(初始化、测试和更新)组合在一起。

#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;
}
[wlsh@wlsh-MacbookPro] ch06$ clang test.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
The ASCII value for a is 97.
The ASCII value for b is 98.
The ASCII value for c is 99.
The ASCII value for d is 100.
The ASCII value for e is 101.
The ASCII value for f is 102.
The ASCII value for g is 103.
The ASCII value for h is 104.
The ASCII value for i is 105.
The ASCII value for j is 106.
The ASCII value for k is 107.
The ASCII value for l is 108.
The ASCII value for m is 109.
The ASCII value for n is 110.
The ASCII value for o is 111.
The ASCII value for p is 112.
The ASCII value for q is 113.
The ASCII value for r is 114.
The ASCII value for s is 115.
The ASCII value for t is 116.
The ASCII value for u is 117.
The ASCII value for v is 118.
The ASCII value for w is 119.
The ASCII value for x is 120.
The ASCII value for y is 121.
The ASCII value for z is 122.

字符在内部是以整数形式存储的,该循环实际上仍是用整数来计数。

6.6 其他赋值运算符:+=、-=、*=、/=、%=

组合形式的负值运算符,代码更加紧凑,与一般形式相比,组合形式的运算符省车给你的机器代码更高效。

6.7 逗号运算符

// postage.c -- first-class postage rates
#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;
}
[wlsh@wlsh-MacbookPro] ch06$ clang postage.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
 ounces  cost
    1   $0.46
    2   $0.66
    3   $0.86
    4   $1.06
    5   $1.26
    6   $1.46

逗号表达式保证被分割的表达式从左往右求值。即逗号是一个序列点。

/* zeno.c -- series sum */
#include <stdio.h>

int main(void)
{
    int t_ct;       // term count
    double time, power_of_2;
    int limit;
    
    printf("Enter the number of terms 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;
}
[wlsh@wlsh-MacbookPro] ch06$ clang zeno.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
Enter the number of terms you want: 10
time = 1.000000 when terms = 1.
time = 1.500000 when terms = 2.
time = 1.750000 when terms = 3.
time = 1.875000 when terms = 4.
time = 1.937500 when terms = 5.
time = 1.968750 when terms = 6.
time = 1.984375 when terms = 7.
time = 1.992188 when terms = 8.
time = 1.996094 when terms = 9.
time = 1.998047 when terms = 10.

6.8 出口条件循环

C语言有出口条件循环(exit-condition loop),即在循环的每次迭代之后检车测试条件,保证至少执行循环体中的内容一次。

do
    statement
while(expression); //分号结尾

6.9 如何选择循环

确定是入口条件循环 还是 出口条件循环

while(scans("%ld",&num)==1)

涉及索引计数的循环,用for循环更合适

for(count = 1; count <= 100; count++)

6.10 嵌套循环

6.10.1 程序分析

6.10.2 嵌套变式

// rows2.c -- using dependent nested loops
#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;
}
[wlsh@wlsh-MacbookPro] ch06$ clang rows2.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
ABCDEF
BCDEF
CDEF
DEF
EF
F

6.11 数组简介

用于识别数组元素的数字被称为下标(subscript)、索引(indice)或偏移量(offset)

// scores_in.c -- uses loops for array processing
#include <stdio.h>
#define SIZE 10
#define PAR 72
int main(void)
{
    int index, score[SIZE];
    int sum = 0;
    float average;
    
    printf("Enter %d golf scores:\n", SIZE); //方便处理大小为size的数组
    for (index = 0; index < SIZE; index++)
        scanf("%d", &score[index]);  // read in the ten scores
    printf("The scores read in are as follows:\n");

    for (index = 0; index < SIZE; index++)
        printf("%5d", score[index]); // verify input
    printf("\n");

    for (index = 0; index < SIZE; index++)
        sum += score[index];         // add them up
    average = (float) sum / SIZE;    // time-honored method
    printf("Sum of scores = %d, average = %.2f\n", sum, average);
    printf("That's a handicap of %.0f.\n", average - PAR);
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch06$ clang scores_in.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
Enter 10 golf scores:
99 95 109 105 100
96 98 93 99 97 98
The scores read in are as follows:
   99   95  109  105  100   96   98   93   99   97
Sum of scores = 991, average = 99.10
That's a handicap of 27.

scanf()会跳过空白字符,使用空格或换行符隔开每个数字。因为输入是缓冲的只有当,用户Enter键数字后才会被发送给程序。

6.12 使用函数返回值的循环示例

6.12.1 程序分析

// power.c -- raises numbers to integer powers
#include <stdio.h>
double power(double n, int p); // ANSI prototype//编译器知道power()返回值类型,才知道有多少字节的数据,以及如何解释它们
int main(void)
{
    double x, xpow;
    int exp;
    
    printf("Enter a number and the positive integer power");
    printf(" to which\nthe number will be raised. Enter q");
    printf(" to quit.\n");
    while (scanf("%lf%d", &x, &exp) == 2)//成功读取2个值,则返回2
    {
        xpow = power(x,exp);   // function call
        printf("%.3g to the power %d is %.5g\n", x, exp, xpow);
        printf("Enter next pair of numbers or q to quit.\n"); //q与scanf()中的转换说明%lf不匹配,scanf()会使返回值为0 输入2.8 返回值为1
    }
    printf("Hope you enjoyed this power trip -- bye!\n");
    
    return 0;
}

double power(double n, int p)  // function definition
{
    double pow = 1;
    int i;
    
    for (i = 1; i <= p; i++)
        pow *= n;
    
    return pow;                // return the value of pow
}
[wlsh@wlsh-MacbookPro] ch06$ clang power.c 
[wlsh@wlsh-MacbookPro] ch06$ ./a.out 
Enter a number and the positive integer power to which
the number will be raised. Enter q to quit.
1.2 12
1.2 to the power 12 is 8.9161
Enter next pair of numbers or q to quit.
q
Hope you enjoyed this power trip -- bye!

6.12.2 使用带返回值的函数

为什么在使用scanf()的返回值之前没有声明scanf() ? 为什么在定义中说明了power()的返回类型为double,还要单独声明这个函数?

6.13 关键概念

6.14 本章小结

猜你喜欢

转载自blog.csdn.net/qq_24990189/article/details/90081972