⌨️ 第三章 数值和数据的处理方法
📄 一句话概括

计算机只认数字,文字必须先变成数字——字符编码就是那张【字到数字】的对照表;字符串是字符排成的序列,C 语言还要在末尾放一个 NULL 字符(\0)当句号,告诉程序【到这儿为止】。

📝 本节和前面几节的关系

3-1 的二进制能表示数,这一篇让它表示字。回收 C++ 课 2.2.3 字符变量(char 一个字节的老规矩)与树莓派课 6-6(Python 字符串按字符不按字节)——两课的落差正是编码演化史。

一、字符编码:字与数字的对照表

二、字符串:字符的数组

字符串就是字符排成一串——本质就是 3-8 的数组,元素是字符:

s = "Hello"
print(s[0], s[4])      # H o
print(len(s))          # 5

Python 与 C 的两处关键不同:

  1. C 字符串以 NULL 字符收尾:C 里 "Hi" 实际占 3 个字节——H、i、\0。\0(数值 0)就是那个【句号】,函数靠扫描它才知道字符串到哪结束。忘了给句号留位置,函数会一路读到内存深处——C 最经典的越界事故源。Python/Java 的字符串自带长度信息,不需要这个句号;
  2. Python 字符串按【字符】算不按【字节】算:len("你好") 是 2 不是 4(回收树莓派课 6-6 的坑)——Python 3 的字符串是 Unicode 字符序列,字节是编码(3-10)之后的事。

三、字符与数字互转

print(ord("A"))    # 65   字 -> 编号
print(chr(66))     # B    编号 -> 字

每个字符背后就是一个数字——文字与数字在这里打通。

四、动手 Demo:句号、锚点与长度

print(ord("0"), ord("5"))       # 48 53
print(ord("5") - ord("0"))      # 5    字符数字转真数值的经典招

s = "Hi"
print(len(s), len(s.encode()))  # 2 2   ASCII:2 字符 2 字节
print(len("你好"), len("你好".encode()))  # 2 6  UTF-8 下每个汉字 3 字节

看到什么算成功:48 53、5、2 2、2 6。

读结果:第一对是【字符 5 减字符 0 得数值 5】——ASCII 编号设计成连续整数的红利(C 老代码里天天用);最后一对比出【字符数】与【字节数】的落差——中文一个字 UTF-8 占 3 字节,长度有两个口径,永远先问清是哪个。

五、30 秒实验

跑 print(chr(97), chr(98), chr(99))——得 a b c。再猜 chr(97 + 1) 是什么?字母表的编号是连续的,字符能当数字算——30 秒体会【文字就是数】。

六、常见误区

  1. 【一个字符就是一个字节】——错。ASCII 时代对,Unicode 时代错:一个汉字 UTF-8 占 3 字节、UTF-16 占 2 或 4 字节;char 一个字节的 C 语言因此处理不了中文。
  2. 【空字符串和 NULL 是一回事】——错。空字符串是【有盒子、零个字符】(Python 的 "",len 为 0);C 的 NULL 是【根本没有盒子】(指针指向空)——前者能安全调用方法,后者一碰就崩。
  3. 【字符串可以像列表一样原地改】——Python 里错。字符串不可变,s[0] = "X" 直接报错;所有【修改】其实都造了个新字符串(回收树莓派课 6-6)。
自测三问(点开对答案) 1. **C 字符串为什么需要 NULL 字符?** 答:C 不单独存字符串长度,函数靠扫描结尾的 \0 才知道字符串边界——缺了它就会读越界。 2. **len("你好") 和 len("你好".encode()) 为什么不同?** 答:前者数字符(2 个 Unicode 字符),后者数 UTF-8 编码后的字节(每个汉字 3 字节共 6)——字符与字节是两个口径。 3. **为什么 ord("5") - ord("0") 能得到 5?** 答:ASCII 里数字字符的编号连续(0 是 48、5 是 53),相减正好得出字符所代表的数值。

相关笔记