第五章 二进制
5.1 进制
计算机世界中只有二进制,所以计算机中存储和运算的所有数据都要转为二进制。包括
数字、字符、图片、声音、视频等。
5.1.1 常见进制介绍
1)二进制:0、1,满 2 进 1。
(2)十进制:0 - 9,满 10 进 1。
(3)十六进制:0 - 9 及 A-F,满 16 进 1。十六进制中,除了 0 到 9 十个数字外,还
引入了字母,以便表示超过 9 的值。字母 A 对应十进制的 10,字母 B 对应十进制的 11,字
母 C、D、E、F 分别对应十进制的 12、13、14、15。
| 二进制 | 十进制 | 十六进制 |
| 0 | 0 | 0 |
| 1 | 1 | 1 |
| 10 | 2 | 2 |
| 11 | 3 | 3 |
| 100 | 4 | 4 |
| 101 | 5 | 5 |
| 110 | 6 | 6 |
| 111 | 7 | 7 |
| 1000 | 8 | 8 |
| 1001 | 9 | 9 |
| 1010 | 10 | A |
| 1011 | 11 | B |
| 1100 | 12 | C |
| 1101 | 13 | D |
| 1110 | 14 | E |
| 1111 | 15 | F |
| 10000 | 16 | 10 |
| 10001 | 17 | 11 |
5.1.2 c语言中使用不同进制表示整数
(1)二进制:以 0b 或 0B 开头表示。
(2)十进制:正常数字表示。
(3)十六进制:以 0x 或 0X 开头表示,此处的 A-F 不区分大小写。
示例:
#include<stdio.h>
int main()
{
int num1 = 0b10;//二进制
int num2 = 210;//十进制
int num3 = 0x1f;//十六进制
printf("num1=%d\n",num1);
printf("num2=%d\n", num2);
printf("num3=%d\n", num3);
return 0;
}
num1=2
num2=210
num3=31D:\c-code\Project1\x64\Debug\3-14.exe (进程 21224)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
5.1.3 输出格式
不同的进制只是整数的书写方法不同,不会对整数的实际存储方式产生影响。不同进制
可以混合使用,比如 10 + 015 + 0x20 是一个合法的表达式。
使用格式占位符可以将整数以不同进制形式输出,相关的格式占位符如下:
%d :十进制整数。
%x :十六进制整数。
%#x :显示前缀 0x 的十六进制整数。
%#X :显示前缀 0X 的十六进制整数。
示例:
#include<stdio.h>
int main()
{
int x = 100;
printf("十进制:%d\n", x);
printf("十六进制:%x\n", x);
printf("十六进制(0x开头):%#x\n", x);
return 0;
}
十进制:100
十六进制:64
十六进制(0x开头):0x64D:\c-code\Project1\x64\Debug\3-14.exe (进程 20940)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
5.2 进制转换
5.2.1 二进制与十进制转换
5.2.1.1二进制转换成十进制
1)规则:从最低位开始,将每个位上的数提取出来,乘以 2 的(位数-1)次方,然
后求和。
(2)案例:请将二进制 1011 转成十进制的数。

5.2.1.2 十进制转换成二进制
(1)规则:将该数不断除以 2,直到商为 0 为止,然后将每步得到的余数倒过来,就
是对应的二进制。
(2)案例:请将 56 转成二进制。

5.2.2 十六进制和十进制
5.2.2.1 十六进制转换成十进制
(1)规则:从最低位开始,将每个位上的数提取出来,乘以 16 的(位数-1)次方,然后求和。
(2)案例:请将 0x34A 转成十进制的数。

5.2.2.2 十进制转换成十六进制
(1)规则:将该数不断除以 16,直到商为 0 为止,然后将每步得到的余数倒过来,就
是对应的十六进制。
(2)案例:请将 356 转成十六进制。

5.2.3 二进制和十六进制
5.2.3.1 二进制转换成十六进制
(1)规则:低位开始,将二进制数每四位一组,转成对应的十六进制数即可。
(2)案例:请将 1011011 转成十六进制。

