1.5 字符串和字符

单引号和双引号在C语言中代表完全不同的含义,在某些上下文中,把他们搞混了不会产生错误信息,但是结果会出乎意料。

写一个字符加单引号跟写出这个字符在系统库实现中赋予的整数值是一样的。因此,在ASCII实现下,’a’和0141或者97是完全相同的。

写一个在双引号中的字符串,其实是写了一个指向一个无名字符数组的第一个字符的指针,这个字符数组被初始化为双引号中的字符并在最后加了一个二进制值为0的字符。

因此,语句

  1. print("Hello world\n");

  1. char hello[] = {'H', 'e', 'l', 'l', 'o', ' ',
  2. 'w', 'o', 'r', 'l', 'd', '\n', 0};
  3. printf(hello);

作用是相同的。

因为一个字符加单引号代表一个整数,而一个字符加双引号代表一个指针,所以编译器的类型检查就经常能找到用混的地方。例如对于

  1. char *slash = '/';

编译器就会产生一个错误信息,因为’/‘不是一个指向字符的指针。然而,一样写系统库实现并不检查参数类型,尤其对于printf的参数。因此,写下面的语句:

  1. printf('\n');

而不是

  1. printf("\n");

可能不会引发错误,但在运行时可能会产生出乎意料的结果。4.4节(57页)会详细讨论其他情况。

因为整型通常都大到能容纳多个字符,一些C编译器就允许多个字符存储在一个字符常量中,也就跟字符串常量一样。这就意味着写’yes’和写”yes”一样不会被检查出错误。后者意味着”一个各自包含着y、e、s和空字符的大小为4的连续内存块的第一个地址”,’yes’的含义则没有明确的定义,但是很多C的实现把它当作”一个由y、e、s三个字符的值用某种方式组合成的整数”。这两个量之间任何的相似性都绝对是巧合。

练习 1-1

一些C编译器允许嵌套的注释。写一个C程序,判断在这样的编译器上是不是真不会报任何错误。换句话说,这个程序应该在两种方式下都能运行,但是在两种方式下应该有不同的表现。提示:在字符串中注释起始符/*只是字符串的一部分,而在注释中的双引号是注释的一部分。

练习 1-2

如果你在写一个C编译器,你会不会让它允许用户嵌套注释?如果你在使用一个允许嵌套注释的C编译器,你会不会使用这个特性?你对第二个问题的回答会影响你对第一个问题的回答吗?

练习 1-3

为什么n-->0代表n-- > 0而不是n- -> 0?

练习 1-4

a+++++b是什么意思?