第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)); }

浙公网安备 33010602011771号