5.2.3.2 十六进制转换成二进制
(1)规则:将十六进制数每 1 位,转成对应的 4 位的一个二进制数即可。
(2)案例:请将 0x23B 转成二进制。
5.3 原码,反码,补码
计算机底层存储数据时使用的是二进制数字,但是计算机在存储一个数字时并不是直接
存储该数字对应的二进制数字,而是存储该数字对应二进制数字的补码。
5.3.1 机器数和真值
(1)机器数
一个数在计算机的存储形式是二进制数,我们称这些二进制数为机器数。机器数可以是
有符号的,用机器数的最高位存放符号位,0 表示正数,1 表示负数。
(2)真值
因为机器数带有符号位,所以机器数的形式值不等于其真实表示的值(真值),以机器
数 10000001 为例,其真正表示的值(首位为符号位)为-1,而形式值(首位就是代表 1)
为 129;因此将带符号的机器数的真正表示的值称为机器数的真值。
5.3.2 原码、反码、补码的概念
(1)原码
原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值。
正数的原码:就是它对应的二进制数。
负数的原码:它的绝对值对应的二进制数,且最左边位变为 1。
0 的原码:仍然是 0。
十进制的正负 1,用 8 位二进制的原码表示如下:
+1 原码:[ 0000 0001 ]
-1 原码:[ 1000 0001 ]
(3)补码
正数的补码:和原码、反码相同。 负数的补码:反码的基础上加 1。 0 的补码:仍然是 0。
十进制的正负 1,用 8 位二进制的补码表示如下:
+1 原码:[ 0000 0001 ] 反码:[ 0000 0001 ] 补码:[ 0000 0001 ]
-1 原码:[ 1000 0001 ] 反码:[ 1111 1110 ] 补码:[ 1111 1111 ]
(4)总结
(1)正数的原码、反码、补码都一样,三码合一。
(2)负数的反码:它的原码符号位不变,其它位取反(0 -> 1,1 -> 0);负数的补码:
它的反码+1。
(3)0 的反码,补码都是 0。
5.3.3 计算机为什么用补码

5.3.4 计算案例
需求:计算 10 – 12,使用补码描述计算机内部的计算过程。

第六章 数据类型
程序的主要目的就是对数据进行计算和处理,为了方便数据的管理,通常会对数据进行
分类。就像根据容器的容量和形状不同,可以分成大杯中杯、大碗小碗等,不同的容器适合
装不同的东西。
C 语言根据数据的特性和用途进行了类型划分,不同类型的数据在内存中占据不同大小
的空间。

6.1 整数类型
(1)基本介绍
整数类型简称整型,就是用于存放整数值的,比如:12,30,3456 等。
(2)整型的类型

