1、第三章第三章 数据类型数据类型 Chapter 3 Data Types2022-11-141本章学习目标:本章学习目标:初始初始化和化和二维二维数组数组指针指针运算运算二维二维向量向量基本基本类型类型及其表及其表示方法示方法2022-11-142Contents整型子类整型子类(sub-int Types)2C-串与串与string4整型整型(int Types)3 1浮点型浮点型(Floating-Point Type)3 3向量向量(vectors)6数组数组(Arrays)3 5指针与引用指针与引用(Pointer&References)3 72022-11-143这是个有类型的世界这
2、是个有类型的世界 Q1:现实生活,有哪些信息可以用计算机现实生活,有哪些信息可以用计算机可以管理呢?可以管理呢?Q2:所有的这些信息,在计算机里都是以什么所有的这些信息,在计算机里都是以什么样的数据形式来表达呢?样的数据形式来表达呢?“二进数二进数”,正确。,正确。“已数字化的数据已数字化的数据”,也算正确。,也算正确。“0“0和和1”1”,正确。,正确。“机器语言机器语言”,正确!,正确!2022-11-144所有的信息都用机器语言那些所有的信息都用机器语言那些0 0和和1 1来表达来表达编写程序岂不很难编写程序岂不很难尽量向尽量向“高级动物高级动物”的思维习惯做了一些接的思维习惯做了一些接
3、近近如果如果那么那么所以所以数据类型数据类型,就是计算机语言向人类语言靠近,就是计算机语言向人类语言靠近时,走出的第一步,很重要的一步。因为:时,走出的第一步,很重要的一步。因为:机器语言或汇编语里,没有数据类型一说。机器语言或汇编语里,没有数据类型一说。2022-11-145整个世界都可以用数据和处理来表达整个世界都可以用数据和处理来表达 整个世界就是一个程序;而万物是世界的数据=2022-11-146 通过抽象抽象将人类世界中的类型,移植到计算机中。官方定义:官方定义:数据类型是指定义了一组数据以及定义在这一组数据的操作,它是程序中最基本的元素。2022-11-147C+数据类型十分丰富,
4、大体上可分为基本数据类型十分丰富,大体上可分为基本类型、空类型、构造类型、指针类型、类类类型、空类型、构造类型、指针类型、类类型五种。如下型五种。如下图图所示。所示。最重要类型,也称为C/C+语言的基本基本数据类型数据类型,只有两个:“数值数值”和“字字符符”。第一是第一是“数值类型数值类型”。这样,在职工的信息中,比。这样,在职工的信息中,比如年纪,工龄、工资就有了归属如年纪,工龄、工资就有了归属第二是第二是“字符类型字符类型”。像职工姓名或家庭住址。像职工姓名或家庭住址2022-11-148数据类型数据类型基本类型基本类型空类型(无值类型)空类型(无值类型)void构造类型构造类型类类型类
5、类型class指针类型指针类型整型整型int实型(浮点型)实型(浮点型)字符型字符型逻辑型逻辑型bool结构类型结构类型 struct数组类型数组类型 array枚举型类型枚举型类型 enum向量类型向量类型 vector联合型类型联合型类型 union单精度型单精度型float双精度型双精度型double单字符型单字符型char宽字符型宽字符型w-char图:图:C+数据类型数据类型2022-11-149理解整型和实型理解整型和实型 数值类型又被分为“整型”和“实型”。整型就是不带小数位的数,而实型则是指带小数位的数,也称为“浮点数”。问题:问题:2=2.0,为什么不直接用,为什么不直接用浮
6、点数来代替整数浮点数来代替整数回答:因为在计算机里,对整数的运算要远远回答:因为在计算机里,对整数的运算要远远快于对浮点数的运算快于对浮点数的运算2022-11-1410 折中的结果就是虽然都是数值类型,但程序员在程序时,必须事先想好,哪些数据是必须带小数计算的,那些数据定为实型。所以,在人类的思维习惯与计算机特点之间,必须做一个折中。2022-11-1411理解数值的范围理解数值的范围 同顾及计算机的运行速度一样,与速度同样重要的是计算机的空间空间的考虑。这就是计算机的空间问题:任何一个量,都有一个大的上限,和小的下限,出了这个范围(比上限还大,比下限还小),就会称为溢出溢出。数值类型在被划
7、分为整型和实型后,将根据所占占用的空间用的空间而被继续划分为几种不同类型2022-11-1412字符型和各种整型、实型字符型和各种整型、实型类型标识符类型标识符类型说明类型说明长度长度 (字(字节)节)范围范围备注备注charchar字符型字符型1 1-128 127-128 127-2-27 7 (2 (27 7-1)-1)unsigned charunsigned char无符字符型无符字符型1 10 2550 2550 (20 (28 8-1)-1)short intshort int短整型短整型2 2-32768 32767-32768 327672 2-15-15 (2 (21515
8、-1)-1)unsigned short unsigned short intint无符短整型无符短整型2 20 655350 655350 (20 (21616-1)-1)intint整型整型4 4-2147483648 -2147483648 21474836472147483647-2-23131 (2 (23131-1)-1)unsigned intunsigned int无符整型无符整型4 40 42949672950 42949672950 (20 (23232-1)-1)floatfloat实型(单精度)实型(单精度)4 41.181.18*1010-38-38 3.40 3.4
9、0*101038387 7位有效位位有效位doubledouble实型(双精度)实型(双精度)8 82.232.23*1010-308-308 1.79 1.79*10103083081515位有效位位有效位long doublelong double实型(长双精度)实型(长双精度)10103.373.37*1010-4932-4932 1.181.18*1010493249321919位有效位位有效位2022-11-14131.整型整型(int Types)整型数的内部表示:二进制补码 好处:二进制补码运算没有加减的区别;即减法也可以用加法实现;符号位也可以参加运算。整型数的表示范围:取决于
10、二进制位数一个m位的整型若采用原码或反码表示,其范围是 ,若用补码表示,则范围是:。2022-11-1414说明:说明:(1)整型数据分为长整型(long int)、一般整型(int)和短整型(short int)。在int前面加long和short分别表示长整型和短整型。(2)整型数据的存储方式为按二进制数形式存储,例如十进制整数85的二进制形式为1010101,则在内存中的存储形式如下图所示。2022-11-1415(3)在整型符号int和字符型符号char的前面,可以加修饰符signed(表示“有符号”)或unsigned(表示“无符号”)。如果指定为signed,则数值以补码形式存放,
11、存储单元中的最高位(bit)用来表示数值的符号。如果指定为unsigned,则数值没有符号,全部二进制位都用来表示数值本身。例如短整型数据占两个字节,见下图。2022-11-1416 有符号时,能存储的最大值为2151,即32767,最小值为32768。无符号时,能存储的最大值为2161,即65535,最小值为0。有些数据是没有负值的,可以使用unsigned,它存储正数的范围比用signed时要大一倍。2022-11-1417.整型子类整型子类(Sub-int Types)字符型:表示范围:有符号:-128127 无符号:0255 输出形式与整型数不同:int a=65;char b=65;
12、couta“n”;coutb“n”;结果为:65 A 2022-11-1418枚举型:枚举型:自定义整数区间,甚至列举单个整数值 enum Week Mon,Tue,Wed,Thu,Fri,Sat,Sun;最大特点是可以给每个值指定一个在程序中直接使用的标记(枚举符)编程中将其当作整数常量用如:int a=7;if (a=Sun)cout “Sundayn”;2022-11-1419布尔型:布尔型:表示范围仅含整数和1,也可以表示成true和false,相当于:enum bool false,true;因为条件表达式、逻辑运算的结果都是或,因为条件表达式、逻辑运算的结果都是或,所以,很多的表达
13、式的值都与布尔型相对应所以,很多的表达式的值都与布尔型相对应2022-11-1420 常量的值是不能改变的,一般从其字面形式即可判别是否为常量。常量包括两大类常量包括两大类,即数值型常量(即常数)数值型常量(即常数)和字符型常量字符型常量。如12,0,3为整型常量,4.6,1.23为实型常量,包含在两个单引号之间的字符为字符常量,如a,x。这种从字面形式即可识别的常量称为“字面常量”或“直接常量”。什么是常量什么是常量2022-11-14211.普通的字符常量普通的字符常量 用单引号括起来的一个字符就是字符型常量。如a。#,%,D都是合法的字符常量,在内存中占一个字节。注意:注意:字符常量只能
14、包括一个字符,如AB 是不合法的。字符常量区分大小写字母,如A和a是两个不同的字符常量。引号()是定界符,而不属于字符常量的一部分。如cout a;输出的是一个字母 a。字符常量字符常量2022-11-14222.转义字符常量转义字符常量 除了以上形式的字符常量外,C+还允许用一种特殊形式的字符常量,就是以“”开头的字符序列。例如,n代表一个“换行”符。“coutn;”将输出一个换行,其作用与“cout endl;”相同。这种“控制字符”,在屏幕上是不能显示的。在程序中也无法用一个一般形式的字符表示,只能采用特殊形式来表示。常用的以“”开头的特殊字符见书P70中表33。2022-11-1423
15、3.字符数据在内存中的存储形式及其使用方法字符数据在内存中的存储形式及其使用方法 将一个字符常量存放到内存单元时,实际上并不是把该字符本身放到内存单元中去,而是将该字符相应的ASCII代码放到存储单元中。如果字符变量c1的值为a,c2的值为b,则在变量中存放的是a的ASCII码97,b 的ASCII码98,如图(a)所示,实际上在内存中是以二进制形式存放的,如图(b)所示。2022-11-14242022-11-1425u 既然字符数据是以ASCII码存储的,它的存储形式就与整数的存储形式类似。u 这样,在C+中字符型数据和整型数据之间就可以通用。u 一个字符数据可以赋给一个整型变量,反之,一
16、个整型数据也可以赋给一个字符变量。也可以对字符数据进行算术运算,此时相当于对它们的ASCII码进行算术运算。2022-11-1426例例1 将字符赋给整型变量。将字符赋给整型变量。#include using namespace std;int main()int i,j;i=A;j=B;cout i j n;return 0;2022-11-1427执行时输出 65 66i和j被指定为整型变量。但在第5和第6行中,将字符A和B分别赋给i和j,它的作用相当于以下两个赋值语句:i 65;j 66;2022-11-1428因为A和B的ASCII码为65和66。在程序的第5和第6行是把65和66直接
17、存放到i和j的内存单元中。因此输出65和66。可以看到:在一定条件下,字符型数据和整型数据是可以通用的。但是应注意字符数据只占一个字节,它只能存放0255范围内的整数。2022-11-1429例2 字符数据与整数进行算术运算。下面程序的作用是?#include using namespace std;int main()char c1,c2;c1=a;c2=b;c1=c1-32;c2=c2-32;coutc1 c2endl;return 0;2022-11-1430运行结果为A Bu a的ASCII码为97,而A的ASCII码为65,b为98,B为66。u 从ASCII代码表中可以看到每一个小
18、写字母比它相应的大写字母的ASCII代码大32。C+符数据与数值直接进行算术运算,字符a32得到整数65,b32得到整数66。u 将65和66存放在c1,c2中,由于c1,c2是字符变量,因此用cout输出c1,c2时,得到字符A和B(A的ASCII码为65,B的ASCII码为66)。2022-11-1431u 浮点型(又称实型)数据分为单精度单精度(float)、双双精度精度(double)和长双精度长双精度(long double)3种;u 在Visual C+6.0中,对对float提供提供6位有位有效数字效数字,对double提供15位有效数字,并且float和double的数值范围不
19、同。对float分配4个字节,对double和long double分配8个字节。浮点型浮点型(Floating-Point Type)2022-11-1432一个浮点数可以用两种不同的方式表示:(1)十进制小数形式。十进制小数形式。(2)如21.456,7.98等。它一般由整数部分和小数部分组成。C+编译系统把用这种形式表示的浮点数一律按双精度常量处理,在内存中占8个字节。浮点数的表示方法浮点数的表示方法2022-11-1433如果在实数的数字之后加字母F或f,表示此数为单精度浮点数,如1234F,43f,占4个字节。如果加字母L或l,表示此数为长双精度数(long double),在GCC
20、中占12个字节,在Visual C+6.0中占8个字节。2022-11-1434(2)指数形式指数形式(即浮点形式即浮点形式)一个浮点数可以写成指数形式,如3.14159可以表示为0.314159101,3.14159100,31.415910-1,314.15910-2等形式。在程序中应表示为:0.314159e1,3.14159e0,31.4159e1,314.159e2,用字母e表示其后的数是以10为底的幂,如e12表示1012。2022-11-1435其一般形式为:数符数符 数字部分数字部分 指数部分指数部分 上面各数据中的0.314159,3.14159,31.4159,314.15
21、9 等就是其中的数字部分。可以看到:由于指数部分的存在,使得同一个浮点数可以用不同的指数形式来表示,数字部分中小数点的位置是浮动的数字部分中小数点的位置是浮动的。例如:2022-11-1436a0.314159e1;a3.14159e0;a31.4159e1;a314.159e2;以上4个赋值语句中,用了不同形式的浮点数,但其作用是相同的。在程序中不论把浮点数写成小数形式还是指数形式,在内存中都是以指数形式(即浮点形式)存储的。例如不论在程序中写成314.159或314.159e0,31.4159e1,3.14159e2,0.314159e3等形式,在内存中都是以规范化的指数形式存放,如右图2
22、022-11-1437 大家都知道任何数据在内存中都是以二进制(1或着0)顺序存储的,每一个1或着0被称为1位,而在x86CPU上一个字节是8位。比如一个16位(2字节)的 short int型变量的值是1156,那么它的二进制表达就是:00000100 10000100。由于Intel CPU的架构是Little Endian,所以在Intel CPU 中,1156 应该怎样存放?2022-11-1438Big Endian 和和 Little Endian谈到字节序的问题,必然牵涉到两大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列系列CPU。Powe
23、rPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。那么究竟什么是big endian,什么又是little endian呢?其实big endian是指低地址存放最高有效字节(MSB)Most Significant Byte,而little endian则是低地址存放最低有效字节(LSB)Least Significant Byte。2022-11-1439 用文字说明可能比较抽象,下面用图像加以说明。比如数字0 x12345678在两种不同字节序CPU中的存储顺序如下所示:2022-11-14402022-11-1441u 为什么要注
24、意字节序的问题呢?你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。u 但是,如果你的程序要跟别人的程序产生交互呢?假如是两种语言C/C+语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则唯一采用big endian方式来存储数据。试想,如果你用C/C+语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?2022-11-1442 就拿上面的0 x12345678来说,你的程序传递给别人的一个数据,将指向0 x12345678的指针传给了JAVA程序,由于JAVA采取big endi
25、an方式存储数据,很自然的它会将你的数据翻译为0 x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,在你的C程序传给JAVA程序之前有必要进行字节序的转换工作。2022-11-1443 无独有偶,所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。目前应该littleendian是主流,因为在数据类型转换的时候(尤其是指针转换)不用考虑地址问题。2022-11-1444 那么 short in
26、t型变量1156,即:00000100 10000100。在奔腾系列的计算机中,1156 应该怎样存放?2022-11-1445 由于Intel CPU的架构是Little Endian,所以在Intel CPU 中,1156,即:00000100 10000100是按字节倒序存储的,那么就因该是这样:10000100 00000100 这就是定点数1156在内存中的结构。那么浮点数是如何存储的呢?那么浮点数是如何存储的呢?2022-11-1446 目前已知的所有的C/C+编译器都是按照IEEE(Institute of Electrical and Electronics Engineers
27、)(国际电子电器工程师协会)制定的IEEE 754浮点数表示法来进行运算的。这种结构是一种科学表示法,用符号符号(正或负)、指数指数(或阶码)和尾数尾数来表示,底数被确定为2,也就是说是把一个浮点数表示为尾数乘以2的指数次方再加上符号。2022-11-1447 下面来看一下具体的下面来看一下具体的 float 的规格:的规格:float共计32位,折合4字节由最高到最低位分别是第31、30、29、0位31位是符号位,1表示该数为负,0反之。3023位,一共8位是指数(阶码)位。220位,一共23位是尾数位。每8位分为一组,分成4组,分别是A组、B组、C组、D组。每一组是一个字节,在内存中逆序存
28、储,即:DCBA2022-11-1448 现在让我们按照IEEE浮点数表示法,一步步的将float型浮点数12345.0f转换为十六进制代码。在处理这种不带小数的浮点数时,直接将整数部转化为二进制表示:1,1110,0010,0100,0000 也可以这样表示:1,1110,0010,0100,0000.02022-11-1449 1,1110,0010,0100,0000.0 然后将小数点向左移,一直移到离最高位只有然后将小数点向左移,一直移到离最高位只有1位位,这种情况下,其实最高位也就是:“1”!即:1.11100010010000000 一共移动了一共移动了16位位,小数点每向左移一位
29、就等于在以小数点每向左移一位就等于在以“2”为底的科学计算法表示中指数为底的科学计算法表示中指数+1,所以原数就等于这样:1.11100010010000000*(2 16)。这就叫做二进制浮点数的这就叫做二进制浮点数的“规格化规格化”!注意:这和十进制科学计数法的规格化:X0.X *(10m),比如 123 0.123*(10 3)是不同的喔_2022-11-1450 OK,现在我们要的尾数和指数都出来了。显而易见,最高位永远是“1”,因为你不可能把买了16个鸡蛋说成是买了0016个鸡蛋吧?所以这个1我们还有必要保留吗?2022-11-1451 好的,我们删掉他!好的,我们删掉他!再举一个例
30、子!如:在32位浮点数中:0.6=0.1001(2)1.0011,0011,0011,0011,0011,001 如果删掉最高位的“1”,就比老老实实表示的23位尾数:0.1001,1011,1001,1011,0011,101 多了一位精度。在具体实现中,去掉规格化的多了一位精度。在具体实现中,去掉规格化的1,写入二,写入二进制浮点数!而当重新从机器中取出参加运算时,则补进制浮点数!而当重新从机器中取出参加运算时,则补上上1。因此。因此23尾数,加上省略的一位,其精度或有有效尾数,加上省略的一位,其精度或有有效尾数就变成了尾数就变成了24位位_2022-11-1452 呵呵_,继续回到我们的
31、数12345.0f:1.1110,0010,0100,000,00 *(2 16)。这样尾数的二进制就变成了:1110,0010,0100,0000,0 最后在尾数的后面补0,一直到补够23位:1110,0010,0100,0000,0000,000OK!到此为止,我们的尾数就计算完毕。!到此为止,我们的尾数就计算完毕。2022-11-1453 再回来看阶码(即指数),一共8位,可以表示范围是0255的无符号整数,也可以表示128127的有符号整数。但因为指数是可以为负的但因为指数是可以为负的,所以为了统一,同时为了使得浮点数0与整数0统一,即符号位、阶码位和尾数即符号位、阶码位和尾数位全部为
32、零。位全部为零。把十进制的整数化为二进制时,都把十进制的整数化为二进制时,都先加上先加上127,而在取出该浮点数时,再做一个,而在取出该浮点数时,再做一个减减127的的逆操作逆操作!在这里,我们的16加上127后就变成了 143,二进制表示为:10001111 思考:思考:128在机器中是如何表示的?在机器中是如何表示的?2022-11-1454 注意:注意:由于补码中“0”的表示是唯一的,故 【X】补 10000,对应的真值应该是:X 其实补码其实补码“10000”的形式是一个特殊情的形式是一个特殊情况,最高位的况,最高位的1既代表符号又代表数值!既代表符号又代表数值!2022-11-145
33、5继续继续 由于12345.0f 这个数是正的,所以符号位是0,那么我们按照前面讲的格式把它拼起来:符号位 阶 码 尾 数 0 10001111 11100010010000000000000即:0100,0111,1111,0001,0010,0000,0000,0000 再转化为16进制为:47 F1 20 00,最后把它翻过来,就成了:00 20 F1 47。即浮点数12345.0f 在机器最终表示为:00 20 F1 47 现在把现在把 5432.0f 转为二进制表示,试试看!转为二进制表示,试试看!2022-11-1456 有了上面的基础后,下面我再举一个带小数的例子来看一下为什么会
34、出现精度问题。按照IEEE浮点数表示法,将float型浮点数 35.6f 转换为十六进制代码。对于这种带小数的就需要把整数部和小数部分开处理。整数部直接化二进制:100011。小数部的处理比较麻烦一些了 2022-11-1457 具体办法,就是采用“乘乘2取整法取整法”,即:对被转换的十进制小数乘以2,取其整数部分作为二进制的小数部分,再乘以2,直到小数部分为0,或者已经取到了足够的位数。每次取的整数部分,按先后次序,构成了二进制小数从高到低位的数字排列。具体如下:2022-11-1458 0.621.2 0.1 0.220.4 0.10 0.420.8 0.100 0.821.6 0.100
35、1 0.621.2 0.10011 开始循环了哦 这说明0.60.1001 1001 1001(2)2022-11-1459 0.60.1001 1001 1001(2)假设,我们要求的精度是小数点后16位,那么,0.6的二进制表示形式应该是多少呢?是:是:1001 1001 1001 1001 吗?吗?不对!正确的应该是:1001 1001 1001 1010(见书P75)2022-11-1460 OK,我们继续,我们继续_ 嗯,刚才那个数还没转完呢,反正最后一直求也求不尽,加上前面的整数部分算够24位就行了,即:10 0011.1001 1001 1001 1001 10。某DX问:“不是
36、说尾数是23位吗?为什么要算够24位?”“晕!不是说过了要把第一个1去掉吗?所以当然要加一位喽!”2022-11-1461l现在开始向左移小数点,大家和我一起移,“1、2、3”好了,一共移了5位,5加上 127得132(呵呵),二进制表示为:1000 0100 l 所以:35.6f 的价码在计算机中表示为:1000 01002022-11-1462 So 符号位为,然后再,哎哟,不说了,越说越啰嗦,大家自己看吧:0,10000100,0001 1100 1100 1100 1100 110 即:0100 0010 0000 1110 0110 0110 0110 0110 42 0E 66 6
37、6 42 0E 66 66内存中应为内存中应为:66 66 0E 422022-11-1463 一个一个IEEE754浮点数的问题?浮点数的问题?将(100.25)D 转换成短浮点数。并且:(1)把十进制转成二进制。(2)规格化二进制 (3)计算出移码移码(阶码真值+偏移量)2022-11-1464 思考:这个思考:这个110是如何得出来的?是如何得出来的?一、把十进制转成二进制。(100.25)D (1100100.01)B二、规格化二进制 1100100.011.10010001*26三、计算出移码(阶码真值+偏移量)110+01111111100001012022-11-1465 补充:
38、补充:阶码是以移码的形式存储!对于单精度浮点数,偏移量为127(7FH),而双精度的偏移量为1023(3FFH)。存储浮点数的阶码之前,偏移量要先加到阶码上。比如:阶为2的三次方,则在单精度浮点数中,移码后的结果为127+3即130(82H),双精度为1026(402H)。2022-11-1466 最后,要特别注意:最后,要特别注意:浮点数有两个例外!A.数0.0存储为全零。B.无限大数的阶码存储为全1,尾数部分全零。符号位用来指示是正无穷还是负无穷。2022-11-1467 作业:作业:将十进制数12 和 0.25转换成单精度浮点数在计算机中存储的标准格式。2022-11-1468 十进制数
39、12 和 0.25转换成单精度浮点数后在计算机中存储的标准格式如下:2022-11-14694.C-串与串与string(C-string&string)C-串结构串结构每个字符占据每个字符占据1个字节个字节一个一个C串是一个字符序列,用串是一个字符序列,用来表示各种名字或者文字说明来表示各种名字或者文字说明C串的字符序列的最后总是添串的字符序列的最后总是添加有一个结束标志。即在加有一个结束标志。即在6个字个字符的字串(符的字串(“Hello!”)其空间)其空间存储有存储有7个字节个字节左边三图是不同细节的同一空左边三图是不同细节的同一空间结构描述间结构描述Hello!0 72 101 108
40、 108 111 33 0010010000110010101101100011011000110111100100001000000002022-11-1470 用双引号括起来的部分就是字符串常量,如abc,Hello!,a+b,Li ping都是字符串常量。字符串常量字符串常量abc在内存中占在内存中占4个字节个字节(而不是而不是3个字节个字节),见下图。编译系统会在字符串最后自动加一个0作为字符串结束标志。但0并不是字符串的一部分,它只作为字符串的结束标志。如:coutabcendl;输出输出3个字符个字符abc,而不包括而不包括0。2022-11-1471注意:注意:a和和a代表不同的
41、含义,代表不同的含义,a是字符串常量,是字符串常量,a 是字符常量。前者占是字符常量。前者占两个字节,后者占两个字节,后者占1个字节。个字节。分析下面的程序片段:分析下面的程序片段:char c;/定义一个字符变量 c=a;/正确 c=a;/错误,c只能容纳一个字符2022-11-1472请思考:字符串常量abcn包含几个字符?答:答:不是5个而是4个字符,其中“n”是一个转义字符。但它在内存中占5个字节(包括一个“0”字符)。编译系统遇到“”时就会把它认作转义字符的标志,把它和其后的字符一起作为一个转义字符。So,字符串常量要用字符数组来存放!,字符串常量要用字符数组来存放!2022-11-
42、1473u如果“”后面的字符不能与“”组成一个合法的转义字符(如b),则在编译时显示出错信息。u如果希望将“”字符也作为字符串中的一个字符,则应写为abcn,此时字符串包括5个字符,即a,b,c,n。如果有以下输出语句:cout abcn endl;则会输出:abc,然后换行。u思考一下:执行的输出又是什么呢?cout I say Thank you!n;2022-11-1474输出是:I say Thank you!2022-11-1475 知道了C串首地址,即可知道整个串,所以可以藉字符首址(字符指针)来操作C串,但要注意,串的第一个字符与整个串的操作不同,如:C串的输出操作:char*s
43、tr=”Hello”;cout *str endl;/显示H cout str endl;/显示Hello2022-11-1476 C串不能直接比较,因为字符指针的比较只是地址因为字符指针的比较只是地址值的比较而不是值的比较而不是C串的字符序比较串的字符序比较:1.cout(“join”join”?“”:“not”)”equaln”;/字面值比较 2.char*str1 “good”;char*str2 “good”;cout (str1str2?“”:“not”)“equaln”;/字符指针比较 2022-11-1477 3.char buffer16 “Hello”;char buffer
44、26 “Hello”;cout (buffer1buffer2?“”:“not”)“equaln”;/字符数组比较 结果:结果:not equal not equal not equal2022-11-1478So,不得不配备专门操作,不得不配备专门操作C-串的库函数串的库函数:strcpy(s1,s2);/从s2拷贝到s1strcmp(s1,s2);/比较s1与s2strcat(s1,s2);/连接s2到s1strrev(s);/将s倒排 strset(s,c);/将s全置为cstrstr(s,“ell”);/查找s中的子串strchr(s,c);/查找s中的字符 等等等等2022-11-1
45、479但字符指针操作C串的安全性受到质疑:char*str1;char*str2=new char5;strcpy(str2,“ugly”);strcpy(str1,str2);/错:str1没有空间可储strcpy(str2,“Hello”);/错:str2空间不够大str2=“Hello”;/错:原来的”ugly”空间脱钩,导致内存泄漏根源:根源:复制操作须以足够的目的地空间为前提,而所有C串操作的空间调配都是人为安排的,C串库函数一概不管。2022-11-1480类串string串类自定义串对应字符指针的C串操作:string a,s1=Hello;string s2=123;a=s1;
46、/copy cout (a s1?“”:not“)equaln;/compare cout as2 endl;/connect 2022-11-1481 reverse(a.begin(),a.end();/reverse cout a endl;cout a.replace(0,9,9,c)endl;/set cout (s1.find(ell )!=1?:not )foundn;/find string cout (s1.find(c)!=1?:not )的读入方式总是将前导的空格(所谓空格,即包括空格、回车、水平或垂直制表符等)滤掉,将单词读入,在遇到空格时结束本次输入getline 总
47、是将行末的回车符滤掉,将其整行输入2022-11-1483对字串“Hello,How are you?”的两种输入方式for(string s;cin s;)cout s “”;cout endl;string s;getline(cin,s);cout s a;sum+=a);cout sum “n”;2022-11-1485string流流 使用一个string流可以将输入输出设备和一块表示string字符串的内存区域连接起来。所有从程序的输出都将被保存到这块内存中,同时也可以从这块内存中读取数据到程序中。使用string流必须包括sstream头文件,在这个头文头文件,在这个头文件里定义
48、了三个类:件里定义了三个类:1.istringstream 类,从istream类派生出来;2.ostringstream 类,从ostream类派生而来;3.stringstream 类,他从iostream类中派生而来。2022-11-14861.ostringstream类类#include#include int main()ostringstream ostring;int ival=1;double dval=1.0;ostring ival dval ival dval;/将字符串转换为一个int和一个double2022-11-1488为了编程和阅读的方便,在C+程序设计中,常
49、用一个符号名代表一个常量,称为符号常量,即以标识符形式出现的常量。符号常量符号常量2022-11-1489例:例:符号常量的使用。符号常量的使用。#define PRICE 30 /注意这不是语句,末尾不要加分号注意这不是语句,末尾不要加分号int main()int num,total;num=10;total=num *PRICE;cout total=total endl;return 0;2022-11-1490程序中用预处理命令#define 指定PRICE在本程序单位中代表常量30,此后凡在本程序单位中出现的PRICE都代表30,可以和常量一样进行运算,程序运行结果为:total=
50、300 2022-11-1491请注意符号常量虽然有名字,但它不是变量。它的值在其作用域(在本例中为主函数)内是不能改变的,也不能被赋值不能被赋值。如用赋值语句“PRICE=40;”给PRICE赋值是错误的。使用符号常量的好处是:(1)含义清楚。(2)在需要改变一个常量时能做到“一改全改一改全改”。如#define PRICE 352022-11-1492 在定义变量时,如果加上关键字const,则变量的值在程序运行期间不能改变,这种变量称为常变量(constant variable)。例如:const int a3;/用const来声明这种变量的值不能改变,指定其值始终为3常变量常变量202