第2章 类型、运算符与表达式

练习 2-2 使用逻辑运算符修改 for循环

原来的循环
for (int i = 0; i < limit-1 && (c=getchar()) != '\n' && c != EOF; i++)
    s[i] = c;

答案中的循环
int flag = 0, i = 0;
while (flag) {
    if (i >= limit - 1)                flag = 1;
    else if ((c=getchar()) == '\n')    flag = 1;
    else if (c == EOF)                 flag = 1;
    else                             s[i++] = c;
}

自己写的, 如果可以用 break
for (int ix = 0; ix < limit - 1; ix++) {
    if ((c=getchar()) == '\n')    break;
    if (c == EOF)                 break;
    s[i] = c;
}

2.7 类型转换
之后的章节中,对atoi() 进行了多次优化,如下是第一版

int atoi(char s[]) {
    int n = 0;
    for (int i = 0; s[i] >= '0' && s[i] <= '9'; i++) {
                n = 10 * n + s[i] - '0';
    }
        return n;
}

 2.8 自增运算符和自减运算符

删除字符串s中的所有字符c

void squeeze(char s[], int c) {
    for (int ix = 0, jx = 0; s[ix]; ix++) {
        if (c != s[ix])
            s[jx++] = s[ix];
    }
    s[jx] = 0;
}

拼接字符串

void strcat(char s[], char t[]) [
    int ix = 0, jx = 0;
    for (; s[ix]; ix++); //到达s的末尾
    while (s[ix++] = t[jx++]); // 此时,s[ix-1] = '\0';
}

 2.9 按位运算符

按位与运算符&经常用于屏蔽某些二进制位,例如:n = n & 0177
该语句将n中低7位保持不变,其他位都设置为0

按位或运算符|经常用于将某些二进制位置1,例如:n = n & 0x0F
该语句将n中低4位置1,其他位保持不变

^ 异或运算符可以让对应位取反, 例如n = n^0x0F
n的低4位会取反,高四位保持不变

?&0 = 0 置0
?&1 = ? 不变化
?|0 = ? 不变化
?|1 = 1 置1
?^0 = ? 不变化

移位运算符>>和<<在有些机器上会算术移位,有些是逻辑移位(空出的位用0填补)

~取反运算符,~0 = 0xFF

函数getbits(x, p, n), 它返回x中从右边数第p位开始向右数n位的字段。这里假定最右边的一位是第0位,n与p都是合理的正值。
例如,getbits(x, 4, 3)返回x中第4、3、2三位的值

unsigned getbits(unsigned char x, int p, int n) {
    return x >> (p + 1 - n) && ~(~0 << n); 
}

获取一个数的低n位,可以先设置mask = ~(~0 << n),然后
x &= mask, 就可以获取低n位,高位已经是0

练习2-6 编写一个函数 setbits(x, p, n, y), 该函数返回对x执行下列操作后的结果:将x中从
第p位开始的n个(二进制)位设置为y中最右边n位的值,x的其余位保持不变。

#include <stdio.h>
#include <assert.h>
unsigned setbits(unsigned x, int p, int n, unsigned y) {
    return x & ~(~(~0<<n) << (p + 1 -n)) | (y & ~(~0 << n)) << (p+1 -n); // 移位的优先级高于 & |
}
void main() {
    assert(0x14 == setbits(0x0, 4, 3, 0x5));  printf("0x14 == setbits(0x0, 4, 3, 0x5)\n");
    assert(0x1C == setbits(0x0, 4, 3, 0x7));  printf("0x1C == setbits(0x0, 4, 3, 0x7)\n");
}

练习2-7 编写一个函数 invert(x, p, n), 该函数返回对x执行 下列操作之后的结果值:将x中从第P位开始的n个(二进制)位求反(即 1变成0, 0变成1),x的其余位保持不变

#include <stdio.h>
#include <assert.h>

unsigned invert(unsigned x, int p, int n) {
    return x ^ (~(~0 << n) << (p + 1 - n));
}

void main() {
    assert(0x5A == invert(0x66, 5, 4));  printf("0x5A == invert(0x66, 5, 4)\n");
}

练习 2-8 编写一个函数rightrot(x, n), 该函数返回将x循环右移(即从最右端移出的位将从最左端再移入)n位后所得的值 

#include <stdio.h>
#include <assert.h>

unsigned rightrot(unsigned x, int n) {
        unsigned mask, size = sizeof(x) * 8;
        while (n-- > 0) {
                mask = (x & 1) << (size - 1);
                x = (x >> 1) | mask;
        }
        return x;
}

void main() {
    assert(0xc0003fff == rightrot(0x0000FFFF, 2));
    assert(0xc000003f == rightrot(0x00FF,     2));
    assert(0x40000000 == rightrot(1,          2));
}

思考题:如果n是很大的数值,是否需要移位 n 次?如果 n = 7, 是否可以一下移动 7位?如下是优化后的处理

#include <stdio.h>
#include <assert.h>

int wordlength() {
    unsigned x = (unsigned)~0;
    int cnt = 1; // 默认x 一定大于0
    for (; (x>>=1) > 0; cnt++);
    return cnt;
}

unsigned rightrot(unsigned x, int n) {
    unsigned bits, size = wordlength();
if ((n %= size) > 0) { bits = ~(~0 << n) & x; // 取出x的低 n 位 bits <<= size - n; x = (x >> n) | bits; } return x; } void main() { assert(0xc0003fff == rightrot(0x0000FFFF, 2)); assert(0x40000000 == rightrot(1, 2)); assert(0x0000ffff == rightrot(0x0000FFFF, 128)); assert(0xff0000ff == rightrot(0x0000FFFF, 1000)); }

 

posted @ 2025-02-25 15:46  靖意风  Views(10)  Comments(0)    收藏  举报