关于存储大小单位:
bit(位):计算机中的最小存储单位,表示一个二进制位。
byte(字节):计算机中基本存储单元,1byte = 8bit。
(3)整型注意事项
1)各类型存储大小受到操作系统、编译器、硬件平台的影响。
2)整型分为有符号 signed 和无符号 unsigned 两种,默认是 signed。
3)开发中使用整型一般用 int 型,如果不足以表示大数,可以使用 long long。
4)字面量后缀
字面量是源代码中一个固定值的表示法,用于直接表示数据,如图所示:
1)一个整数字面量默认是 int 类型。
2)如果需要表示 long 类型字面量,需要添加后缀 l 或 L。
3)如果需要表示 long long 类型字面量,需要添加后缀 ll 或 LL。
4)如果需要表示无符号整数字面量,需要添加后缀 u 或 U, 注意, u 和 l 可以
结合使用,不分先后,如 ul(无符号 long 类型)、ULL(无符号 long long 类型),lu(无
符号 long 类型) 等。
(5)格式占位符
1)%d 对应 int 类型,%u 对应 unsigned int 类型。
2)%ld 对应 long 类型,%lu 对应 unsigned long 类型。
3)%lld 对应 long long 类型,%llu 对应 unsigned long long 类型。
(6)代码演示:
#include<stdio.h>
int main()
{
//short 类型
short a1 = 10;//等同于signed short a1 = 10;
short a2 = 20;//等同于signed short a1 = -10;
unsigned short a3 = 20;
printf("a1=%d;a2=%d;a3=%d\n", a1, a2, a3);
//int 类型
int b1 = 100;
int b2 = -200;
unsigned int b3 = 200u;
unsigned b4 = 300u;//等同于unsigned int b4 = 300u
printf("b1=%d;b2=%d;b3=%d;b4=%d\n", b1, b2, b3,b4);
//long类型
long c1 = 10000l;
long c2 = -39484l;
unsigned long c3 = 32424ul;
printf("c1=%ld;c2=%ld;c3=%ld\n", c1, c2, c3);
//long long 类型
long long d1 = 2323232ll;
long long d2 = -324242424ll;
unsigned long long d3 = 432412412ull;
printf("d1=%d;d2=%d;d3=%d", d1, d2, d3);
return 0;
}
a1=10;a2=20;a3=20
b1=100;b2=-200;b3=200;b4=300
c1=10000;c2=-39484;c3=32424
d1=2323232;d2=-324242424;d3=432412412
D:\c-code\Project1\x64\Debug\3-14.exe (进程 23136)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
(7)精确宽度类型
C 语言的整数类型(short、int、long)在不同计算机上,占用的字节宽度可能是不一样
的。程序员有时需要精准的字节宽度,以提高代码的可移植性,尤其是嵌入式开发中,使用
精确宽度类型可以确保代码在各种平台上的一致性。
标准库的头文件 <stdint.h> 中定义了一些新的类型别名,如下:
上面这些都是类型别名,编译器会指定它们指向的底层类型。比如,某个系统中,如果
int 类型为 32 位, int32_t 就会指向 int ;如果 long 类型为 32 位, int32_t 则会指向
long 。
示例代码:
#include<stdio.h>
#include<stdint.h>
int main()
{
//变量x32声明为int32_t类型,可以保证是32位(4个字节)的宽度
int32_t x32 = 4543423432;
printf("x32=%d", x32);
return 0;
}
x32=248456136
D:\c-code\Project1\x64\Debug\3-14.exe (进程 12864)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
6.2 浮点类型
(1)基本介绍
浮点类型可以表示一个小数,比如:123.4,7.8,0.12 等。
(2)浮点型的类型
(3)浮点型注意事项
1)各类型的存储大小和精度受到操作系统、编译器、硬件平台的影响。 2)浮点型数据有两种表示形式。
十进制数形式:如:5.12、512.0f、.512(0.512 可以省略 0)
科学计数法形式:如:5.12e2、5.12E-2
3)开发中用到浮点型数字,建议使用 double 型,如精度要求更高可以使用 long double
型。 ( 4)字面量后缀
1)浮点数字面量默认是 double 型,
2)如果需要表示 float 类型字面量,须加后缀 f 或 F。
3)如果需要表示 long double 类型字面量,需加后缀 l 或 L。
(5)格式占位符
在 C 语言中,占位符是一种用于格式化输出的特殊字符,通常用于 printf() 等输出函
数中,用于指定输出的格式和内容。
1)%f 是浮点类型的格式占位符,在 printf 中对应 double 类型(float 类型会转换成
double 来处理);默认会保留 6 位小数,可以指定小数位数,如:%.2f 表示保留 2 位小数。
2)%lf 在 printf 中和 %f 意思相同(C99 标准加入),也对应 double 类型,默认保留
6 位小数,可以指定小数位数,如:%.2lf 表示保留 2 位小数。但需要注意的是,在 scanf
中 %lf 和 %f 含义不同:输入一个 float 类型数据时使用 %f;而输入 double 类型时必须使
用 %lf。
3)%Lf 对应的是 long double 类型,默认保留 6 位小数,可以指定小数位数,
如: %.2Lf 表示保留 2 位小数。需要注意的是,输入输出 long double 类型都必须使
用 %Lf 占位符。
4)%e 对应科学计数法表示的浮点数,可以指定尾数部分所保留的小数位数,
如 %.2e 表示尾数部分保留两位小数。
代码演示:
#include<stdio.h>
int main()
{
//double类型
double a1 = 3.1415;
double a2 = .21242;
double a3 = -2e12;
double a4 = 1.9738e4;
printf("a1=%f;a2=%.10;a3=%.2lf;a4=%lf\n", a1, a2, a3, a4);
printf("a1=%e,a2=%.2e,a3=%e,az4=%e\n", a1, a2, a3, a4);
//float类型
float b1 = 3.1415f;
float b2 = .12324f;
float b3 = -2e12f;
float b4 = 1.97867e2f;
printf("b1=%f,b2=%f,b3=%.0f,b4=%f\n", b1, b2, b3, b4);
printf("b1=%e,b2=%.2e,b3=%e,b4=%e\n", b1, b2, b3, b4);
return 0;
}
a1=3.141500;a2=;a3=0.21;a4=-2000000000000.000000
a1=3.141500e+00,a2=2.12e-01,a3=-2.000000e+12,az4=1.973800e+04
b1=3.141500,b2=0.123240,b3=-1999999991808,b4=197.867004
b1=3.141500e+00,b2=1.23e-01,b3=-2.000000e+12,b4=1.978670e+02D:\c-code\Project1\x64\Debug\3-14.exe (进程 19104)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
6.3字符类型
(1)基本介绍
字符类型 char 可以表示单个字符,如一个数字、一个字母、一个符号。
(2)注意事项
1)char 类型的字面量是用单引号括起来的单个字符。
2)可以使用转义字符 \ 表示特殊含义的字符。

