《C陷阱与缺陷》一1.5 字符与字符串

1.5 字符与字符串

C语言中的单引号和双引号含义迥异,在某些情况下如果把两者弄混,编译器并不会检测报错,从而在运行时产生难以预料的结果。

用单引号引起的一个字符实际上代表一个整数,整数值对应于该字符在编译器采用的字符集中的序列值。因此,对于采用ASCII字符集的编译器而言,'a'的含义与0141(八进制)或者97(十进制)严格一致。

用双引号引起的字符串,代表的却是一个指向无名数组起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制值为零的字符'0'初始化。

下面的这个语句:

printf ("Hello world\n");

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

是等效的。

因为用单引号括起的一个字符代表一个整数,而用双引号括起的一个字符代表一个指针,如果两者混用,那么编译器的类型检查功能将会检测到这样的错误。例如:

char *slash = '/';

在编译时将会生成一条错误消息,因为'/'并不是一个字符指针。然而,某些C编译器对函数参数并不进行类型检查,特别是对printf函数的参数。因此,如果用

printf('\n');

来代替正确的

printf("\n");

则会在程序运行的时候产生难以预料的错误,而不会给出编译器诊断信息。本书的4.4节还详细讨论了其他情形。

译注:

现在的编译器一般能够检测到在函数调用时混用单引号和双引号的情形。
整型数(一般为16位或32位)的存储空间可以容纳多个字符(一般为8位),因此有的C编译器允许在一个字符常量(以及字符串常量)中包括多个字符。也就是说,用'yes'代替"yes"不会被该编译器检测到。后者(即"yes")的含义是“依次包含'y'、'e'、's'以及空字符'0'的4个连续内存单元的首地址”。前者(即'yes')的含义并没有准确地进行定义,但大多数C编译器理解为,“一个整数值,由'y'、'e'、's'所代表的整数值按照特定编译器实现中定义的方式组合得到”。因此,这两者如果在数值上有什么相似之处,也完全是一种巧合而已。

译注:

在Borland C++ v5.5和LCC v3.6中采取的做法是,忽略多余的字符,最后的整数值即第一个字符的整数值;而在Visual C++ 6.0和GCC v2.95中采取的做法是,依次用后一个字符覆盖前一个字符,最后得到的整数值即最后一个字符的整数值。
练习1-1. 某些C编译器允许嵌套注释。请写一个测试程序,要求:无论是对允许嵌套注释的编译器,还是对不允许嵌套注释的编译器,该程序都能正常通过编译(无错误消息出现),但是这两种情况下程序执行的结果却不相同。

提示:

