C语言学习笔记(二二)

C语言学习第二十二天。

3.5 while循环与for循环
在while循环语句

    while (表达式)
        语句

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

    for循环语句

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

    它等价于下列while语句:

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

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

    for (; ;) {
        ...
    }

是一个“无限”循环语句,这种语句需要借助其他手段(如break语句或return语句)才能终止。

如何选择主要取决于个人偏好。例如,在下列语句中:

    while ((c = getchar()) == ' ' || c == '\n' || c == '\t')
        ; /* 跳过空白符*/

因为其中没有初始化或重新初始化的操作,所以使用while循环语句更自然一些。
如果语句中需要执行简单的初始化和变量递增,使用for语句更合适一些,它将循环控制语句集中放在循环的开头,结构更紧凑、更清晰。 例如:

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

这是C语言处理数组前n各元素的一种习惯性用法。

下面是将字符串转换为对应数值的函数atoi。它可以处理可选的前导空白符以及一个可选的加(+)或减(-)号。
下面是程序结构,从中可以看出输入的格式:

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

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

#include <stdio.h>
#include <ctype.h>

int main() {
    printf("%d", atoi("     -123xf2"));
}

/* atoi函数:将s转换为整数型;*/
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;
}

标准库中提供了一个更完善的函数strol, 它将字符串转换为长整型。

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

#include <stdio.h>

void shellsort(int v[], int n);

int main() {
    int a[] = {3, 5, 62, 4, 6, 32 , 6};
    int i = 0;
    shellsort(a, 7);
    for (; i < 7; i++)
        printf("%d ", a[i]);
}

/* shellsort函数:按递增顺序对v[0]...v[n-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 <stdio.h>
#include <string.h>

void reverse(char s[]) ;
int main() {
    char a[] = "warning!";
    reverse(a);
    printf("%s", a);
}

/* reverse函数:倒置字符串s中各个字符的位置 */
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;

练习 3-3 编写函数expand(s1, s2) ,将字符串s1中类似于a-z一类的速记符号在字符串s2中扩展为等价的完整列表abc...xyz.该函数可以处理大小写字母和数字,并可以处理a-b-c、a-z0-9于-a-z等类似的情况。作为前导和尾随的-字符原样排印。

#include<stdio.h>

void expand(char s1[], char s2[]);

int main() {
    char s1[] = "-a-z0-9a-b-c";
    char s2[100];

    expand(s1, s2);
    printf("%s", s2);
}


void expand(char s1[], char s2[]) {
    int i, j, k;

    i = j = k = 0;
    while(s1[i] != '\0') {
        if (i > 0 && s1[i] == '-') {
            for (k = 0; k < s1[i+1] - s1[i-1]; k++)
                s2[j++] = s1[i-1] + k + 1;
            i++;
        } else {
            s2[j++] = s1[i];
        }
        i++;
    }
    s2[j] = '\0';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值