3)多个字符称为字符串,在 C 语言中使用 char 数组表示,数组不是基本数据类型,
而是构造类型,我们后续专门讲解。
(3)格式占位符
使用%c 表示 char 类型。
4)字符类型本质
(1)C 语言中,char 类型本质是一个整数,是 ASCII 码中对应的数字,存储长度是 1
个字节,char 类型也可以进行数学运算。
(2)字符型同样分为 signed char(无符号)和 unsigned char(有符号),其中 signed char
取值范围-128 ~ 127,unsigned char 取值范围 0 ~ 255。默认是否带符号取决于当前运行环境。
(3)字符型数据在计算中存储和读取的过程:

(5)ASCII 码介绍
ASCII(American Standard Code for Information Interchange)码是一种用于表示文本字符
的字符编码标准,一共规定了 128 个字符的编码,比如空格“SPACE” 是 32(二进制
00100000),大写的字母 A 是 65(二进制 01000001)。
(6)代码演示:
#include<stdio.h>
int main()
{
//char类型字面量需要使用引号包裹
char a1 = 'A';
char a2 = '9';
char a3 = '\t';
printf("c1=%c,c3=%c,c2=%c\n", a1, a2, a3);
//char 类型本质上整数可以进行运算
char b1 = 'b';
char b2 = 101;
printf("%c->%d\n", b1, b2);
printf("%c->%d\n", b2, b1);
printf("%c+%c\n", b1, b2);
//char类型取值范围
unsigned char c1 = 200;
signed char c2 = 200;
char c3 = 200;
printf("c1=%d,c2=%d,c3=%d", c1, c2, c3);
return 0;
}
c1=A,c3=9,c2=
b->101
e->98
b+e
c1=200,c2=-56,c3=-56
D:\c-code\Project1\x6
6.4 布尔(bool)类型
(1)基本介绍
布尔值用于表示真、假两种状态,通常用于逻辑运算和条件判断。
(2)声明布尔类型的三种方式
1)C89 标准没有定义布尔类型,判断真假时以 0 为假,非 0 为真 ,但这种做法不直
观,我们一般需要借助 C 语言的宏定义。
#include<stdio.h>
//宏定义
#define Bool int
#define TURE 1
#define FALSE 0
int main()
{
//使用整形数表示真假两种状态
//int isPass=0;
//int Ok=1;
//借助宏定义
Bool IsPass = FALSE;
Bool IsOk = TURE;
printf("isPass=%d,IsOk=%d\n", IsPass, IsOk);
if (IsPass)
{
printf("Pass");
}
if (IsOk)
{
printf("ok");
}
return 0;
}
isPass=0,IsOk=1
ok
D:\c-code\Project1\x64\Debug\3-14.exe (进程 21160)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
2)C99 标准提供了_Bool 型,_Bool 仍是整数类型,但与一般整型不同的是,_Bool
变量只能赋值为 0 或 1,非 0 的值都会被存储为 1。
#include <stdio.h>
#include<stdbool.h>
int main()
{
// 使用 _BOOL 类型
_Bool isPass = 0;
//_Bool isOk = 1;
_Bool isOk = -4;
printf("isPass=%d, isOk=%d\n", isPass, isOk);
if (isPass)
{
printf("Pass");
}
if (isOk)
{
printf("Ok");
}
return 0;
}
isPass=0,IsOk=1
ok
D:\c-code\Project1\x64\Debug\3-14.exe (进程 19272)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
6.5 获取数据的存储大小
使用 sizeof 可以获取数据类型或变量、字面量的存储大小,单位是字节。sizeof 返回一
个 size_t 类型的无符号整数值,格式占位符是 %zu。
size_t 通常是 unsigned int 或 unsigned long 的别名,具体是哪个类型的别名,由系统
和编译器决定。
#include<stdio.h>
int main()
{
//计算数据类型的大小,必须使用括号将数据类型包裹起来
printf("char:%zu\n", sizeof(char));//char:1
printf("short:%zu\n", sizeof(short));//int:2
printf("int:%zu\n", sizeof(int));//int:4
printf("long:%zu\n", sizeof(long));//long:4
printf("long long:%zu\n", sizeof(long long));//long long:8
printf("float:%zu\n", sizeof(float));//float:4
printf("double:%zu\n", sizeof(double));//double:8
printf("long double:%zu\n", sizeof(long double));//long double:16
printf("\n");
//计算字面量数据的大小,字面量可以省略
printf("%zu\n", sizeof('a'));//4
printf("%zu\n", sizeof(413));//4
printf("%zu\n", sizeof(4.13));//8
printf("\n");
//计算变量的大小,变量可以省略括号
char a = 'A';
int b = 90;
long long c = 100;
double d = 10.8;
printf("a:%zu\n",sizeof(a));
printf("b:%zu\n", sizeof(b));
printf("c:%zu\n", sizeof(c));
printf("d:%zu\n", sizeof(d));
return 0;
}
char:1
short:2
int:4
long:4
long long:8
float:4
double:8
long double:81
4
8a:1
b:4
c:8
d:8D:\c-code\Project1\x64\Debug\3-14.exe (进程 1732)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
6.6 数据类型转换
6.6.1 自动类型转换(隐式转换)
6.6.1.1运算过程中的自动类型转换
不同类型的数据进行混合运算,会发生数据类型转换,窄类型会自动转为宽类型,这样
不会造成精度损失。
(1)转换规则
1)不同类型整数进行运算,窄类型整数自动转换为宽类型整数。
2)不同类型浮点数进行运算,精度小的类型自动转换为精度大的类型。
3)整数与浮点数进行运算,整数自动转换为浮点数。
(2)转换方向

