- 内容提要
- 前言
- 第 1 章 预备知识
- 第 2 章 开始学习 C++
- 第 3 章 处理数据
- 第 4 章 复合类型
- 第 5 章 循环和关系表达式
- 第 6 章 分支语句和逻辑运算符
- 第 7 章 函数——C++的编程模块
- 第 8 章 函数探幽
- 第 9 章 内存模型和名称空间
- 第 10 章 对象和类
- 第 11 章 使用类
- 第 12 章 类和动态内存分配
- 第 13 章 类继承
- 第 14 章 C++中的代码重用
- 第 15 章 友元、异常和其他
- 第 16 章 string 类和标准模板库
- 第 17 章 输入、输出和文件
- 第 18 章 探讨 C++新标准
- 附录 A 计数系统
- 附录 B C++保留字
- 附录 C ASCII 字符集
- 附录 D 运算符优先级
- 附录 E 其他运算符
- 附录 F 模板类 string
- 附录 G 标准模板库方法和函数
- 附录 H 精选读物和网上资源
- 附录 I 转换为 ISO 标准 C++
- 附录 J 复习题答案
7.5 函数和 C-风格字符串
C-风格字符串由一系列字符组成,以空值字符结尾。前面介绍的大部分有关设计数组函数的知识也适用于字符串函数。
例如,将字符串作为参数时意味着传递的是地址,但可以使用 const 来禁止对字符串参数进行修改。然而,下面首先介绍一些有关字符串的特殊知识。
7.5.1 将 C-风格字符串作为参数的函数
假设要将字符串作为参数传递给函数,则表示字符串的方式有三种:
- char 数组;
- 用引号括起的字符串常量(也称字符串字面值);
- 被设置为字符串的地址的 char 指针。
但上述 3 种选择的类型都是 char 指针(准确地说是 char*),因此可以将其作为字符串处理函数的参数:
可以说是将字符串作为参数来传递,但实际传递的是字符串第一个字符的地址。这意味着字符串函数原型应将其表示字符串的形参声明为 char *类型。
C-风格字符串与常规 char 数组之间的一个重要区别是,字符串有内置的结束字符(前面讲过,包含字符,但不以空值字符结尾的 char 数组只是数组,而不是字符串)。这意味着不必将字符串长度作为参数传递给函数,而函数可以使用循环依次检查字符串中的每个字符,直到遇到结尾的空值字符为止。程序清单 7.9 演示了这种方法,使用一个函数来计算特定的字符在字符串中出现的次数。由于该程序不需要处理负数,因此它将计数变量的类型声明为 unsigned int。
程序清单 7.9 strgfun.cpp
下面是该程序的输出:
程序说明
由于程序清单 7.9 中的 c_int_str( ) 函数不应修改原始字符串,因此它在声明形参 str 时使用了限定符 const。这样,如果错误地址函数修改了字符串的内容,编译器将捕获这种错误。当然,可以在函数头中使用数组表示法,而不声明 str:
然而,使用指针表示法提醒读者注意,参数不一定必须是数组名,也可以是其他形式的指针。
该函数本身演示了处理字符串中字符的标准方式:
str 最初指向字符串的第一个字符,因此*str 表示的是第一个字符。例如,第一次调用该函数后,*str 的值将为 m——“minimum”的第一个字符。只要字符不为空值字符(\0),*str 就为非零值,因此循环将继续。在每轮循环的结尾处,表达式 str++将指针增加一个字节,使之指向字符串中的下一个字符。最终,str 将指向结尾的空值字符,使得*str 等于 0——空值字符的数字编码,从而结束循环。
7.5.2 返回 C-风格字符串的函数
现在,假设要编写一个返回字符串的函数。是的,函数无法返回一个字符串,但可以返回字符串的地址,这样做的效率更高。例如,程序清单 7.10 定义了一个名为 buildstr( ) 的函数,该函数返回一个指针。该函数接受两个参数:一个字符和一个数字。函数使用 new 创建一个长度与数字参数相等的字符串,然后将每个元素都初始化为该字符。然后,返回指向新字符串的指针。
程序清单 7.10 strgback.cpp
下面是该程序的运行情况:
程序说明
要创建包含 n 个字符的字符串,需要能够存储 n + 1 个字符的空间,以便能够存储空值字符。因此,程序清单 7.10 中的函数请求分配 n + 1 个字节的内存来存储该字符串,并将最后一个字节设置为空值字符,然后从后向前对数组进行填充。在程序清单 7.10 中,下面的循环将循环 n 次,直到 n 减少到 0,这将填充 n 个元素:
在最后一轮循环开始时,n 的值为 1。由于 n−−意味着先使用这个值,然后将其递减,因此 while 循环测试条件将对 1 和 0 进行比较,发现测试为 true,循环继续。测试后,函数将 n 减为 0,因此 pstr[0]是最后一个被设置为 c 的元素。之所以从后向前(而不是从前向后)填充字符串,是为了避免使用额外的变量。从前向后填充的代码将与下面类似:
注意,变量 pstr 的作用域为 buildstr 函数内,因此该函数结束时,pstr(而不是字符串)使用的内存将被释放。但由于函数返回了 pstr 的值,因此程序仍可以通过 main( ) 中的指针 ps 来访问新建的字符串。
当该字符串不再需要时,程序清单 7.10 中的程序使用 delete 释放该字符串占用的内存。然后,将 ps 指向为下一个字符串分配的内存块,然后释放它们。这种设计(让函数返回一个指针,该指针指向 new 分配的内存)的缺点是,程序员必须记住使用 delete。在第 12 章中,读者将知道 C++类如何使用构造函数和析构函数负责为您处理这些细节。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论