C语言学习笔记(十九)

C语言学习第十九天。

2.10 赋值运算符与表达式
在赋值表达式中,如果表达式左边的变量重复出现在表达式的右边,如:

    i = i + 2;

则可以将这种表达式缩写为下列形式:

    i += 2;

其中的运算符+=称为赋值运算符。
大多数二元运算符(即有左、右两个操作数的运算符,比如+)都有一个相应的赋值运算符op=,其中op可以时下面这些运算符之一:

    + - * / % << >> & ^ |

如果expr1和expr2是表达式,那么

    expr1 op= expr2

等价于:

    expr1 = (expr1) op (expr2)

它们的区别再与,前一种形式expr1只计算一次。注意,在第二种形式中,expr2两边的圆括号是必不可少的,例如

    x *= y + 1

的含义是

    x = x * (y + 1)

而不是

    x = x * y + 1

下面的函数bitcount统计其整型参数的值为1的而进制位的个数。

/* bitcount函数:统计x中值为1的二进制位数 */
int bitcount(unsigned x) {
    int b;
    for(b = 0; x != 0; x >>= 1)
        if (x & 01)
            b++;
    return b;
}

这里将x声明为无符号类型是为了保证将x右移时,无论该程序在什么机器上运行,左边空出的位都用0(而不是符号位)填补。
除了简洁外,赋值表达式的表示方式与人们的思维习惯比较接近。我们通常会说“把2加到i上”或“把i增加2”,而不会说“取i的值,加上2,再把结果放回的i中”,因此,表达式i+=2比i=i+2更自然。另外,对于复杂的表达式,例如:

    yyval[yypv[p3+p4] + yypv[p1+p2]] += 2;

赋值运算符使程序代码更易于理解,代码的阅读者不必煞费苦心地取检查两个长表达式是否完全一样,也无需为两者为什么不一样而疑惑不解。并且,赋值运算符还有助于编译器产生高效代码。

练习 2-9: 在求对二的补码时,表达式x&=(x-1)可以删除x中最右边值为1的一个二进制位。请解释这样做的道理。用这一方法重写bitcount函数,以加快其执行速度。

_____________________________________________________________________________________________________
    x-1就相当于x最右边为1的哪一项变成0,后面的项都变成1,这样求按位与,就会把最右边为1后面的位全置0.
例如:
    x: 111,那么x-1: 110,x&(x-1): 110
    x: 110,那么x-1: 101,x&(x-1): 100
    x: 100,那么x-1: 011,x&(x-1): 000
三个1,执行了三次;

/* bitcount1函数:统计x中值为1的二进制位数,使用x&(x-1) */
int bitcount1(unsigned x) {
    int b;
    if(x >= 1)
        b++; // x大于1必然有1位,弥补x&=(x-1)最后等于0的那次
    while(x &= (x-1))
        b++;
    return b;
}
_____________________________________________________________________________________________________

2.11 条件表达式

下面这组语句:

    if (a > b)
        z = a;
    else
        z = b;

用于求a与b中的最大值,并将结果保存到z中,条件表达式(使用三元运算符“”)提供了另外一种方法编写这段程序及类似的代码段。在表达式

    expr1 ? expr2: expr3

中,首先计算expr1,如果其值不等于0(为真),则计算expr2的值,并以该值作为条件表达式的值,否则计算expr3的值,并以该值作为条件表达式的值。expr2与expr3中只有一个表达式被计算。因此,以上语句可以改写为:

    z = (a > b) ? a : b;    /* z = max(a, b) */

条件表达式实际上时一种表达式,它可以用在其他表达式可以使用的任何地方。如果expr1与expr3的类型不同,结果的类型将由本章前面讨论的转换规则决定。例如,如果f为float类型,n为int类型,那么表达式

    (n > 0) ? f : n

是float类型,与n是否为正值无关。
条件表达式中第一个表达式两边的圆括号并不是必须的,这是因为条件运算符?:的优先级非常低,仅高于赋值运算符。但我们还是建议使用圆括号,因为这可以使表达式条件部分更易于阅读。
采用条件表达式可以编写出很简洁的代码。例如下面这个循环语句打印一个数组的n个元素,每行打印10个元素,每列之间用一个空格隔开,每行用一个换行符结束(包括最后一行):

    for (i = 0; i < n; i++)
        printf("%6d%c", a[i], (i%10==9 || i==n-1) ? '\n' : ' ');

在每10个元素之后以及在第n个元素之后都要打印一个换行符,所有其他元素后面都要打印一个空格。编写这样的代码可能需要一些技巧,但比用等价的if-else结构编写的代码要紧凑一些。下面是另一个 比较好的例子:

    printf("You have %d item%s.\n", n, n==1 ? "" : "s");

练习2-10 重新编写将大写字母转换为小写字母的函数lower,并用条件表达式替代其中的if-else结构。

________________________________________________

int lower1(int c) {
    return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
}

________________________________________________

你可能感兴趣的:(C语言,c语言,学习,开发语言)