栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

The C Programming Language(第 2 版) 笔记 / 3 控制流 / 3.5 while 循环与 for 循环

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

The C Programming Language(第 2 版) 笔记 / 3 控制流 / 3.5 while 循环与 for 循环

目录


3.5 while 循环与 for 循环

while 循环语句

while (表达式) 
    语句

首先求表达式的值,如果其值非 0,则执行语句,并再次求该表达式的值
这一循环过程一直进行下去,直到该表达式的值为 0 为止,随后继续执行语句后面的部分

for 循环语句

for (表达式 1; 表达式 2; 表达式 3) 
    语句

它等价于下边的 while 语句:

表达式 1; 
while (表达式 2) { 
    语句
    表达式 3; 
}

但当 while 或 for 循环语句中包含 continue 语句时,上述二者之间就不一定等价了
3.7 节介绍 continue 语句

从语法角度看,for 循环语句的 3 个组成部分都是表达式
最常见的情况是,表达式 1 与表达式 3 是赋值表达式或函数调用,表达式 2 是关系表达式
这 3 个组成部分中的任何部分都可以省略,但分号必须保留
如果在 for 语句中省略表达式 1 与表达式 3,它就退化成了 while 循环语句
如果省略测试条件,即表达式 2,则认为其值永远是真值
因此,下列 for 循环语句是一个 “ 无限 ” 循环语句:

for (;;) { 
    ... 
}

这种语句需要借助其它手段(如 break 语句或 return 语句)才能跳出循环

在设计程序时到底选用 while 循环语句还是 for 循环语句,主要取决于程序设计人员的个人偏好
例如,在下列语句中:

while ((c = getchar()) == ' ' || c == 'n' || c = 't') 
    ; 

因为其中没有初始化或重新初始化的操作,所以使用 whi1e 循环语句更自然一些

如果语句中需要执行简单的初始化和变量递增,使用 for 语句更合适一些
它将循环控制语句集中放在循环的开头,结构更紧凑、更清晰
通过下列语句可以看出这一点:

for (i = 0; i < n; i++) 
    ...

这是 C 语言处理数组前 n 个元素的一种习惯性用法,它类似于 Fortran 语言中的 DO 循环或 Pascal 语言中的 for 循环
但是,这种类比并不完全准确,因为在 C 语言中 for 循环语句的循环变量和上限在循环体内可以修改
并且当循环因某种原因终止后循环变量 i 的值仍然保留
因为 for 语句的各组成部分可以是任何表达式,所以 for 语句并不限于通过等差数列进行循环控制
尽管如此,牵强地把一些无关的计算放到 for 语句的初始化和变量递增部分是一种不好的程序设计风格,该部分放置循环控制运算更合适

作为一个较大的例子,我们来重新编写将字符串转换为对应数值的函数 atoi
这里编写的函数比第 2 章中的 atoi 函数更通用,它可以处理可选的前导空白符以及一个可选的加(+)或减(-)号
第 4 章将介绍函数 atof,它用于对浮点数执行同样的转换

下面是程序的结构,从中可以看出输入的格式:

如果有空白符的话,则跳过
如果有符号的话,则读取符号
取整数部分,并执行转换

其中的每一步都对输入数据进行相应的处理,并为下一步的执行做好准备。当遇到第一个不 能转换为数字的字符时,整个处理过程终止

#include  
 
int atoi(char s[]) 
{ 
    int i, n, sign; 
    for (i = 0; isspace(s[i]); i++)  
        ; 
    sign = (s[i] == '-') ? -1 : 1; 
    if (s[i] == '+' || s[i] == '-')  
        i++; 
    for (n = 0; isdigit(s[i]); i++) 
        n = 10 * n + (s[i] - '0'); 
    return sign * n; 
}

标准库中提供了一个更完善的函数 strtol,它将字符串转换为长整型数
有关函数 strtol 的详细信息,请参见附录 B.5 节

把循环控制部分集中在一起,对于多重嵌套循环,优势更为明显
下面的函数是对整型数组进行排序的 Shell 排序算法
Shell 排序算法是 D. L. Shell 于 1959 年发明的
其基本思想是:先比较距离远的元素,而不是像简单交换排序算法那样先比较相邻的元素
这样可以快速减少大量的无序情况,从而减轻后续的工作
被比较的元素之间的距离逐步减少,直到减少为 1,这时排序变成了相邻元素的互换

 
void shellsort(int v[], int n) 
{ 
    int gap, i, j, temp; 
    for (gap = n / 2; gap > 0; gap /= 2) 
        for (i = gap; i < n; i++) 
            for (j = i - gap; j >= 0 && v[j] > v[j + gap]; j -= gap) { 
                temp = v[j]; 
                v[j] = v[j + gap]; 
                v[j + gap] = temp; 
            }
}

该函数中包含一个三重嵌套的 for 循环语句
最外层的 for 语句控制两个被比较元素之间的距离,从 n/2 开始,逐步进行对折,直到距离为 0
中间层的 for 循环语句用于在元素间移动位置
最内层的 for 语句用于比较各对相距 gap 个位置的元素,当这两个元素逆序时把它们互换过来
由于 gap 的值最终要递减到 1,因此所有元素最终都会位于正确的排序位置上
注意,即使最外层 for 循环的控制变量不是等差数列,for 语句的书写形式仍然没有变,这就说明 for 语句具有很强的通用性

逗号运算符 , 也是 C 语言优先级最低的运算符,在 for 语句中经常会用到它
被逗号分隔的一对表达式将按照从左到右的顺序进行求值,表达式右边的操作数的类型和值即为其结果的类型和值
这样,在 for 循环语句中,可以将多个表达式放在各个语句成分中
比如同时处理两个循环控制变晕
我们可以通过下面的函数 reverse(s) 来举例,该函数用于倒置字符串 s 中各个字符的位置

#include  
 
void reverse(char s[]) 
{ 
    int c, i, j; 
    for (i = 0, j = strlen(s) - 1; i < j; i++, j--) { 
        c = s[i]; 
        s[i] = s[j]; 
        s[j] = c; 
    } 
}

某些情况下的逗号并不是逗号运算符,比如分隔函数参数的逗号,分隔声明中变量的逗号等
这些逗号并不保证各表达式按从左至右的顺序求值

应该慎用逗号运算符
逗号运算符最适用于关系紧密的结构中,比如上面的 reverse 函数内的 for 语句
对于需要在单个表达式中进行多步计算的宏来说也很适合
逗号表达式还适用于 reverse 函数中元素的交换,这样,元素的交换过程便可以看成是一个单步操作

for (i = 0, j = strlen(s) - 1; i < j; i++, j--) 
    c = s[i], s[i] = s[j], s[j] = c;

目录

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/935095.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号