目录
一、C语言通识
二、数据类型和运算符
三、位运算
四、进制转换
五、进制转换方法
一、C语言通识
1. C语言是⼀种(结构化的程序设计语言),它强调(模块化)和(层次化)的程序设计方法,通过 (函数)将程序分解为小的、易于管理的模块,每个模块完成特定的任务,从而提高代码的(可读性)、(可维护性)和(可重用性)。
2. C程序的执行总是从(main函数)开始, main 函数是C程序的(入口点),操作系统通过调用
main 函数来启动程序。 main 函数通常负责程序的(初始化)、(调用其他函数)以及(返回
程序的退出状态)。
3. 每个C程序必须有且仅有⼀个(main函数), main 函数是程序的(唯⼀入口),如果缺少
main 函数,编译器将无法找到程序的起始位置。如果存在多个 main 函数,编译器将无法确定
应该从哪个函数开始执行,从而导致(编译错误)。
4. C语言(区分大小写),C语言将(大写字母)和(小写字母)视为不同的字符。这意味着(变量名)、(函数名)、(关键字)等的大小写必须严格⼀致,否则编译器将无法识别。
5. C语言语句以(分号;)结束,分号是C语言语句的(结束符),用于告诉编译器⼀条语句的结束位置。缺少分号会导致(编译错误)。一些语句,如(预处理指令)和(复合语句),不需要以分号结尾。
6. 注释用于(解释代码), // 为(单行注释), /* */ 为(多行注释)。注释是程序员用来解释
代码的文本,编译器会忽略注释。良好的注释可以提高代码的(可读性)和(可维护性)。
7. 预处理指令以(#)开头,预处理指令是在(编译之前)由预处理器处理的指令。预处理器负责处理(头文件包含)、(宏定义)、(条件编译)等任务。
8. (#include)用于(包含头文件), #include 指令用于将头文件的内容包含到当前源⽂件中。
头⽂件通常包含(函数声明)、(宏定义)、(类型定义)等信息,使得程序可以使用这些功能。
9. (#define)用于(定义宏), #define 指令用于定义宏,宏可以是(对象宏)或(函数宏)。
对象宏用于定义常量,函数宏用于定义简单的函数。
10. 头文件通常包含(函数声明)和(宏定义),头文件是包含函数声明、宏定义、类型定义等信息的文件,用于在多个源文件中(共享这些信息)。
二、数据类型和运算符
11. char 类型通常用于存储(ASCII字符), char 类型占用(1个字节)的内存空间,可以存储范
围(-128到127)之间的整数,或者(0到255)之间的无符号整数。
12. int 类型的大小取决于(编译器)和(操作系统), int 类型用于存储整数,通常为(4个字
节)或(2个字节)。可以使用(sizeof(int))运算符获取 int 类型的大小。
13. float 类型提供(单精度浮点数), float 类型用于存储带有小数部分的数值,通常占用(4
个字节)的内存空间,可以表示大约(6到7位)有效数字。
14. double 类型提供(双精度浮点数),(精度更高), double 类型用于存储带有小数部分的
数值,通常占用(8个字节)的内存空间,可以表示大约(15到16位)有效数字。
15. long double 类型提供(扩展精度浮点数), long double 类型的大小和精度取决于(编
译器)和(操作系统),通常比 double 类型(更大)、(精度更高)。
16. 短整型 short 通常占用(2个字节), short 类型用于存储整数,可以存储(-32768到
32767)之间的整数,或者(0到65535)之间的无符号整数。
17. 长整型 long 通常占用(4个字节), long 类型用于存储整数,可以存储(-2147483648到
2147483647)之间的整数,或者(0到4294967295)之间的无符号整数。
18. 长整型 long long 通常占用(8个字节), long long 类型用于存储整数,可以存储(非
常大的整数)。
19. 无符号整数类型使用(unsigned)关键字, unsigned 关键字用于修饰整数类型,表示(无符
号整数)。
20. 无符号整数(不能表示负数),无符号整数只能存储(非负整数)。
21. 可以使用(十六进制:0x开头)或(八进制:0开头)表示整数,例如, 0x1A 表示十进制的
26, 032 表示十进制的26。
22. 浮点数可以使用(科学计数法)表示,例如, 1.23e4 表示1.23乘以10的4次方,即12300。
23. 字符常量可以使用(ASCII码)表示,例如, '\65' 表示字符 'A' ,因为 'A' 的ASCII码是
65。
24. 字符串常量是(字符数组),以(空字符\0)结尾,例如, "Hello" 实际上是⼀个包含 'H' ,
'e' , 'l' , 'l' , 'o' , '\0' 的字符数组。
25. 字符串常量存储在(只读内存区域),这意味着程序不能修改字符串常量的内容。
🖐 了解即可
1. 可以使用( L 前缀)表示宽字符常量,如 L'A' ,宽字符类型是 wchar_t ,用于表示
(Unicode字符)。
2. 可以使用( u 前缀)表示UTF-16字符常量,如 u'A' (C11标准),UTF-16是⼀种
Unicode编码方式。
3. 可以使用( U 前缀)表示UTF-32字符常量,如 U'A' (C11标准),UTF-32是另⼀种
Unicode编码方式。
4. 可以使用( R 前缀)表示原始字符串常量,避免转义字符,如 R"
(Hello\nWorld)" (C11标准),原始字符串常量中的 \n 不会被解释为换行符。
26. 算术运算符
◦ 包含:+(加)、-(减)、*(乘)、/(除)、%(取余)、++(自增)、--(自减)
◦ 特点:用于数值计算,如a=5/2结果为2(整数除法),%仅用于整数。
27. 赋值运算符
◦ 基本形式:=(简单赋值),以及+=、-=、*=等复合赋值(如a+=5等价于a=a+5)
◦ 特性:右结合性,例如a=b=c=5从右向左赋值。
28. 关系运算符
◦ 包含:>(大于)、<(小于)、==(等于)、!=(不等于)、>=(大于等于)、<=(小于等
于)
◦ 作用:比较操作数大小,结果为逻辑值(0或1),如5>3返回1。
29. 逻辑运算符
◦ 包含:&&(逻辑与)、||(逻辑或)、!(逻辑非)
◦ 短路特性:&&左操作数为假时右操作数不执行,||左操作数为真时右操作数不执行。
30. 位运算符
◦ 包含:&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移)、>>(右
移)
◦ 用途:直接操作二进制位,如a<<2表示将a的二进制左移两位。
31. 条件运算符(三目运算符)
◦ 形式:表达式1 ? 表达式2 : 表达式3
◦ 规则:若表达式1为真,返回表达式2的值,否则返回表达式3的值,如a>b ? a : b。
32. 其他特殊运算符
◦ sizeof:计算变量或类型的字节数,如sizeof(int)结果为4。
◦ 逗号运算符:连接多个表达式,最终结果为最后⼀个表达式值,如a=(x=3, y=5)时a=5。
🖐 按操作数数目分类
一元运算符
◦ 特点:仅需一个操作数,如 ++ 、 -- 、 ! (逻辑⾮)、 ~ (按位取反)。
二元运算符
◦ 特点:需两个操作数,如 + 、 - 、 && 、 || 等,占运算符的绝大多数。
三元运算符
◦ 唯一代表:条件运算符 ?: ,如 a>b ? a : b 。
33. 运算符优先级最高的是(一元运算符),如 ++ 、 -- 、 ! 等,其次是(算术运算符),最后是
赋值运算符。
34. 自增/自减运算符 ++ 、 -- 的前置与后置区别:(前置先运算后赋值,后置先赋值后运算),例
如 a=3; b=++a; 结果为 a=4,b=4 。
35. 逻辑运算符 && 和 || 具有(短路特性),若左操作数已确定结果,则右操作数不执行。
36. 条件运算符 ? : 是唯一的三目运算符,结合方向为(右→左),例如 a>b ? a : c>d ? c
: d 等价于 a>b ? a : (c>d ? c : d) 。
37. 逗号运算符 , 优先级(最低),整个表达式值为最后一个子表达式结果,例如 a=(x=3,y=5)
时 a=5 。
38. 赋值运算符 = 结合方向为(右→左),连续赋值时先计算右侧表达式,例如 a=b=c=5 等价于
a=(b=(c=5)) 。
39. 位运算符中, << 左移右侧补0, >> 右移补符号位(算术右移)或补0(逻辑右移,依赖编译
器)。
40. 运算符 sizeof 用于(计算变量或类型所占字节数),是编译时运算符,例如 sizeof(int)
结果为4。
41. 关系运算符 == 与赋值运算符 = 易混淆,建议将常量写在左边避免误用,例如 if(5==a) 。
42. 复合赋值运算符如 += 、 *= 等价于展开式,但(运算对象仅计算一次),例如 a*=b+1 等价
于 a=a*(b+1) 。
三、位运算
43. 位运算符用于(直接操作整数在内存中存储的二进制位)
44. & 运算符是(按位与),它会将两个操作数的对应位进行比较,只有当两个操作数对应位都为 1 时,结果的对应位才为 1,否则为 0。
🖐 例子: 假设有两个整数 a = 5 和 b = 3 ,它们的二进制表示分别为 a = 00000101
和 b = 00000011 (假设是 8 位整数)。
• a & b = 00000101 & 00000011 = 00000001 ,转换为十进制为 1。
• C代码示例:
int a = 5; // ⼆进制:00000101
int b = 3; // ⼆进制:00000011
int result = a & b; // result 的值为 1,⼆进制:00000001
printf("a & b = %d\n", result); // 输出:a & b = 1
45. | 运算符是(按位或),它会将两个操作数的对应位进行比较,只要两个操作数对应位中有⼀个为 1,结果的对应位就为 1,否则为 0。
🖐 例子: 假设有两个整数 a = 5 和 b = 3 ,它们的二进制表示分别为 a = 00000101
和 b = 00000011 (假设是 8 位整数)。
• a | b = 00000101 | 00000011 = 00000111 ,转换为十进制为 7。
• C代码示例:
int a = 5; // ⼆进制:00000101
int b = 3; // ⼆进制:00000011
int result = a | b; // result 的值为 7,⼆进制:00000111
printf("a | b = %d\n", result); // 输出:a | b = 7
46. ^ 运算符是(按位异或),它会将两个操作数的对应位进行比较,当两个操作数对应位不同时,结果的对应位为 1,相同时为 0。
🖐 例子: 假设有两个整数 a = 5 和 b = 3 ,它们的二进制表示分别为 a = 00000101
和 b = 00000011 (假设是 8 位整数)。
• a ^ b = 00000101 ^ 00000011 = 00000110 ,转换为十进制为 6。
• C代码示例:
int a = 5; // ⼆进制:00000101
int b = 3; // ⼆进制:00000011
int result = a ^ b; // result 的值为 6,⼆进制:00000110
printf("a ^ b = %d\n", result); // 输出:a ^ b = 6
47. ~ 运算符是(按位取反),它会将操作数的每⼀位进行取反,即 0 变为 1,1 变为 0。
注意: 在有符号整数中,取反会影响符号位,需要考虑补码表⽰。
🖐 例子: 假设有⼀个 8 位整数 a = 5 ,它的二进制表示为 a = 00000101 。
• ~a = ~00000101 = 11111010 ,转换为十进制为 -6(补码表示)。
• C代码示例:
int a = 5; // ⼆进制:00000101 (8位)
int result = ~a; // result 的值为 -6,⼆进制:11111010 (补码)
printf("~a = %d\n", result); // 输出:~a = -6
48. << 运算符是(左移),它会将操作数的二进制位向左移动指定的位数,右边补 0。左移⼀位相
当于乘以 2。
🖐 例子: 假设有⼀个整数 a = 5 ,它的二进制表示为 a = 00000101 。
• a << 2 = 00000101 << 2 = 00010100 ,转换为十进制为 20。
• C代码示例:
int a = 5; // ⼆进制:00000101
int result = a << 2; // result 的值为 20,⼆进制:00010100
printf("a << 2 = %d\n", result); // 输出:a << 2 = 20
49. >> 运算符是(右移),它会将操作数的二进制位向右移动指定的位数。右移分为两种:逻辑右
移(左边补 0)和 算术右移(左边补符号位)。具体使用哪种右移方式取决于编译器和数据类
型。
🖐 例子:
假设有⼀个整数 a = 5 ,它的二进制表示为 a = 00000101 。
• a >> 2 = 00000101 >> 2 = 00000001 ,转换为十进制为 1(逻辑右移)。
假设有⼀个整数 a = -5 ,它的二进制表示为 a = 11111011 (补码)。
• a >> 2 = 11111011 >> 2 = 11111110 ,转换为十进制为 -2(算术右移,补符号位)。
• C代码示例:
int a = 5; // ⼆进制:00000101
int result = a >> 2; // result 的值为 1,⼆进制:00000001
printf("a >> 2 = %d\n", result); // 输出:a >> 2 = 1
int b = -5; // ⼆进制:11111011 (补码)
int result2 = b >> 2; // result2 的值取决于编译器,可能是 -2 或其他值
printf("b >> 2 = %d\n", result2); // 输出:b >> 2 = -2 (取决于编译器)
50. (位设置)用于(将⼀个整数的特定位设置为 1)。
🖐 例子: 假设要将一个 8 位整数 num = 0b00000000 的第 2 位(从右往左数,从 0 开始)
设置为 1。
• 定义⼀个掩码 mask = 0b00000100 。
• newNum = num | mask = 0b00000000 | 0b00000100 = 0b00000100 ,即十进制的 4。
• C代码示例:
unsigned char num = 0b00000000; // 初始值为 0
unsigned char mask = 0b00000100; // 掩码
unsigned char newNum = num | mask; // 设置第 2 位为 1
printf("New number: %d\n", newNum); // 输出:New number: 4
51. (位清除)用于(将一个整数的特定位设置为 0)。
🖐 例子: 假设要将⼀个 8 位整数 num = 0b11111111 的第 2 位(从右往左数,从 0 开始)
设置为 0。
• 定义一个掩码 mask = ~0b00000100 = 0b11111011 。
• newNum = num & mask = 0b11111111 & 0b11111011 = 0b11111011 ,即十进制的 251。
• C代码示例:
unsigned char num = 0b11111111; // 初始值为 255
unsigned char mask = ~0b00000100; // 掩码
unsigned char newNum = num & mask; // 清除第 2 位
printf("New number: %d\n", newNum); // 输出:New number: 251
52. (判断奇偶数)可以使用位运算来(快速判断⼀个整数是奇数还是偶数)。
🖐 例子:
• 如果 num = 7 ,则 num & 1 = 0b00000111 & 0b00000001 =
0b00000001 = 1 ,所以 7 是奇数。
• 如果 num = 6 ,则 num & 1 = 0b00000110 & 0b00000001 =
0b00000000 = 0 ,所以 6 是偶数。
• C代码示例:
int num = 7;
if (num & 1)
{printf("%d 是奇数\n", num); // 输出:7 是奇数
}
else
{printf("%d 是偶数\n", num);
}int num2 = 6;
if (num2 & 1)
{printf("%d 是奇数\n", num2);
}
else
{printf("%d 是偶数\n", num2); // 输出:6 是偶数
}
53. (交换两个变量的值)可以使用位运算来(在不使用额外变量的情况下交换两个变量的值)。
🖐 例子: 假设 a = 5 和 b = 3 。
• a ^= b; // a = 5 ^ 3 = 6 (0101 ^ 0011 = 0110)
• b ^= a; // b = 3 ^ 6 = 5 (0011 ^ 0110 = 0101)
• a ^= b; // a = 6 ^ 5 = 3 (0110 ^ 0101 = 0011)
• C代码示例:
int a = 5;
int b = 3;
printf("交换前:a = %d, b = %d\n", a, b); // 输出:交换前:a = 5, b = 3a ^= b;
b ^= a;
a ^= b;
printf("交换后:a = %d, b = %d\n", a, b); // 输出:交换后:a = 3, b = 5
四、进制转换
54. 进制是⼀种(计数系统),用于表示数值。常见的进制包括(二进制)、(八进制)、(十进
制)和(十六进制)。
55. (二进制)使用 0 和 1 两个数字表示数值,是计算机内部使用的基本进制。
56. (八进制)使用 0 到 7 八个数字表示数值,通常用于简化二进制的表示。
57. (十进制)使用 0 到 9 十个数字表示数值,是人类最常用的进制。
58. (十六进制)使用 0 到 9 和 A 到 F 十六个数字表示数值,通常用于表示内存地址和颜色值。
59. 在 C 语言中,可以使用(不同的前缀)来表示不同进制的整数常量。
60. (十进制常量)直接使用数字表示,例如 123 。
61. (八进制常量)以 0 开头,例如 0173 表示十进制的 123。
62. (十六进制常量)以 0x 或 0X 开头,例如 0x7B 表示十进制的 123。
63. C 语言(没有直接表示二进制常量的语法),但可以使用位运算或查表法来实现二进制的转换。
五、进制转换方法
64. (十进制转换为二进制)可以使用(除 2 取余法),将十进制数不断除以 2,记录每次的余数,直到商为 0,然后将余数倒序排列。
🖐 例子: 将十进制数 25 转换为二进制:
• 25 / 2 = 12 ... 1
• 12 / 2 = 6 ... 0
• 6 / 2 = 3 ... 0
• 3 / 2 = 1 ... 1
• 1 / 2 = 0 ... 1
• 所以,25 的二进制表示为 11001。
65. (二进制转换为十进制)可以将二进制数的每⼀位乘以 2 的相应次方,然后将结果相加。
🖐 例子: 将二进制数 11001 转换为十进制:
• 1 * 2^4 + 1 * 2^3 + 0 * 2^2 + 0 * 2^1 + 1 * 2^0 = 16 + 8 + 0 + 0 + 1 = 25
• 所以,11001 的十进制表示为 25。
66. (十进制转换为八进制)可以使用(除 8 取余法),将十进制数不断除以 8,记录每次的余数,直到商为 0,然后将余数倒序排列。
🖐 例子: 将十进制数 123 转换为八进制:
• 123 / 8 = 15 ... 3
• 15 / 8 = 1 ... 7
• 1 / 8 = 0 ... 1
• 所以,123 的八进制表示为 173。
67. (八进制转换为十进制)可以将八进制数的每⼀位乘以 8 的相应次方,然后将结果相加。
🖐 例子: 将八进制数 173 转换为十进制:
• 1 * 8^2 + 7 * 8^1 + 3 * 8^0 = 64 + 56 + 3 = 123
• 所以,173 的十进制表示为 123。
68. (十进制转换为十六进制)可以使用(除 16 取余法),将十进制数不断除以 16,记录每次的余数,如果余数大于 9,则用 A 到 F 表示,直到商为 0,然后将余数倒序排列。
🖐 例子: 将十进制数 123 转换为十六进制:
• 123 / 16 = 7 ... 11 (B)
• 7 / 16 = 0 ... 7
• 所以,123 的十六进制表示为 7B。
69. (十六进制转换为十进制)可以将十六进制数的每⼀位乘以 16 的相应次方,然后将结果相加。
🖐 例子: 将十六进制数 7B 转换为十进制:
• 7 * 16^1 + 11 * 16^0 = 112 + 11 = 123
• 所以,7B 的十进制表示为 123。
70. (二进制转换为八进制)可以将二进制数从右向左每 3 位⼀组进行分组,然后将每组转换为对应的八进制数。
🖐 例子: 将二进制数 11001 转换为八进制:
• 011 001 (从右向左分组,不足 3 位用 0 补齐)
• 3 1
• 所以,11001 的八进制表示为 31。
71. (八进制转换为二进制)可以将八进制数的每⼀位转换为对应的 3 位二进制数。
🖐 例子: 将八进制数 31 转换为二进制:
• 3 -> 011
• 1 -> 001
• 所以,31 的二进制表示为 011001,去掉前面的 0,为 11001。
72. (二进制转换为十六进制)可以将二进制数从右向左每 4 位⼀组进行分组,然后将每组转换为对应的十六进制数。
🖐 例子: 将二进制数 11001 转换为十六进制:
• 0001 1001 (从右向左分组,不足 4 位用 0 补齐)
• 1 9
• 所以,11001 的十六进制表示为 19。
73. (十六进制转换为二进制)可以将十六进制数的每⼀位转换为对应的 4 位二进制数。
🖐 例子: 将十六进制数 19 转换为二进制:
• 1 -> 0001
• 9 -> 1001
• 所以,19 的二进制表示为 00011001,去掉前面的 0,为 11001。
74. 源码、反码、补码
1. 源码(Original Code):
源码是最简单的机器数表示形式,直接将十进制数转换为二进制数,并在最左边添加符号位。
符号位:0 表示正数,1 表示负数。
例如,十进制数 +7 的源码为 00000111(假设是 8 位),-7 的源码为 10000111。
2. 反码(Inverse Code):
正数的反码与源码相同。
负数的反码是对其源码除符号位外的所有位取反(0 变为 1,1 变为 0)。
例如,+7 的反码为 00000111,-7 的反码为 11111000。
3. 补码(Complement Code):
正数的补码与源码相同。
负数的补码是其反码加 1。
例如,+7 的补码为 00000111,-7 的补码为 11111001。
4. 总结
十进制 | 源码 | 反码 | 补码 |
7 | 111 | 111 | 111 |
-7 | 10000111 | 11111000 | 11111001 |
正数的原反补码一致。
75. 原反补转换过程例子
🖐
• 例子 1:十进制数 +10
源码: 00001010 (8 位表示)
反码: 00001010 (正数,与源码相同)
补码: 00001010 (正数,与源码相同)
🖐 • 例子 2:十进制数 -10
源码: 10001010 (8 位表示)
反码: 11110101 (源码符号位不变,其余位取反)
补码: 11110110 (反码加 1)
🖐 • 例子 3:已知补码求源码
如果已知一个负数的补码,求其源码,可以对补码再次求补码(即取反加 1),或者 补
码-1,再取反。
假设已知某数的补码为 11110110。
a. 判断符号位为 1,是负数。
b. 反码:11110110 - 1 = 11110101
c. 源码:符号位不变,对反码取反 = 10001010,即 -10。