C 语言重拾【二】字符串
1  | 
  | 
运行程序,输入结果如下:
Hi! What’s your first name?
Christine
Christine, what’s your weight in pounds?
154
Well, Christine, your volume is 2.47 cubic feet.
Also, your first name has 9 letters, and we have 40 bytes to store it.
该程序包含以 下新特性。
- 用数组(array)储存宇符串(character string)。在该程序中,用户输入的名被储存在数组中,该数组占用内存中 40 个连续的字节,每个字节储存一个字符值。
 - 使用名 
%s转换说明来处理字符串的输入和输出。注意,在scanf()中,name 没有&前缀,而weight
有(稍后解释,&weight和name都是地址)。 - 用 C 预处理器把字符常量 
DENSITY定义为 62.4。 - 用 C 函数 
strlen()获取字符串的长度。 
char 类型数组和 null 字符
C 语言没有专门用于储存字符串的变量类型,字符串都被储存在 char 类型的数组中。数组由连续的存储单元组成,字符串中的宇符被储存在相邻的存储单元中,每个单元储存一个字符,如下图:
注意上图中数组末尾位置的字符 \0。这是空字符(null character),C 语言用它标记字符串的结束。
空字符不是数字 0,它是非打印字符,其 ASCII 码值是(或等价于)0。C 中的字符串一定以空字符结束,这意味着数组的容量必须至少比待存储字符串中的字符数多 1。因此,程序清单中有 40 个存储单元的字符串,只能储存 39 个字符,剩下一个字节留给空字符。
那么,什么是数组?可以把数组看作是一行连续的多个存储单元。用更正式的说法是,数组是同类型数据元素的有序序列。程序清单通过以下声明创建了一个包含 40 个存储单元(或元素)的数组,每个单元储存一个 char 类型的值:
1  | char name [40];  | 
name 后面的方括号表明这是一个数组,方括号中的 40 表明该数组中的元素数量。char 表明每个元素的类型,见下图。
字符串看上去比较复杂!必须先创建一个数组,把字符串中的字符逐个放入数组,还要记得在末尾加上一个 \0。还好,计算机可以自己处理这些细节。
字符串和字符
字符串常量 "x" 和字符常量 'x' 不同。区别之一在于,'x' 是基本类型(char),而 "x" 是派生类型(char数组);区别之二是 "x" 实际上由两个字符组成:'x' 和空字符 \0,见下图:
strlen() 和 sizeof
sizeof 运算符报告,name 数组有 40 个存储单元。但是,只有前 11 个单元用来储存 serendipity,所以 strlen() 得出的结果是 11。 name 数组的第 12个单元储存空字符,strlen() 并未将其计入。下图演示了这个概念。
对于 PRAISE,
1  | 
用 strlen() 得出的也是字符串中的字符数(包括空格和标点符号)。然而,sizeof 运算符给出的数更大,因为它把字符串末尾不可见的空字符也计算在内。该程序并末明确告诉计算机要给字符串预留多少空间,所以它必须计算双引号内的字符数。
另外,还要注意一点:上一章的 sizeof 使用了圆括号,但本例没有。圆括号的使用时机否取决于运算对象是类型还是特定量?运算对象是类型时,圆括号必不可少,但是对于特定量,可有可无。也就是说,对于类型,应写成 sizeof(char) 或 sizeof (float);对于特定量,可写成 sizeof name 或 sizeof 6.28。尽管如此,还是建议所有情况 下都使用圆括号,如 sizeof(6.28)。
常量和 C 预处理器
#define
1  | 
编译程序时,程序中所有的 TAXRATE 都会被替换成 0.015。 这一过程被称为编译时替换(compile-timesubstitution)。在运行程序时,程序中所有的替换均己完成(见下图)。通常,这样定义的常量也称为明示常量(manifest constant)。
请注意格式,首先是 #define,接着是符号常量名(TAXRATE),然后是符号常量的值(0.015)(注意,其中并没有 = 符号)。所以,其通用格式如下:
1  | 
实际应用时,用选定的符号常量名和合适的值来替换 NAME 和 value。注意,末尾不用加分号,因为这是一种由预处理器处理的替换机制。为什么 TAXRATE 要用大写?用大写表示符号常量是 C 语言一贯的传统。这样,在程序中看到全大写的名称就立刻明白这是一个符号常量,而非变量。大写常量只是为了提高程序的可读性,即使全用小写来表示符号常量,程序也能照常运行。尽管如此,初学者还是应该养成大写常量的好习惯。
另外,还有一个不常用的命名约定,即在名称前带 c_ 或 k_ 前缀来表示常量(如,c_level 或 k_line)。
符号常量的命名规则与变量相同。可以使用大小写字母、数字和下划线宇符,首字符不能为数字。
const 限定符
C90 标准新增了 const 关键字,用于限定一个变量为只读。其声明如下:
1  | const int MONTHS = 12; // MONTHIS 在程序中不可更政,值为 12  | 
这使得 MONTHS 成为一个只读值。也就是说,可以在计算中使用 MONTHS,可以打印 MONTHS,但是不能更改 MONTHS 的值。const 用起来比 #define 更灵活。(详细内容将在接下来的博客中推出。)
参考文献
- C Primer Plus