-
Lesson 1 - 最简单的C程序
-
Lesson 2 - 打印输出
-
Lesson 3 - 循环打印
-
Lesson 4 - 判断奇偶
-
Lesson 5 - 从1加到100求和
-
Lesson 6 - 乘法表
-
Lesson 7 - 求100以内的最大素数
-
Lesson 8 - 1到100有多少个9
-
Lesson 9 - 整型转字符串
-
Lesson 10 - 约瑟夫环
-
Lesson 11 - 求两个坐标点之间的距离
-
Lesson 12 - 判断机器存储是否小尾端
-
Lesson 13 - 对不起,你的车今天限行
-
Lesson 14 - 判断地图上某点是否有出路
-
Lesson 15 - 统计一个数二进制表示中1的个数
-
Lesson 16 - 字符串拷贝
-
Lesson 17 - 统计单词个数
-
Lesson 18 - 实现 printf
-
Lesson 19 - 命令解释器
-
Lesson 20 - 预处理器实现
-
Lesson 21 - 词法分析器实现
-
Lesson 22 - 猜数游戏
-
Lesson 23 - 五子棋
-
Lesson 24 - 超链接分析器
-
Lesson 25 - cp命令实现
-
Lesson 26 - ELF文件头分析器实现
-
Lesson 27 - 简单流处理器实现和正则表达式
-
Lesson 28 - 数学计算器实现
-
Lesson 29 - 数学计算器实现more命令实现
-
Lesson 30 - sort命令实现
-
Lesson 31 - ls -l命令实现
-
Lesson 32 - Bash项目
-
Lesson 33 - 动态数组实现
-
Lesson 34 - 约瑟夫环问题
-
Lesson 35 - 表达式求值问题
-
Lesson 36 - 广度优先解决迷宫问题
-
Lesson 37 - 词频统计器
-
Lesson 38 - 堆排序问题
-
Lesson 39 - 构造符号表
-
Lesson 40 - MyDictionary项目
-
Lesson 41 - BSearch 实现
-
Lesson 42 - QSort 实现
-
Lesson 43 - 深度优先解决迷宫问题
-
Lesson 44 - KMP 算法实现
-
Lesson 45 - 最长公共子序列(LCS)问题
-
Lesson 46 - Dijkstra 算法
-
Lesson 47 - Huffman Coding 算法
-
Lesson 48 - 地图导航项目
Lesson 15 Count bit 1 in a number 统计一个数二进制表示中1的个数
#include <stdio.h>
int count_bit_1(int n)
{
unsigned int i;
int counter = 0;
for(i = 0; i < sizeof(int) * 8; i++)
{
if((n >> i) & 0x01)
counter++;
}
return counter;
}
int main(int argc, char *argv[])
{
int num;
printf("please input a number:");
scanf("%d", &num);
printf("number in hex is 0x%x\n", n);
printf("%d bit '1' in %d\n", count_bit_1(num), num);
return 0;
}
copy
第2种算法--消去最左侧的1
#include <stdio.h>
int count_bit_1(int n)
{
int counter;
for (counter = 0; n; counter++)
n &= n-1;
return counter;
}
int main(int argc, char *argv[])
{
int num;
printf("please input a number:");
scanf("%d", &num);
printf("number in hex is 0x%x\n", num);
printf("%d bit '1' in %d\n", count_bit_1(num), num);
return 0;
}
copy
第3种算法--二进制数内的加法
#include <stdio.h>
//types and constants used in the functions below
typedef unsigned int uint32; //assume this gives 32-bits
const uint32 m1 = 0x55555555; //binary: 0101...
const uint32 m2 = 0x33333333; //binary: 00110011..
const uint32 m4 = 0x0f0f0f0f; //binary: 4 zeros, 4 ones ...
const uint32 m8 = 0x00ff00ff; //binary: 8 zeros, 8 ones ...
const uint32 m16 = 0x0000ffff; //binary: 16 zeros, 16 ones ...
const uint32 h01 = 0x01010101; //the sum of 256 to the power of 0,1,2,3...
//This is a naive implementation, shown for comparison,
//and to help in understanding the better functions.
//It uses 24 arithmetic operations (shift, add, and).
int count_bit_1(unsigned int x)
{
x = (x & m1 ) + ((x >> 1) & m1 ); //put count of each 2 bits into those 2 bits
x = (x & m2 ) + ((x >> 2) & m2 ); //put count of each 4 bits into those 4 bits
x = (x & m4 ) + ((x >> 4) & m4 ); //put count of each 8 bits into those 8 bits
x = (x & m8 ) + ((x >> 8) & m8 ); //put count of each 16 bits into those 16 bits
x = (x & m16) + ((x >> 16) & m16); //put count of each 32 bits into those 32 bits
return x;
}
int main(int argc, char *argv[])
{
int num;
printf("please input a number:");
scanf("%d", &num);
printf("number in hex is 0x%x\n", num);
printf("%d bit '1' in %d\n", count_bit_1(num), num);
return 0;
}
copy
知识点
- 位操作 &, |, ~, ^
- 设置位 set bit
a |= 1<<4; - 清除位 clear bit
a &= ~(1<<4); - 测试位 test bit
if (a & (1<<31)) - 设置位域 set bit-field
a &= ~(0x7<<28); a |= 0x5<<28; - 获取位域 get bit-field
if (((a>>28) & 0x7) == 0x5)
- 设置位 set bit
- 常见操作
- 不要把 &, | 混淆为 &&, ||
1 & 1 == 1 && 1 1 & 2 == 0 但是 1 && 2 == ture 同理类似的 5 & 10 == 0 - 取反操作用来构造数
0xFFFFFFFF == ~0x0 0xFFFFFFE0 == ~0x1F - 运算符&,^,| 的优先级比<,>关系运算符和判等运算符 == 要低
举例:
int status = 0;
if (status & 0x4000 == 0) // 条件成立,还是不成立?
- 不要把 &, | 混淆为 &&, ||
- 优化算法效率 http://hi.baidu.com/bobchennan/item/169952dc515045e4795daa10
n & n-1 妙用
二进制数内的加法
课堂讨论
- 与第1个算法相比,第2个算法有什么优点?
- 第3个算法的时间复杂度是多少? 它背后的思想是什么?
课后练习
请写出可以进行位操作的 set_bit, get_bit 接口
- set_bit(int num, int pos, int v);
- get_bit(int num, int pos);
用位运算实现字符的大小写转换 (两种方法:异或,测试后修改)
- 要求:输入大写的字符转为小写,输入小写的字符转为大写;
用位运算实现对一个无符号整型的二进制打印,八进制打印,十六进制打印
要求:
int print_bin(int a);
int print_oct(int a);
int print_hex(int a);a = 31
二进制打印 0000 0000 ... 0001 1111
八进制打印 0 0 0 ... 0 3 7
十六进制打印 00 00 00 1FBit-Field 位域操作
include <stdio.h>
struct flag { unsigned int is_keyword : 1; unsigned int is_extern : 1; unsigned int is_static : 1; unsigned int is_mid : 4; unsigned int is_high : 1; unsigned int is_highest : 30; } flags;
int main( int argc, char * argv[] ) { printf( "hello, Cruel World! \n" );
flags.is_keyword = 1; flags.is_extern = 1; flags.is_high = 1;
flags.is_mid = 2;
printf( "flags = 0x%x \n", flags ); printf( "sizeof flags = 0x%x \n",sizeof(flags) );
return 0; }
扩展应用
/* include/linux/tcp.h */
struct tcphdr {
__be16 source;
__be16 dest;
__be32 seq;
__be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
__be16 window;
__sum16 check;
__be16 urg_ptr;
};
copy
知识点
- 位域 bit-field
- 大端和小端 Big-Endian/Little-Endian
课堂讨论
- 位域和之前学过的结构体,有何异同之处?
- 位域在哪些场合下可以适用?
- 码流结构 stream
- 传输协议结构 protocal
- 特殊功能寄存器设置 SFR
课后练习
- 用位域操作实现随机生成无重复的10个数字,要求不允许使用数组
- 提示:随机数用 rand() 函数,用一个整型数的bit0-bit9来记录已经产生的数字
名人名言
- Donald Ervin Knuth
- Premature optimization is the root of all evil. (过早优化是万恶之源)