strlib.h#

该接口定义了动态分配字符串的通用库。传统 C 字符串与使用此接口定义的字符串之间的主要区别是:

  • strlib.h 接口负责内存分配,确保有足够的空间来保存每个字符串操作的结果。

  • strlib.h 接口的客户端应将所有字符串视为不可变,并避免写入字符数组。

字符串抽象数据类型#

字符串在 C 中就是一个字符序列(数组)。如果想要完整地掌握 C 字符串,我们需要从多个层面、不同角度来仔细研究。涉及到的知识点,保守估计也要四五节课的时间来讨论。

以抽象数据类型来看待字符串,可以将其当作一个逻辑单元来处理,无需过早地关注数据表示的内部细节。这也是我们一直推崇的抽象思维方法,即关注抽象层的行为,在学会如何有效使用之前,不必沉溺于细节问题。

以抽象观点处理字符串,我们可以利用 strlib.h 迁移很多 CS101 中的字符串处理案例。遗憾的是,C 标准库并没有提供现成的容器,在涉及中间数据存储时,暂时不太方便处理。后续学习完数组后,我们可以使用动态数组来实现这一目的。随着课程的深入,最终我们应该有能力实现一个泛型的 C 版本的容器,例如 vectorstack 等。

关于字符串的分层抽象如下所示:

分层抽象

strlib.h 接口

string.h 接口

语言级操作

机器级操作

其中,string.h 是 C 标准接口,后续课程会重点介绍。这也是你必须掌握的接口,但是用好该接口需要掌握很多底层的细节。常规的字符串处理,并不需要关注太多底层的细节,所以这里引入了 string 类型,并在标准库基础上封装了更好用的 strlib.h 接口,使得字符串操作相对容易些。

strlib.h 接口#

提起抽象类型,我们就要确定可以在该类型上实施的操作,这些被称为基本操作。

一些常见的操作比如:

  • 如何定义一个字符串变量/常量?

  • 如何从用户那里读入一个字符串?

  • 如何在屏幕上输出一个字符串?

除此之外,我们还需要:

  • 如何确定一个字符串的长度?

  • 如何比较两个字符串?是否相等?是否靠前?

  • 如何选择字符串中某个位置的字符?

  • 如何连接两个字符串?

  • 如何将单个字符转换为字符串?

  • 如何对字符串进行切分?

  • 如何判断一个字符串是否包含另一个字符串?

以上所有的操作,在 C++ 中都可以方便地通过类和成员方法来定义。虽然 C 没有 C++ 对象和方法的概念,但是我们可以使用自由函数来替代。

函数

功能

ConcatString(s1, s2)

通过将两个字符串首尾相连进行连接

IthChar(s, i)

返回字符串 s 中位置 i 的字符

SubString(s, p1, p2)

返回 s 索引区间为 [p1, p2] 的子字符串

CharToString(ch)

接受单个字符并返回由该字符组成的单字符字符串

StringLength(s)

返回字符串 s 的长度

CopyString(s)

将字符串 s 复制到动态内存中并返回新字符串

StringEqual(s1, s2)

如果字符串 s1s2 相等,则返回 true

StringCompare(s1, s2)

如果字符串 s1 按字典顺序位于 s2 之前,则返回 -1;如果相等,则返回 0;如果 s1 位于 s2 之后,则返回 +1

FindChar(ch, text, start)

从位置 start 开始,在字符串 text 中搜索的字符 ch,并返回该字符出现的第一个索引;如果未找到匹配项,则返回 -1

FindString(str, text, start)

从位置 start 开始,在字符串 text 中搜索字符串 str,并返回该字符串出现的第一个索引;如果未找到匹配项,则返回 -1

ConvertToLowerCase(s)

返回一个新字符串,其中所有字母字符都转换为小写

ConvertToUpperCase(s)

返回一个新字符串,其中所有字母字符都转换为大写

IntegerToString(n)

将整数转换为相应的数字字符串

StringToInteger(s)

将数字字符串转换为整数

RealToString(d)

将浮点数转换为相应的数字字符串

StringToReal(s)

将数字字符串转换为浮点数