案例:
#include<stdio.h>
int main()
{
//整形提升
short s1 = 10;
int n1 = 40000;
//运算过程中,变量 s1 是 short 类型,会自动转换成 int 类型
printf("10+40000=%d\n", s1 + n1);
//有符号整形自动转换成无符号整形
//int n2 =-100
int n2 = -100;
unsigned int n3 = 20;
//负数转换成无符号整数,两者绝对值的和是无符号整数的最大值再加1
printf("-100+20=%u\n", n2 + n3);
//不同类型的浮点数运算,精度低的转换精度高的
float f1 = 1.25f;
float f2 = 4.478634;
printf("1.25+4.478634=%.10f\n", f1 + f2);
//整型与浮点型运算,整形转化为浮点型
int n4 = 10;
double d3 = 1.67;
printf("10+1.67=%f", n4 + d3);
return 0;
}
10+40000=40010
-100+20=4294967216
1.25+4.478634=5.7286338806
10+1.67=11.670000
D:\c-code\Project1\x64\Debug\3-14.exe (进程 9868)已退出,代码为 0 (0x0)。
按任意键关闭此窗口. . .
每日一测-day-2
1. 【计算题】将十进制数 42 转换为二进制表示。
【答案】
101010
【解析】
(1)使用除以 2 法,将 42 除以 2,得到商 21 和余数 0。
(2)将商 21 再次除以 2,得到商 10 和余数 1。
(3)重复此过程,直到商为 0。最终得到的余数反向排列就是二进制表示。
(4)42 的二进制表示为 101010。
2. 【计算题】将二进制数 110110 转换为十进制表示。
【答案】
54
【解析】
(1)从右往左,分别为每位赋予 2 的幂次,从 0 开始。
(2)对每位乘以对应的 2 的幂次,并求和。
(3)计算:0*2^0 + 1*2^1 + 1*2^2 + 0*2^3 + 1*2^4 + 1*2^5 = 0 + 2 + 4 + 0 + 16 + 32 = 54。
(4)110110 的十进制表示为 54。
3. 【计算题】将二进制数 1101 转换为十六进制表示。
【答案】
D
【解析】
(1)先将二进制数转换为十进制数,得到 13。
(2)再将十进制数 13 转换为十六进制,得到 D。
(3)1101 的十六进制表示为 D
4. 【计算题:】将十六进制数 1A3 转换为二进制表示。
【答案】
000110100011 或者 110100011
【解析】
(1)十六进制数的 1 对应十进制的 1,A 对应十进制的 10,3 对应十进制的 3。
(2)将每个部分分别转换为二进制数,得到 0001(1)、1010(A)、0011(3)。
(3)连接这三个部分,得到 000110100011。
(4)1A3 的二进制表示为 000110100011。
5. 【计算题】有十进制数-8,请用八位二进制小数表示的它的原
码、反码、补码
【答案】
原码:10001000
反码:11110111
反码:11111000
6. 【问答题】请将下列数据类型按照所占字节多少从小到大排序
long long、char、int、short
【答案】
char、short、int、long long
【解析】
char 类型占 1 个字节,short 类型占 2 个字节,int 类型占 4 个字
节,long long 类型占 8 个字节。
7.. 【代码题】写出下面代码的运行结果
#include <stdio.h>
int main()
{
printf("%zu", sizeof(12.5));
return 0;
}
【答案】
8
【解析】
字面量 12.5 会被识别为 double 类型,double 类型占 8 个字节。
8.【代码题】写出下面代码的运行结果
#include <stdio.h>
int main()
{
int a = 10;
_Bool b1 = -4;
printf("%d", a + b1);
return 0;
}
【答案】
11
【解析】
C99 标准提供了_Bool 型,_Bool 仍是整数类型,但与一般整型不同的是,_Bool 变量
只能赋值为 0 或 1,非 0 的值都会被存储为 1。
9. 【问答题】有变量 int a 和 short b ,现在 a 和 b 进行运算 a
+ b, 哪个变量会发生数据类型转换,转换为什么类型?
【答案】
变量 b 会发生数据类型转换,转换为 int 类型
【解析】 运算过程中,字节宽度较小的类型会自动转换为字节宽度较大的类型。
10. 如果将一个字节宽度较大的类型转为字节宽度较小的类型,可能会造成什
么问题?
【答案】
精度损失
【解析】
字节宽度较大的类型转为字节宽度小的类型,可能会造成精度损失

870

被折叠的 条评论
为什么被折叠?



