![Visual C++从入门到精通(第5版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/338/27563338/b_27563338.jpg)
2.3 数据类型
C++语言中常用的数据类型包括数值类型、字符类型、数组类型、布尔类型、枚举类型、结构体类型、共用体类型、指针类型、引用类型和自定义类型。本节将详细介绍这些数据类型。
2.3.1 数值类型
C++语言中数值类型主要分为整型和实型(浮点类型)两大类。其中,整型按符号划分,可以分为有符号和无符号两大类;按长度划分,可以分为普通整型、短整型和长整型3类,如表2.2所示。
表2.2 整型类型
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-T57_24496.jpg?sign=1739264932-XHGhItg1mZUgrbIAZpthZUshlwJPeN1e-0-081affabda712f2f975fb3b1e8d812ff)
说明
表格中的[]为可选部分。例如,[signed] long [int]可以简写为long。
实型主要包括单精度型、双精度型和长双精度型,如表2.3所示。
表2.3 实型类型
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-T58_90698.jpg?sign=1739264932-Xj5k4c2zuQeXk9IkizW81iovVAiOUmwu-0-7810009d05964f22211b3003c17d41ff)
在程序中使用实型数据时需要注意以下几点。
(1)实数的相加
实型数据的有效数字是有限制的,如单精度float的有效数字是6~7位,如果将数字86041238.78赋值给float类型,显示的数字可能是86041240.00,个位数“8”被四舍五入,小数位被忽略。如果将86041238.78与5相加,输出的结果为86041245.00,而不是86041243.78。
(2)实数与零的比较
在开发程序的过程中,经常会进行两个实数的比较,此时尽量不要使用“==”或“!=”运算符,而应使用“>=”或“<=”之类的运算符,许多程序开发人员在此经常犯错。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P58_24544.jpg?sign=1739264932-RICgimJhtMlZru60gNyUjKALY6w3qm0Y-0-bc7e390f1b282656a501456e2261f43a)
上述代码并不是高质量的代码,如果程序要求的精度非常高,可能会产生未知的结果。通常在比较实数时需要定义实数的精度。例如:
【例2.2】 利用实数精度进行实数比较。(实例位置:资源包\TM\sl\2\2)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P58_24559.jpg?sign=1739264932-cG2M6riwx1L7SaEAqtxob6FPQXHO3po2-0-cbdde078dc005c8584a68e9163231941)
2.3.2 字符类型
在C++语言中,字符数据使用“' '”来表示,如'A''B''C'等。定义字符变量可以使用char关键字。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P58_24604.jpg?sign=1739264932-p68nsGqB7vDvG6x7udZr7wUN25cS0VOy-0-f5fa8959fb2ef69c1181493a113052ca)
在计算机中字符是以ASCII码的形式存储的,因此可以直接将整数赋值给字符变量。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P58_24614.jpg?sign=1739264932-uRTKxKjgGkp7TiJFOcWVWjlBswbWp6Ds-0-59e993bd999217e4131070b0a89edcdd)
输出结果为“a”,因为97对应的ASCII码为“a”。
2.3.3 数组类型
数组是指具有相同数据类型的一组元素的集合,数组中的元素是按顺序存储在内存中的。数组按维数划分,可以分为一维数组、二维数组和多维数组。
1. 一维数组
在C++语言中,一维数组的定义格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24707.jpg?sign=1739264932-nCVCgTvEqMfL6LjIXbyTkbauRjcT60p6-0-4c0042d01ba64f78088ff8d1624d6ed8)
例如,下面的代码定义了一个具有10个元素的整型数组。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24712.jpg?sign=1739264932-tPu2ta1Ocb3rF394t2PW1whBgX3Nzkw0-0-e03344091d35456d4fee532796c5d075)
在定义数组后,还需要访问数组中的元素。数组元素是通过数组名和下标来访问的,例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24717.jpg?sign=1739264932-nmRZ9U7rh7kOufprWJ6uoX2YPG18hLnF-0-83aaa32db5dcbd797486d9e38e1154c0)
上面的代码将数组array中的第2个元素值设置为1。
注意
数组的下标是从0开始的。array数组共包含10个元素,下标分别为0、1、2、…、9。如果出现array[10],将会导致数组访问越界,发生意想不到的后果。编译器并不能识别此类错误,因此在访问数组元素时一定要谨慎,不要发生数组访问越界的情况。
在定义数组时,用户可以直接为数组赋初值。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24722.jpg?sign=1739264932-tV8FVJwFu8tYqPZdOrgBfvN823Sp6DpO-0-ddade9f156fae22cc5150aecbbca2fdc)
也可以只对部分元素赋初值。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24727.jpg?sign=1739264932-EPpg3v7dtPGR04HNVF0qkikkTKOrwleA-0-823695eb994da94f23b452e9d170e572)
上面的代码只对array数组的前5个元素设置了初值。注意,不能给数组提供超过数组长度的初始值,例如下面的代码是不能通过编译的,将提示太多的初始值。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24732.jpg?sign=1739264932-ISY9Pn4jYqrwY9npIjgUwfnltsi8bR2j-0-8c9fac9e00ebd6abd518fa5b96f13956)
如果将数组元素全部初始化为0,用户可以简写为:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24737.jpg?sign=1739264932-4BY8aqoSycUyBgJdBGcLUcucaRwdTr9K-0-95c7fe322c5a63cc7e403e4e9acfe008)
但是上述方式不能够将全部数组元素初始化为其他的值,例如将全部数组元素初始化为1。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24742.jpg?sign=1739264932-AQTYY7K6hXnxrV8pPLJOXbUfnpZVDCcp-0-4ac578a5c683831bffb5bd99c59e54e7)
上面的代码将导致第1个数组元素的值为1,其他数组元素的值为0。
如果需要对数组全部元素进行初始化,可以省略数组长度,但是数组下标符号“[]”不能省略。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24779.jpg?sign=1739264932-e1ObYbkT9EEyQd5ZgKVISTijpMeHHN0Y-0-bdb2f36045869c9299be4c7a3c1fe063)
2. 二维数组
在C++语言中,二维数组的定义格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24784.jpg?sign=1739264932-0knTDSYao0LKmOVn6UfWjcaHmxcqiRIW-0-c18e54f537ba0144b5b25bd861f6f775)
例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24789.jpg?sign=1739264932-IqiFRfXyGtrlhuPM7RFTzc2mgde1KLgO-0-8ec41d23f78fcd0aea8d187d31122c7d)
二维数组元素也是通过数组名和下标来访问的。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24794.jpg?sign=1739264932-o7767g1JLX5q2JJvADc4kvd4Ot6gNoeW-0-f6c61706dc38d242ba4c6fe3ceea6d14)
可以认为二维数组是一个特殊的一维数组,只是数组中的每一个元素又是一个一维数组。例如,array[3][4]可以认为是一个一维数组array[3],其中的每一个元素又是一个包含4个元素的一维数组。
在定义二维数组时也可以直接进行初始化。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24799.jpg?sign=1739264932-WZXVC5Oj3zHC2b9nD1hLfjyguwrnHuyJ-0-94ad2735bb477cb5d04283370ae06428)
用户也可以在一个大括号内直接初始化所有的元素。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24804.jpg?sign=1739264932-QvKxTo5issfGA3StGeOS3KKMcLkJM9Wp-0-cc553fd5c7eed512738d321ceb2e0571)
但是并不提倡该方法,因为如果数组元素过多,将很难界定每一个元素。
与一维数组类似,二维数组也可以只对部分元素进行初始化。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24809.jpg?sign=1739264932-sP53MQdwDIO08HYf6Q2QYi43yRFq0uaI-0-c64494069eaa7064b8d92f52aac46986)
结果是对每一行第1个元素赋值,其他元素为0。
对于二维数组,还可以只对某一个元素或某一行赋值。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24814.jpg?sign=1739264932-Jg5oVio0yyYFIK9R8wnCHQasaybmpmsU-0-831d1e1df3257913d5802cd21c5d12cd)
在定义二维数组时,如果需要提供全部元素的初始值,可以省略第一维的长度,但是不能省略第二维的长度。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24824.jpg?sign=1739264932-IYKgWh8feJaFTfpzlLMhqrl1QMMTUJz3-0-8a7cd6e9ced50c3428b0356108592a57)
注意
最后一行代码,只提供了11个元素的初始值,但是数组array却包含12个元素,最后一个元素被初始化为0。
2.3.4 布尔类型
在逻辑判断中,结果通常只有真和假两个值。C++语言中提供了布尔类型bool来描述真和假。bool类型共有两个取值,分别为true和false。顾名思义,true表示真,false表示假。在程序中,bool类型被作为整数类型对待,false表示0,true表示1。将bool类型赋值给整型是合法的,反之,将整型赋值给bool类型也是合法的。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P61_24863.jpg?sign=1739264932-vnlbF56dLbfUnhilXyN8JMD5Yvlt8sp5-0-8e77f9a5f3a6b10801d971e32efdd645)
2.3.5 枚举类型
在开发程序时,一个对象可能会存在多个状态。例如,Oracle数据库具有关闭、打开、装载、卸载等状态。如果直接在程序中使用0表示关闭状态,1表示打开状态……会使得代码难以阅读。有些用户定义了有意义的常量来表示各个状态,但是在涉及具体函数调用时,无法限制只允许使用“0、1、2、3”。
枚举类型提供了解决上述问题的最好方法。枚举类型提供了一组常量的集合。在定义函数时,将函数参数设置为枚举类型,这样可以限制调用函数必须提供枚举类型中的某个常量,而不能随意输入一个整数。在C++语言中,可以使用enum关键字定义枚举类型。定义格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P61_24883.jpg?sign=1739264932-gnBN1VNSD7QLVDiGPZ2yC2kWocE0c3hy-0-65a0b23a34edc479570c523bd22b542b)
使用enum关键字定义一个枚举类型,例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P61_24888.jpg?sign=1739264932-eDVZO7LHD4zPoYbX9SWjflQCYUNuUkzU-0-2f209dd0dfb3d86ab083c138eba14bcb)
在定义枚举类型时,可以为各个常量提供一个整数值,如果没有提供整数值,默认第1个常量值为0,第2个常量值为1,以此类推。例如上面的代码中,CLOSE常量的值为0,OPEN的值为1……
下面为枚举类型设置常量值。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P61_24893.jpg?sign=1739264932-4ulNS1PnXkUwsb78r2qEZo9iXPMmnVMQ-0-050eed2623d248659731486d95cb84c2)
在上面的代码中,将枚举常量CLOSE设置为1,MOUNT设置为4。那么OPEN和UNMOUNT的值是多少呢?由于没有为OPEN和UNMOUNT提供常数值,它们的值应为前一个常量值加1,即OPEN和UNMOUNT的值分别为2和5。下面来演示一下枚举类型的实际应用。
【例2.3】 应用枚举类型。(实例位置:资源包\TM\sl\2\3)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P61_24898.jpg?sign=1739264932-QmRBR7sdkKIfAWJCf9L70Ih6rSelrdHO-0-c7f65b4917baa1fc2a0fd17c4f015957)
2.3.6 结构体类型
结构体是一组变量的集合。与数组不同,结构体中的变量可以有各种类型。通常将一组密切相关的信息组合为一个结构体,以描述一个对象。例如,描述学生信息,包括姓名、性别、年龄、地址等信息,可以定义一个结构体来描述学生的所有信息。
【例2.4】 定义结构体类型。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P62_25091.jpg?sign=1739264932-caOlB3MC3ZlBF1DCvuAtiPxeeQJHcVlq-0-8caf442401fdc57334cd6a1e7975979a)
其中,关键字struct用于声明一个结构体类型。结构体中的变量被称为成员,如name、sex等。
注意
在声明结构体时,不要忘记末尾的分号。
在声明一个结构体后,可以定义一个结构变量。在C语言中定义结构变量的语法格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25146.jpg?sign=1739264932-Zmz0r6Y6Jkkwi8r8BXUj8XFPtIGlliIT-0-370d2a49100062fc8efeebd5eb35bbc2)
例如,下面的代码采用C语言的形式定义结构体变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25151.jpg?sign=1739264932-oiOJSt5w1MiDXkFGKdqUqEqhIHU9ypcS-0-397d4eae2d5d3e335c0f9fc213544032)
在C++语言中定义结构体变量的格式与定义普通变量的格式相同。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25156.jpg?sign=1739264932-xGvsPnxD2fCS2tBlLA1scWw3tB3Wa1rD-0-37d89b92059c86b1f19a7322e3193902)
当定义一个结构体变量时,编译器将为变量分配足够的空间以容纳结构体中所有的成员。在声明结构体类型时,也可以直接定义结构体变量。例如:
【例2.5】 定义结构体类型时直接定义结构体变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25161.jpg?sign=1739264932-MtnW4BkrrvvDJMMpo4fIwuw0nI0VM8uo-0-d8ffbaccfa75d0e0cb2f600fdc1fe05e)
上述代码在声明结构体Student的同时,定义了一个结构体变量stdnt。此外,在定义结构体时,如果只需要定义一次结构体变量(在其他地方不需要定义该类型的结构体变量),可以不写结构体类型的名称,而只给出结构体变量。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25201.jpg?sign=1739264932-WuanRj2MArLprybhcLUIt9R4hhQx8zul-0-af70b5c7072df401dde6669af9f161c1)
在使用结构体时,需要访问结构体中的各个成员。可以使用“. ”符号来访问结构体中的成员。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25236.jpg?sign=1739264932-mvR78FOCQx4nroltVmNN6O4MWlUgaAEb-0-cc7704c4f470e6864b6d6d6a4ac7c949)
两个整型变量可以相互赋值,那么两个结构体变量能否直接赋值呢?答案是可以的。观察如下代码。
【例2.6】 结构体变量之间的赋值。(实例位置:资源包\TM\sl\2\4)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P64_25274.jpg?sign=1739264932-w1QRGOfRaILIwIp6R6fYsfJuWPCQMSU4-0-6d089f6bbfca25ffb64c17f01cdae192)
执行上述代码,结果如图2.2所示。
从图2.2中可以发现,another变量的age成员与stdnt变量的age成员是相同的;不仅如此,这两个变量的其他成员数据也相同。
在定义结构体变量时,编译器会为变量分配足够的空间以容纳结构体的所有成员。如果定义如下的一个结构体变量,编译器将为其分配多大的空间呢?
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P64_25387.jpg?sign=1739264932-S1xtQYNof68rHiBsqPD0IU0zOcbBrc85-0-3c735ba9e2a1f61e384fee444e9249ca)
图2.2 结构体变量赋值
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P64_25359.jpg?sign=1739264932-SUqUWYqx8ZIf7NY49Dj7TFZuyLgt4fAV-0-397a80c57bf96a0bfe3d409266036093)
分析结构体成员,其中memOne类型为double,占用8个字节;memTwo类型为char,占用1个字节;memThree类型为int,占用4个字节。在定义结构体ByteAlign的变量时,应分配13个字节。但实际使用sizeof函数测试时,发现结构体ByteAlign的变量占用了16个字节。究竟是如何多出3个字节的呢?这涉及结构体的字节对齐问题。编译器在为结构体变量分配空间时,保证下一个成员的偏移量应为该成员数据类型长度的整数倍。分析一下ByteAlign结构在内存中的简单布局。首先为memOne成员分配空间,假设起始位置从0开始,memOne成员将占用0、1、2、3、4、5、6、7共8个字节。接下来为成员memTwo分配空间,由于char类型占用1个字节,因此,memTwo将占据8的位置,因为当前位置8与4是整除的。接下来为memThree成员分配空间,该成员为int类型,占用4个字节。当前位置为9,并不是4的整数倍,因此需要空出3个字节(9、10、11),memTree从12的位置开始分配4个字节的空间。这样就导致了实际分配的大小与“理论上”的大小不一致。
在开发应用程序时,有时需要在一个字节中表示多项内容。例如,在描述IP协议的首部时,其首部长度占4位(bit),版本号占4位,在定义描述IP协议首部的结构体时,该如何实现呢?与其他计算机语言不同,C/C++语言提供了位域,允许用户单独访问一位数据。例如,下面的代码定义了一个IP结构体,用于描述首部长度和版本号。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P65_25404.jpg?sign=1739264932-R6OecYUoxf1hBVPIabUzf0GQKX6YZVLc-0-f906e360c6ea941d4bf4566d360b725f)
其中,headerlen成员类型为无符号字符型,理应占1个字节(8位),通过使用位域符号“:”和长度4,headerlen成员只占了“半”个字节—4位。在定义位域字段时,也可以不指定成员名称,这样可以预留一些空间。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P65_25429.jpg?sign=1739264932-8QlYCftl8nEdGcv7u9OgB4KytwfCXPwv-0-c36ae368965acfc13c7fa9399649ff1d)
用户在访问memTwo成员时,将直接从一个字节的第5位开始读取数据。
2.3.7 共用体类型
共用体类型提供了一种机制,使得多个变量(共用体中的成员)可以共享同一个内存地址。下面的代码定义了一个共用体类型unType。
【例2.7】 定义共用体类型。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P65_25459.jpg?sign=1739264932-5EJDYjoAG7qKHm1HZGyGWPmQJpC7Z5FF-0-4130f752a1dc6d3cabb5393d400d6f1e)
定义共用体与定义结构体类似,只是关键字不同,共用体使用union关键字。在共用体unType中,成员cdata与idata的内存起始位置相同,如图2.3所示。
由于共用体成员共用内存空间,因此如果视图改变了一个共用体成员的值,其他成员的值也会发生改变。但是,对于共用体来说,通常一次只需要使用一个成员。当定义一个共用体变量时,编译器会根据共用体成员中占用最多内存空间的变量分配空间,这样使得共用体中的所有成员都能够获得足够的空间。例如,定义一个unType类型的变量tg,编译器将为其分配4个字节的空间,因为idata需要4个字节的空间,cdata只需要1个字节的空间。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P65_25484.jpg?sign=1739264932-sD1VJeE76jqY6eAhw6DsRwraq5H8aobq-0-6b7b15bc3fdfb93fe36d199c734b7fe5)
图2.3 共用体成员内部布局示意图
注意
共用体的内存空间可以用来存放数种不同类型的成员,但是在某一时刻只有一个成员起作用,起作用的成员是最后一次存放的成员。
2.3.8 指针类型
在C++语言的数据类型中,指针类型是最难掌握的,也是最重要的数据类型之一。灵活地应用指针,能够提高代码的执行效率。在介绍指针之前,先来回顾一下变量的属性。变量具有左值和右值两个属性,即变量的地址和变量的实际数据。指针是用来存放变量的地址的,即指针的值能够存储变量的地址。直接使用变量时,就称之为直接访问,而通过指针获得变量地址进行使用的方式被称为间接访问。这就像将一个物品放在银行的保险箱里,如果将钥匙带在身上,需要时直接打开保险箱拿东西,这就是直接访问。而为了安全起见,将保险箱的钥匙锁在家中的抽屉里,当你要拿东西时,首先要回家取得保险箱的钥匙,然后再使用钥匙打开保险箱,这就相当于用指针调用变量的地址所进行的间接访问。
如果一个指针存储了变量的地址,那么通过指针就能够访问到变量的值,因为变量的值是存储在变量的地址上的。假设有变量var,指向变量var的指针为pavr,如图2.4所示描述了指针与变量的关系。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P66_25544.jpg?sign=1739264932-2aG4j8nhULzng2qgM9oXocW1OzHertQx-0-f7acbd111ab8e99c0f4000eb541e7467)
图2.4 指针与变量的关系
在C++中,定义指针的语法格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P66_25501.jpg?sign=1739264932-UMZgZ4ZRH8BXtoQ8YQJZyfjdPxrie7aZ-0-f0f45fd599b9bd949e531efb0b5847c3)
例如,下面的代码定义了一个整型的指针变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P66_25506.jpg?sign=1739264932-m8oFJjZK9qHA0gk2fcWHbo4BdqvqrUla-0-e92557b5f8251d19bde139ea4506fdf9)
只定义一个指针变量是没有意义的,还需要为指针变量赋值。指针变量的值应该是一个有意义的地址(通常是某个变量的地址),而不是数据。如何将变量的地址赋值给指针变量呢?C++中可以使用“&”运算符来获得变量的地址。下面的代码演示了通过“&”运算符获得变量地址,并将其赋值为指针变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P66_25511.jpg?sign=1739264932-y11T6rNfWCBBIw6hLSVrVgssnN3HnwQX-0-c9869db0606ad7ac8bd3cf14b065f303)
当指针被赋予一个有效的变量地址后,如何通过指针访问或修改变量的数据呢?在指针变量前使用“*”运算符,即可直接访问变量的数据。
【例2.8】 使用“*”运算符访问指针数据。(实例位置:资源包\TM\sl\2\5)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25566.jpg?sign=1739264932-m6xV8L5zunxzUGiLSwFP6n3U30zDqHMn-0-01d4d9c6b56f6b062d407b943cc55bcb)
执行代码,结果如图2.5所示。
分析上述代码,首先定义了一个整型变量ivar,将其初始化为10;然后定义一个指针变量pvar,将其初始化为ivar的地址;接着修改指针变量指向的地址上的数据;最后输出变量ivar的值和指针变量pvar的值。从图2.5中可以发现,变量ivar的值为8,表明通过指针变量修改了ivar的值。
指针变量不仅可以指向简单的变量,还可以指向数组变量。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25606.jpg?sign=1739264932-q499yTDumou1ks2FYIGFVewtBPZL35Xo-0-af41f177234790cbe858538546424a3d)
在上面的代码中,&iarray[0]表示获取数组中第1个元素的地址,即数组的首地址。对于数组来说,数组名同样表述数组的首地址,因此下面的代码与上述两行代码是完全相同的。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25616.jpg?sign=1739264932-1TKYkOjO6sYU9z1nInJv6NyjR6HpNT0f-0-18d3c097f0a697339da2f39cba2a13d1)
图2.6描述了当前指针变量pvar与数组iarray之间的关系。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25663.jpg?sign=1739264932-shNqcPMuUM1R4jW56VgxeSEDgwpKKqF0-0-81b5059498257f3809f790b9cc82f65e)
图2.5 使用指针变量修改数据
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25664.jpg?sign=1739264932-MnxpmcQCMbTvGfLZ3jhgL24ZaIoJSXxc-0-d0f7ab859fa6ff947fbb1951e28be47e)
图2.6 指针变量pvar与数组iarray之间的关系
当一个指针变量指向一个数组后,通过指针变量即可访问该数组中的每一个元素。例如,下面的代码利用指针输出数组中的每一个元素。
【例2.9】 使用指针变量输出数组元素。(实例位置:资源包\TM\sl\2\6)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25626.jpg?sign=1739264932-dsVr0pxkb4rHw43QtoLkCSnODeJnGMiQ-0-ff849e7c366f2a306564ef72c2ae2d82)
执行上述代码,结果如图2.7所示。
在上述代码中,注意“pvar = pvar + 1;”语句,该语句的作用是使指针指向数组中的下一个元素,而不是简单地将指针地址加1或将指针值加1。语句“pvar = pvar + 1;”是移动指针pvar指向的地址,移动量不是1个字节,而是1个数组元素的大小,更准确地说应该是指针pvar的类型(这里为int类型)的大小。
在开发程序时,如果需要使用一组指针,可以定义一个指针数组。例如,下面的代码定义了一个整型的指针数组。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90816.jpg?sign=1739264932-or7sziWXkLUnTFGuKNgMASlNvoFfGXwL-0-0b1d50b4bccb3fbc19002adbd77e23d9)
对于指针数组来说,数组中的每一个变量均是一个指针变量。下面的代码演示了指针数组的应用。
【例2.10】 利用指针数组存储数据。(实例位置:资源包\TM\sl\2\7)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90821.jpg?sign=1739264932-3QDtGgu7FxNXFMKBuYHpZxDrVCa4ce1V-0-5f1eaf2487962d360d73ec4f3151b816)
执行上述代码,结果如图2.8所示。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90899.jpg?sign=1739264932-3zxBgZFWFC4Km98BbbUfKSRvg3NDM5MF-0-a5b5adc6166c5debc91773cd33259412)
图2.7 利用指针遍历数组
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90900.jpg?sign=1739264932-5eb9WHDo8igojMj9SZgfQYKmcYJCfgQk-0-70367aeb216d645dbabcf2c4ce53dc6f)
图2.8 指针数组应用
在定义指针时,也可以使用const关键字。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90871.jpg?sign=1739264932-81fskGz3UBjO6dy6CSmBTq8EsoFGkUAA-0-0fa2a8e08bd1336360c5e37e370db358)
对于指针pvar来说,用户不能够修改pvar指向的值,但是可以修改pvar指向的地址。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90881.jpg?sign=1739264932-qslIIZwHZKQcX9SV3Z8OlKEO4LB0KlKD-0-a31e47f9149801ee47a3256384b27e6c)
在使用const关键字定义指针时,也可以将const关键字放置在指针变量的前面,但是指针变量的性质发生了改变。观察如下代码:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25807.jpg?sign=1739264932-sD8fyK2rqxiTPcphmvpt9FmZWZBE0HRF-0-f826801b399a0610cd36ab70065ab092)
上面的代码定义了一个常量指针pvar,使用户不能够修改pvar指向的地址,但是可以修改pvar指向的数据。
在定义指针时也可以同时使用两个const关键字。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25832.jpg?sign=1739264932-N9iQmNQhmUGXsiwgYhSlFfmFoxDqF1tK-0-b36cf9c26b36f127bf7facf4b713ba9b)
在上面的代码中,用户既不能修改pvar指向的地址,也不能修改pvar指向的数据。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25842.jpg?sign=1739264932-2aNzrd6uy6rxJoCvLVcIJC1R8Ib9oeqA-0-d9218df7f87df558890d77d361c95905)
2.3.9 引用类型
引用可以认为是一个“别名”,即目标的代名词。当定义一个引用时,需要为其指定一个对象,即目标。此时,引用就成了目标的代名词,操作引用与操作实际的目标对象是相同的。定义引用的格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25857.jpg?sign=1739264932-Smzkq6j3hQWwwBdEZIwNTH0stAwI5zGX-0-ca1498ea6a70ef3708f93ef01fe8837b)
下面的代码定义了一个引用对象。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25862.jpg?sign=1739264932-AsiGjNzfIafVZLibjwTBOBfQATV5JTGm-0-42d0a86a67cbcd1c193b20d673c60468)
在定义引用对象后,即可使用引用对象操作目标对象。
【例2.11】 使用引用对象代替目标对象。(实例位置:资源包\TM\sl\2\8)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25872.jpg?sign=1739264932-xW6OHYOaXF0GPtPBcgyz67QuwxKH1lzf-0-5e1b469fffc95cb8782fc68677947ed1)
执行上述代码,结果如图2.9所示。
从图2.9中可以看到,通过设置引用变量的值,修改了变量ivar的值。在程序中如果对引用对象进行取地址,返回的将是目标的地址,因为引用是目标的代名词。
【例2.12】 访问引用对象的地址。(实例位置:资源包\TM\sl\2\9)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25936.jpg?sign=1739264932-5Iejqo3R6aal79wOkG6LhtBUnIgwVoU9-0-2f51faebfb439e5480839a46cb465a2e)
执行上述代码,结果如图2.10所示。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25984.jpg?sign=1739264932-K1CC9f15vm3N6SFbmZPiygcrYXIbPeu5-0-9d51d34fd4708ebe78853d8b98d67d7e)
图2.9 使用引用操作对象
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25985.jpg?sign=1739264932-cOJck68k3VMdVYQ3UZQLNkceQ0OJkxc5-0-e436ba88be9276f0ddf988975a3dab64)
图2.10 对引用对象进行取地址
说明
从图2.10中可以发现,变量ivar的地址与rvar的地址相同,对引用对象进行取地址运算,其实就是对目标对象进行取地址运算。
2.3.10 自定义类型
在C++语言中,用户可以使用typedef关键字自定义数据类型。自定义数据类型并不是真的创建新的数据类型,而是为已存在的数据类型定义一个新的名称。自定义类型的语法格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25971.jpg?sign=1739264932-1qKJ1rnvhgooKgV69ruGpve89aE3W0Ev-0-6aa7c531cee7e0d0d43e72b6de45be7c)
例如,下面的代码定义了一个UINT数据类型。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25976.jpg?sign=1739264932-cvKX4AbnQ6woFesfGXJtQzqL3Cy5hML6-0-21bcef1f47909fe224cce1e71ba90dee)
当定义完新的数据类型后,就可以像定义普通数据类型变量一样定义新数据类型的变量。例如,下面的代码定义了一个UINT类型的变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25981.jpg?sign=1739264932-n8up0EPXxaVnMigHb6AaOeFuaZtJeIMX-0-b7826ea50b247aeebaff0e560a971386)
在程序中使用自定义类型的好处是能够提高程序的移植性。同一种数据类型,在不同机器或不同操作系统上,其长度或性质可能是不同的。如果程序中统一使用了自定义类型,在修改程序时,只需要修改自定义类型的基类型即可,代码的其他地方不需要改动。