数据类型与进制转换
char 类型
基础信息
- 字符型。
- 单位:一个字节(8 bit 位)。
- 格式匹配符:
- 数值型:
- 有符号:
%hhd—— char 显示数值专用格式匹配符。 - 无符号:
%hhu—— unsigned char 显示数值专用格式匹配符。
- 有符号:
- 字符型:
%c
- 数值型:
- 取值范围:
- 有符号:-128 ~ 127
- 无符号:0 ~ 255
程序获取
#include <stdio.h>
#include <limits.h>
int main(void)
{
// 获取无符号数取值范围
printf("char 无符号 min = 0,max = %hhu\n", UCHAR_MAX);
// 获取有符号数取值范围
printf("char 有符号 min = %hhd,max = %hhd\n", CHAR_MIN, CHAR_MAX);
// 获取 char 占用的字节数
printf("char 大小 = %u\n", sizeof(char));
// 获取 unsigned char 占用的字节数
printf("unsigned char 大小 = %u\n", sizeof(unsigned char));
return 0;
}
ASCII 码
char 类型数据,数值对应一个 ASCII 码。
#include <stdio.h>
int main(void)
{
char ch = 'A'; // 定义变量 ch, 指定初值为 'A';
printf("ch = %c\n", ch); // c: character %c 用来显示字符的 格式匹配符。
ch = 'm'; // 给变量ch 赋值成 'm', 覆盖 原来的 'A';
printf("ch = %c\n", ch);
ch = 97; // 使用 范围内的数值 97 ,给 ch 赋值。
printf("ch = %c\n", ch); // 将数值97,按照字符格式打印输出。
ch = 98; // 使用 范围内的数值 98 ,给 ch 赋值。
printf("ch = %c\n", ch); // 将数值98,按照字符格式打印输出。
return 0;
}
ASCII 表说明
- 0 ~ 32 的 ASCII 码对应的字符都不可见。
- 常用的 ASCII 码:
'a':ASCII 码值 97'A':ASCII 码值 65'0':ASCII 码值 48'\n':ASCII 码值 10'\t':制表符,tab 键对应的字符(ASCII 码值 9)'\0':ASCII 码值 0
练习:将大写字母转换成小写字母
#include <stdio.h>
int main(void)
{
char ch = 'R'; // char 变量定义
printf("R 转换的小写为:%c\n", ch+32); //ch+32 表达式,对应格式匹配符 %c
char ch2 = 'h'; // char 变量定义
printf("h 转换的大写为:%c\n", ch2-32); //ch2-32 表达式,对应格式匹配符 %c
char ch3 = '5';
// 借助字符5, 利用 ASCII特性,打印出 字符9
printf(" 打印字符9 = %c\n", ch3+4);
return 0;
}
转义字符
练习:
- 在一个 printf 函数中,打印输出 hello 换行 world 换行。
- 一个 printf 中打印 hello(一个 tab 缩进)world 换行。
说明:
'/':自右向左划,叫做“斜杠”。'\':自左向右划,叫做“反斜杠”。——是转义字符。
转义字符的作用:
- 将普通字符,转换为特殊意。
- 如:
'\n':这是一个字符,代表换行。 - 如:
'\t':这是一个字符,代表一个制表符。
- 如:
- 将特殊字符,还原成本身意。
- 如:
\\n:这样就将一个字符'\n',还原成两个字符:'\'和'n'。
- 如:
hello 换行 world 换行的两种方法:
// 方法1
int main(void)
{
printf("hello\nworld\n");
return 0;
}
// 方法2
int main(void)
{
char ch = '\n'; //定义ch变量,初值为'\n'
printf("hello%cworld%c", ch, ch); // 等价于 printf("hello\nworld\n");
return 0;
}
hello(tab)world 换行:
int main(void)
{
char ch1 = '\t'; // 实现 一个tab缩进
char ch2 = '\n'; // 实现 一个换行。
printf("hello%cworld%c", ch1, ch2);
return 0;
}
练习:将特殊字符转换成本身意。
题目:屏幕上严格输出如下内容:【 '\n' 的值是 10】,要求显示时要有 ' '。
int main(void)
{
printf("'\\n'的值是 %hhd", '\n');
return 0;
}
实型(浮点型)【了解】
用于显示小数。
基础信息
float:单精度浮点型。%f,大小 4 字节(可以使用sizeof()求取)。4.35默认会被编译器理解为 double 类型。float v = 4.567f;编译器理解为 float。%f格式匹配符,默认保留 6 位小数。
double:双精度浮点型。%lf,大小 8 字节。double d = 5.68;
取值范围
使用头文件 #include <float.h> 获取浮点型取值范围。
int main(void)
{
printf("float 范围:%f ~ %f\n", FLT_MIN, FLT_MAX);
printf("double 范围:%lf ~ %lf\n", DBL_MIN, DBL_MAX);
return 0;
}
精度问题
- float 类型:精度 6~7 位:
- 整数部分 + 小数部分 ≤ 6 位,准确。
- 整数部分 + 小数部分 == 7 位,可能准确,也可能不准确。
- 整数部分 + 小数部分 > 7 位,不准确。
- double 类型:精度 15~16 位:
- 整数部分 + 小数部分 ≤ 15 位,准确。
- 整数部分 + 小数部分 == 16 位,可能准确,也可能不准确。
- 整数部分 + 小数部分 > 16 位,不准确。
- 不同平台(操作系统),对应 float、double 类型实现的精度有可能不同。以上是 Windows 下特性。
- float 和 double 不存在“无符号”类型。
bool 类型
C 语言原来没有 bool 类型。C99 标准中新增了 bool 类型。C++ 自带 bool 类型。
用处,表示:
- 好、坏
- 真、假
- 对、错
- 是、否
取值:
true—— 真 —— 1false—— 假 —— 0
C 语言使用 bool 的条件:
- 编译器要支持 c99 标准。
- 导入
#include <stdbool.h>
bool 类型的大小:1 字节(sizeof() 求取)。
bool 没有专用的格式匹配符,打印时使用 %d 来打印。
int main(void)
{
bool aa = true; // 定义bool 类型变量 aa , 初值为 true == 1
printf("aa = %d\n", aa);
aa = false; // 给 bool 类型变量 aa 赋值为 false == 0
printf("aa = %d\n", aa);
return 0;
}
进制和转换
计算机只使用 2 进制。8 进制、10 进制、16 进制统统都是给人类用的!!!
存储知识
- 1 bit 位就是一个二进制位,存 0 或 1。
- 一个字节(Byte)1B = 8 bit 位。
- “内存单元”是计算机内存存储的最小单位,一个内存单元 == 1 字节。
- 1KB = 1024B
- 1MB = 1024KB
- 1GB = 1024MB
- 1TB = 1024GB
2 进制
- 取值 1 或 0。逢 2 进 1,借 1 当 2。
- 没有格式匹配符。
- 10 转 2:除 2 反向取余法。
- 2 转 10:掌握 2^0 ~ 2^10 各自的取值:
| 幂 | 值 | 幂 | 值 |
|---|---|---|---|
| 2^0 | 1 | 2^6 | 64 |
| 2^1 | 2 | 2^7 | 128 |
| 2^2 | 4 | 2^8 | 256 |
| 2^3 | 8 | 2^9 | 512 |
| 2^4 | 16 | 2^10 | 1024 |
| 2^5 | 32 |
计算方法:对应二进制位,有 1 累加 2 的指数次幂值,有 0 略过。
11101—— 2910110—— 2 + 4 + 16 = 22
8 进制
- 逢 8 进 1,借 1 当 8。
- 取值:0/1/2/3/4/5/6/7,最大值 7。
- 格式匹配符:
%o和%#o - 表示语法:0 开头。
- 8 进制 → 10 进制:
056== 8^0 × 6 + 8^1 × 5 = 6 + 40 = 460123= 8^0 × 3 + 8^1 × 2 + 8^2 × 1 = 3 + 16 + 64 = 83
- 10 进制 → 8 进制:除 8 反向取余法。
135——0207 - 8 转 2:将 8 进制数,自左向右,每一位用 421 码展开。
- 练习:
056——101110;04735——1001 1101 1101;053261——101 0110 1011 0001
- 练习:
- 2 转 8:自右向左,每 3 个二进制位一组,不足 3 位补 0。
1101010101111010→ 分组:1 101 010 101 111 010→ 补齐:001 101 010 101 111 010→ 八进制数为:015257210110111011→ 分组:10 110 111 011→ 补齐:010 110 111 011→ 八进制数为:02673
16 进制
- 逢 16 进 1,借 1 当 16。
- 取值:0~9,10-A/a,11-B/b,12-C/c,13-D/d,14-E/e,15-F/f,最大值 F/f。
- 格式匹配符:
%x或%#x - 表示语法:0x 开头。
- 16 进制 → 10 进制:将每一个 16 进制位展开相加得 10 进制。
- 10 进制 → 16 进制:除 16 反向取余法。
37:0x25;43:0x2B - 16 转 2:将 16 进制数,自左向右,每一位用 8421 码展开。
0xFAC12:1111 1010 1100 0001 0010
- 2 转 16:自右向左,每 4 个二进制位一组,不足 4 位补 0。
101001011101011001→ 分组:10 1001 0111 0101 1001→ 补齐:0010 1001 0111 0101 1001→ 16 进制数为:0x297591110110100111101→ 分组:1110 1101 0011 1101→ 补齐:1110 1101 0011 1101→ 16 进制数为:0xED3D
小结
使用频率最高的是 10 进制,次高的是 16 进制。
int m = 0x15F4;
int n = 0345;
int k = 0101101;
- 不能直接将变量值赋值为 2 进制。
- 上述的赋值,会被编译器理解为 8 进制数。
常用的格式匹配符
| 格式匹配符 | 说明 |
|---|---|
| %d | 有符号十进制整数(int) |
| %c | 字符 |
| %x | 十六进制整数 |
| %u | 无符号十进制整数 |
| %s | 字符串(后续课程讲,打印字符串) |
| %o | 八进制整数 |
| %#o | 八进制整数(带前缀 0) |
| %#x | 十六进制整数(带前缀 0x) |
| %hhd | signed char(数值) |
| %hd | short |
| %ld | long |
| %lld | long long |
| %hhu | unsigned char(数值) |
| %hu | unsigned short |
| %lu | unsigned long |
| %llu | unsigned long long |
| %f | float |
| %lf | double |
进制输出示例:
#include <stdio.h>
int main(void)
{
int a = 56; // 10进制数作a变量初始化。 —— 定义。
printf("10进制:a = %d\n", a);
printf("8进制:a = %o\n", a);
printf("8进制:a = %#o\n", a); //在%和x中间添加#,可以在输出时,显示8进制前缀。
printf("16进制:a = %x\n", a);
printf("16进制:a = %#x\n", a); //在%和x中间添加#,可以在输出时,显示16进制前缀。
return 0;
}
编码和存储
无符号存储
unsigned int a = 12; // 占用 4 字节 32 个 bit位存储。
空间:00000000 00000000 00000000 00000000 ———— 4 字节。
存储:00000000 00000000 00000000 00001100
unsigned short b = 15; //占用 2 字节 16 个 bit位存储。
空间:00000000 00000000 ———— 2 字节。
存储:00000000 00001111
有符号存储
- 需要拿出一个二进制位,专门存储符号,标识正、负。
- 选用最高位为符号位。
- 正:0
- 负:1
有符号正数
采用“源码”存储。
int a = 5;
空间:0 0000000 00000000 00000000 00000000
存储:0 0000000 00000000 00000000 00000101 --- 表示存储正数 5 。
有符号负数
有符号的负数,采用“补码”存储。
- 源码:数值的二进制位直接存储。
- 反码:符号位不变,将其余数值位取反。
- 补码:反码 + 1。
int b = -33;
空间:0 0000000 00000000 00000000 00000000
源码:1 0000000 00000000 00000000 00100001
反码:1 1111111 11111111 11111111 11011110
补码:1 1111111 11111111 11111111 11011111 —— 负33 在计算机中实际的存储形式。
小结
- int —— 4 字节 —— 32 bit 位
- 有符号:31 个数值位。取值范围 -2^31 ~ 2^31 - 1 → -2147483648 ~ +2147483647
- 无符号:32 个数值位。取值范围 0 ~ 2^32 - 1 → 0 ~ 4294967295
- short —— 2 字节 —— 16 bit 位
- 有符号:15 个数值位。取值范围 -2^15 ~ 2^15 - 1 → -32768 ~ 32767
- 无符号:16 个数值位。取值范围 0 ~ 2^16 - 1 → 0 ~ 65535
因此,知道数据类型占用内存的大小,就能算出该类型无符号数、有符号数对应的取值范围。
数据溢出
📷(此处原文为配图,略)
不常用关键字
📷(此处原文为配图,略)