在用双引号括起的字符串中,注释符 /*属于字符串的一部分,而在注释中出现的双引号" "又属于注释的一部分。
练习1-2. 如果由你来实现一个C编译器,你是否会允许嵌套注释?如果你使用的C编译器允许嵌套注释,你会用到编译器的这一特性吗?你对第二个问题的回答是否会影响到你对第一个问题的回答?

练习1-3. 为什么n-->0的含义是n-- > 0,而不是n- -> 0?

练习1-4. a+++++b的含义是什么?

时间: 2022-11-11

《C陷阱与缺陷》一1.5 字符与字符串的相关文章

《C陷阱与缺陷》一第1章 词法“陷阱”1.1 =不同于==

第1章 词法"陷阱" C陷阱与缺陷当我们阅读一个句子时,我们并不去考虑组成这个句子的单词中单个字母的含义,而是把单词作为一个整体来理解.确实,字母本身并没有什么意义,我们总是将字母组成单词,然后给单词赋予一定的意义. 对于用C语言或其他语言编写的程序,道理也是一样的.程序中的单个字符孤立来看并没有什么意义,只有结合上下文才有意义.因此,在p->s = "->";这个语句中,两处出现的'-'字符的意义大相径庭.更精确地说,上式中出现的两个'-'字符分别是不

《C陷阱与缺陷》一第0章 导读

第0章 导读 C陷阱与缺陷我的第一个计算机程序写于1966年,是用Fortran语言开发的.该程序需要完成的任务是计算并打印输出10 000以内的所有Fibonacci数,也就是一个包括1,1,2,3,5,8,13,21,--等元素的数列,其中第2个数字之后的每个数字都是前两个数字之和.当然,写程序代码很难第一次就顺利通过编译: I = 0 J = 0 K = 1 1 PRINT 10,K I = J J = K K = I + J IF (K - 10000) 1, 1, 2 2 CALL E

《C陷阱与缺陷》一导读

前 言 C陷阱与缺陷对于经验丰富的行家而言,得心应手的工具在初学时的困难程度往往要超过那些容易上手的工具.刚刚接触飞机驾驶的学员,初航时总是谨小慎微,只敢沿着海岸线来回飞行,等他们稍有经验就会明白这样的飞行其实是一件多么轻松的事.初学骑自行车的新手,可能觉得后轮两侧的辅助轮很有帮助,但一旦熟练过后,就会发现它们很是碍手碍脚. 这种情况对程序设计语言也是一样.任何一种程序设计语言,总存在一些语言特性,很可能会给还没有完全熟悉它们的人带来麻烦.令人吃惊的是,这些特性虽然因程序设计语言的不同而异,但对

C陷阱与缺陷

1.     <C陷阱与缺陷> int num[10]={0} ;   测试一下 num[0]  是否 等于 0[num]  ......   因为num是首地址   num+0 ==0+num 2. 其实C中只有一维数组   我们所说的 int a[3][4]   只是一个包含了三个元素  每个元素都是包含了四个整形值的一维数组     3.int  num[10][10]  ;  int *p=num[0]  ; 名为num的数组中 num[0]-num[9]表示的是 每个长度为10的一维

《C陷阱与缺陷》——总结

本文主要总结自己看完<C陷阱与缺陷>这本书后的感想. 总的来说,在看的过程中遇到一些知识点的时候,深入的去查询资料,去了解稳重的实质,会让你有一种知识点上的明悟. 本书1-3章,从词法,语法,语义三方面阐述了C中的缺陷和陷阱,对于C和C++者来说可以获得很多新的东西,规避一些自己平时忽略的东西. 本书4-7章,所讲的东西与编译器的联系太过紧密,很多东西对于现在的编译器来说都,都能够胜任,而不需要读者去考虑.故本博客所写<C陷阱与缺陷>系列文章主要为1-3章内容还有第6章内容. 第四

C陷阱与缺陷阅读笔记

本文主要记录<C陷阱与缺陷>第三章中的一些知识. 一.指针与数组: C语言数组特点: (1)C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来.由于数组的元素可以是任何类型的对象,当然也可是另外一个数组.这样,要"仿真"出一个多维数组就不是一件难事. (2)对于一个数组,我们只能够做两件事:确定该数组的大小,以及获得指向改数组下标为0的元素的指针.其他有关数组的操作,哪怕他们乍看上去是以数组下标进行运算的,实际上都是通过指针进行的.换句话说,任何一个数组

Swift字符与字符串

直接上基础的示例代码,多敲多体会就会有收获:百看不如一敲,一敲就会 1 import Foundation 2 3 4 /*******************字符********************/ 5 /* 6 1.单个字符来指定字符常量,如"A"."9" 7 2.转义字符表示特殊字符常量,如"\n"."\t" 8 3.使用 \u{n} 的Unicode形式,n代表一个1-8位的十六进制数 9 4.必须用双引号包起来

Delphi调用WinAPI 字符及字符串函数(3)

CharUpper - 字符或字符串转大写 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; Button4: TButton; Button5:

Delphi调用WinAPI 字符及字符串函数(1)

CharLower - 字符或字符串转小写 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; Button4: TButton; Button5: