![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=1739366369-voxch6375Xvgm0I4tb7RLrRhCpJEACZ2-0-69f960325860846d2a7202445e2d788c)
说明
表格中的[]为可选部分。例如,[signed] long [int]可以简写为long。
实型主要包括单精度型、双精度型和长双精度型,如表2.3所示。
表2.3 实型类型
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-T58_90698.jpg?sign=1739366369-1NAUKTIeCTrHDuScy6UVeQAkP7rTaSKm-0-31623c515559c2cde87f0f57e65ccbe2)
在程序中使用实型数据时需要注意以下几点。
(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=1739366369-DPcDNPTvz3Z6xccbXGs9sW8odWftbtIl-0-fd41099926d6396b6ad537c04b70204e)
上述代码并不是高质量的代码,如果程序要求的精度非常高,可能会产生未知的结果。通常在比较实数时需要定义实数的精度。例如:
【例2.2】 利用实数精度进行实数比较。(实例位置:资源包\TM\sl\2\2)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P58_24559.jpg?sign=1739366369-vkTzDJv0d69zgGFAtGJJTNkNQRYHZEfE-0-b722dd0d3ce8664b3fe6f80d36f567dc)
2.3.2 字符类型
在C++语言中,字符数据使用“' '”来表示,如'A''B''C'等。定义字符变量可以使用char关键字。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P58_24604.jpg?sign=1739366369-i8hJBOFOwrW34bzubGIuebhZxPpoIect-0-ddd902d0cb21947daefed2069aa3703b)
在计算机中字符是以ASCII码的形式存储的,因此可以直接将整数赋值给字符变量。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P58_24614.jpg?sign=1739366369-pnjjfzelPDLitn68B3wQxJwSVIsayjex-0-8ff6d9ebd2b9b75a0bec4e61d3b12cc8)
输出结果为“a”,因为97对应的ASCII码为“a”。
2.3.3 数组类型
数组是指具有相同数据类型的一组元素的集合,数组中的元素是按顺序存储在内存中的。数组按维数划分,可以分为一维数组、二维数组和多维数组。
1. 一维数组
在C++语言中,一维数组的定义格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24707.jpg?sign=1739366369-iupw1Yx8H7anQ0uawHcGC746nFkYwQHS-0-5796258228606b567f1bfa4e374044bb)
例如,下面的代码定义了一个具有10个元素的整型数组。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24712.jpg?sign=1739366369-BcljdHVmP4kMLNP91ba7Vtr8kPxasLvm-0-b0e9619d14d9c94f479f17896f8924d7)
在定义数组后,还需要访问数组中的元素。数组元素是通过数组名和下标来访问的,例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24717.jpg?sign=1739366369-KLU9dZyXXrwLqx5g7XHHSjozXZ5Dl2f9-0-11e0f000e8ad8e5c340e097bcbe4463d)
上面的代码将数组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=1739366369-Da3Eg19TF2mig423WQkAja26Z4qnioUL-0-ee948e687c80e5efb51bdf3d5b9f8e3b)
也可以只对部分元素赋初值。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24727.jpg?sign=1739366369-ZITOfrnQTrUzXlFLLXWOHJFZzY0MbBcL-0-8e21487bdbb75525483802c9c269fe90)
上面的代码只对array数组的前5个元素设置了初值。注意,不能给数组提供超过数组长度的初始值,例如下面的代码是不能通过编译的,将提示太多的初始值。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24732.jpg?sign=1739366369-tfHSTsaDULElUl3dsvvkDqe0UUiTQEux-0-dd6e9434f7a1a640bae478ade894b87a)
如果将数组元素全部初始化为0,用户可以简写为:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24737.jpg?sign=1739366369-rWlCrw3bFopBUzNAugvFo4ISMDp82clL-0-67f64cbf90fa3bd2b22e52ef8a566288)
但是上述方式不能够将全部数组元素初始化为其他的值,例如将全部数组元素初始化为1。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P59_24742.jpg?sign=1739366369-NH5umxGBUWOt3sPrZiO9i9TAFoT1nbbm-0-349553629c0381fdbc285cbea9f6b2f9)
上面的代码将导致第1个数组元素的值为1,其他数组元素的值为0。
如果需要对数组全部元素进行初始化,可以省略数组长度,但是数组下标符号“[]”不能省略。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24779.jpg?sign=1739366369-0Wisxz3StVeF2YTu3rpIbyHR4QfdWW8E-0-c399f2decdde67bc5214e009e4453d07)
2. 二维数组
在C++语言中,二维数组的定义格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24784.jpg?sign=1739366369-0wqcUbheEJFiE5yzopI8Xf5gBln5QaCL-0-118608e2c0e52477d3919202a7bfcbe4)
例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24789.jpg?sign=1739366369-9F67fFKpEhYZgqOlOKR2HO5C1CNPgydX-0-ffb694c1318f2891efde377a5f346702)
二维数组元素也是通过数组名和下标来访问的。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24794.jpg?sign=1739366369-QQ7Tvay01zZUcRFt73r2q32Kkdo9hb6I-0-c4c2d6dde6851eb113ba25a3457decbf)
可以认为二维数组是一个特殊的一维数组,只是数组中的每一个元素又是一个一维数组。例如,array[3][4]可以认为是一个一维数组array[3],其中的每一个元素又是一个包含4个元素的一维数组。
在定义二维数组时也可以直接进行初始化。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24799.jpg?sign=1739366369-jCPWiTOtNFFGAphuEK9Hk3PzUdKG71Nh-0-527e34a49e11a97a8ef2f27968feb474)
用户也可以在一个大括号内直接初始化所有的元素。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24804.jpg?sign=1739366369-6zQsF9QTEJhwVTa4u5pBr28GVl00X1VB-0-5a29ac7d762284e14bd624c09617f5e2)
但是并不提倡该方法,因为如果数组元素过多,将很难界定每一个元素。
与一维数组类似,二维数组也可以只对部分元素进行初始化。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24809.jpg?sign=1739366369-SfinG4WoaquBSqicdf4xUrD1xSBzK8tS-0-868fd05c15d3aba014b04538b641124f)
结果是对每一行第1个元素赋值,其他元素为0。
对于二维数组,还可以只对某一个元素或某一行赋值。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24814.jpg?sign=1739366369-4e9aEHyPaUDXSpC2dwSEke368oh7EOJ0-0-b1763e5b897b037030462969c23f654b)
在定义二维数组时,如果需要提供全部元素的初始值,可以省略第一维的长度,但是不能省略第二维的长度。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P60_24824.jpg?sign=1739366369-bNDVw536e9dK8heG09cjzCzBlRE2L4h4-0-4534a16638788cda714975dc29b3224e)
注意
最后一行代码,只提供了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=1739366369-qEbZptv98ReJsNqn88ZyxXFstq7HBG8O-0-6919a0713b8b1df49b9acf28f3e42486)
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=1739366369-RF8snEkuxK5OIHzoZ5Y2OBR6189G6Fvn-0-0fcbe96bbe01a4b22da38ae972b9ad26)
使用enum关键字定义一个枚举类型,例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P61_24888.jpg?sign=1739366369-q4rOYZbCFWUwe7Bze54mHOjL0FoF6TU8-0-0f9363061263694e52b99c8c12fd426e)
在定义枚举类型时,可以为各个常量提供一个整数值,如果没有提供整数值,默认第1个常量值为0,第2个常量值为1,以此类推。例如上面的代码中,CLOSE常量的值为0,OPEN的值为1……
下面为枚举类型设置常量值。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P61_24893.jpg?sign=1739366369-mWGbVuEew04RHcbhdKp98P2kC9tyIvAz-0-db2ce65c92330255d597b4ae5ada083e)
在上面的代码中,将枚举常量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=1739366369-wV59T6bzSelQWMwT4fDYkb8pg180FFYG-0-0d2ee21bf46c7c65c97aa94a7e25d73a)
2.3.6 结构体类型
结构体是一组变量的集合。与数组不同,结构体中的变量可以有各种类型。通常将一组密切相关的信息组合为一个结构体,以描述一个对象。例如,描述学生信息,包括姓名、性别、年龄、地址等信息,可以定义一个结构体来描述学生的所有信息。
【例2.4】 定义结构体类型。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P62_25091.jpg?sign=1739366369-KT8kOWu7pUUmb8WsdFAKTQX5rWSpxEDD-0-0456898db3c89f0e9417b389d10bf437)
其中,关键字struct用于声明一个结构体类型。结构体中的变量被称为成员,如name、sex等。
注意
在声明结构体时,不要忘记末尾的分号。
在声明一个结构体后,可以定义一个结构变量。在C语言中定义结构变量的语法格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25146.jpg?sign=1739366369-BXpie3ewYz47bIq21XvCZLBDgz0m8HWn-0-077108af4aebecab5bd367cac143f239)
例如,下面的代码采用C语言的形式定义结构体变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25151.jpg?sign=1739366369-KXdRDZTDnyhFMtP8QQHvyuIx1RPUS2qZ-0-e82635bb44a722fab1716607c2a936cd)
在C++语言中定义结构体变量的格式与定义普通变量的格式相同。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25156.jpg?sign=1739366369-07tILzgZdZLDlmw47tgmg9ElTTStRCK3-0-295e21b0b7580b1ff5215735f47664f1)
当定义一个结构体变量时,编译器将为变量分配足够的空间以容纳结构体中所有的成员。在声明结构体类型时,也可以直接定义结构体变量。例如:
【例2.5】 定义结构体类型时直接定义结构体变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25161.jpg?sign=1739366369-F2VqYKEvFF0JECFEigvZw3UY2Pxd1QZA-0-c0f9e7411a79e9f51d93483f64776325)
上述代码在声明结构体Student的同时,定义了一个结构体变量stdnt。此外,在定义结构体时,如果只需要定义一次结构体变量(在其他地方不需要定义该类型的结构体变量),可以不写结构体类型的名称,而只给出结构体变量。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25201.jpg?sign=1739366369-yKc6pWDNg6beRsLvxH3xd2AR8NILyzLP-0-d783f3d569bc87c5d5d3661a6d3ad152)
在使用结构体时,需要访问结构体中的各个成员。可以使用“. ”符号来访问结构体中的成员。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P63_25236.jpg?sign=1739366369-TefS2lrAHEC0TrRGfegqjrqCs03GkKDs-0-30890ecebbba38f67ed9c95296e859ac)
两个整型变量可以相互赋值,那么两个结构体变量能否直接赋值呢?答案是可以的。观察如下代码。
【例2.6】 结构体变量之间的赋值。(实例位置:资源包\TM\sl\2\4)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P64_25274.jpg?sign=1739366369-j7RUNg6DPxDOZPZKIy684eGJHXwmlyAw-0-02e73b981b30ad2e10db76389abfbe81)
执行上述代码,结果如图2.2所示。
从图2.2中可以发现,another变量的age成员与stdnt变量的age成员是相同的;不仅如此,这两个变量的其他成员数据也相同。
在定义结构体变量时,编译器会为变量分配足够的空间以容纳结构体的所有成员。如果定义如下的一个结构体变量,编译器将为其分配多大的空间呢?
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P64_25387.jpg?sign=1739366369-33H7pcNyxHa4GtqS1VhmLpHCjUAn1If5-0-b8ae6577703cf2617b3d47cc917bb36f)
图2.2 结构体变量赋值
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P64_25359.jpg?sign=1739366369-BXeDE2SDiCoh3aBPMJjvLoYOGRvokRDl-0-d4b2f3028ba7cd0d9c7011bc34a31181)
分析结构体成员,其中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=1739366369-36vEfcN7P4IvDAyC0h8pLmSTSIKiTFEX-0-379d71055bc22352b49156372727e8c5)
其中,headerlen成员类型为无符号字符型,理应占1个字节(8位),通过使用位域符号“:”和长度4,headerlen成员只占了“半”个字节—4位。在定义位域字段时,也可以不指定成员名称,这样可以预留一些空间。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P65_25429.jpg?sign=1739366369-c34ip4oPr0VvRXmOSTuzpwtONMiig6lx-0-c98f4c575c0388aba93b9f1faf85518f)
用户在访问memTwo成员时,将直接从一个字节的第5位开始读取数据。
2.3.7 共用体类型
共用体类型提供了一种机制,使得多个变量(共用体中的成员)可以共享同一个内存地址。下面的代码定义了一个共用体类型unType。
【例2.7】 定义共用体类型。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P65_25459.jpg?sign=1739366369-KwciL0UlmjgCJVCTvj0iVR4NOOL87KTj-0-4326d88fe8a28e9462633d14c803682d)
定义共用体与定义结构体类似,只是关键字不同,共用体使用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=1739366369-l0YPVKRp2W7X6UZw8I5DpjsrCCsfyttM-0-4147814ac939113fe11a98be881de4f1)
图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=1739366369-7zmOmB7IqaEYsJXlk2TsLdzQkgx8N3np-0-eedaff90ffdbf47bfb2fc0aa9863467d)
图2.4 指针与变量的关系
在C++中,定义指针的语法格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P66_25501.jpg?sign=1739366369-Q6vhlGGXZpVUQU7xbTUFE0uSb04xMFOW-0-17cafab2cc0a1d8871ec6d19d892d09e)
例如,下面的代码定义了一个整型的指针变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P66_25506.jpg?sign=1739366369-hESAH3RgMVWIhUArnxGv3b3FfjzpO3iL-0-df908f116058b2561d4f6f99196f07a9)
只定义一个指针变量是没有意义的,还需要为指针变量赋值。指针变量的值应该是一个有意义的地址(通常是某个变量的地址),而不是数据。如何将变量的地址赋值给指针变量呢?C++中可以使用“&”运算符来获得变量的地址。下面的代码演示了通过“&”运算符获得变量地址,并将其赋值为指针变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P66_25511.jpg?sign=1739366369-7fVZCoqVWxgROzv85L7H6sVop0iQN3AK-0-741afab881359b9bec14d05e4f8ad9a8)
当指针被赋予一个有效的变量地址后,如何通过指针访问或修改变量的数据呢?在指针变量前使用“*”运算符,即可直接访问变量的数据。
【例2.8】 使用“*”运算符访问指针数据。(实例位置:资源包\TM\sl\2\5)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25566.jpg?sign=1739366369-gLyOO1eovVGNMHCSTrBqLTa6safU3xTi-0-877bc9543d3a81c7d35dc1c50d0307b4)
执行代码,结果如图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=1739366369-xdAfuRrvj2HH5Xrc5znsi6s07wykf8nV-0-c53c54b1a03f17ff873f75c9332421fb)
在上面的代码中,&iarray[0]表示获取数组中第1个元素的地址,即数组的首地址。对于数组来说,数组名同样表述数组的首地址,因此下面的代码与上述两行代码是完全相同的。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25616.jpg?sign=1739366369-vam4VwlhgF7sxgRlXCzWrQQXZttsWIyR-0-bcf2991dec68d8841e0468b0537d99ab)
图2.6描述了当前指针变量pvar与数组iarray之间的关系。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25663.jpg?sign=1739366369-DJeteYreSRSyrqvcNgazIc0rdMpCZgGP-0-d53d0cc2a00b8adeca13514fcd240b83)
图2.5 使用指针变量修改数据
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25664.jpg?sign=1739366369-keKmoW8fe3G2h6q1Kc9vIUSdc1QXUZ0Q-0-00afc7f1e13168ddcedd49b8c68e58a6)
图2.6 指针变量pvar与数组iarray之间的关系
当一个指针变量指向一个数组后,通过指针变量即可访问该数组中的每一个元素。例如,下面的代码利用指针输出数组中的每一个元素。
【例2.9】 使用指针变量输出数组元素。(实例位置:资源包\TM\sl\2\6)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P67_25626.jpg?sign=1739366369-Ipv3K4w956mOxOtEtbELzm3toD42hsk4-0-d3830e44422846e089ac9e180560bf77)
执行上述代码,结果如图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=1739366369-VxJ3BK2uHlB3EtcMkSmwYIWUm8X0KjZt-0-74648b3915d6c38e035e3ff7cea5dea0)
对于指针数组来说,数组中的每一个变量均是一个指针变量。下面的代码演示了指针数组的应用。
【例2.10】 利用指针数组存储数据。(实例位置:资源包\TM\sl\2\7)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90821.jpg?sign=1739366369-eLUOfNSQfwhYPwopV0DoejNevC3dnLkf-0-112d4d87ea7b6c70e422b845bfa158a8)
执行上述代码,结果如图2.8所示。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90899.jpg?sign=1739366369-7UxNY3TXEWxkOFgmaY72tbSRV3mLcxfD-0-ccb8cbe507e08307b4ebf289d04e0665)
图2.7 利用指针遍历数组
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90900.jpg?sign=1739366369-mS4q3aHUJ2zKvR1VImsK19OM3cOoCdtS-0-3d04a2e1481a1d8936b8eff1b872bb3e)
图2.8 指针数组应用
在定义指针时,也可以使用const关键字。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90871.jpg?sign=1739366369-zyMWqdS7Ck0mIvUYUrLJXvesHd0VVrGb-0-3722aee3799375b537c0ef853768ebc6)
对于指针pvar来说,用户不能够修改pvar指向的值,但是可以修改pvar指向的地址。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P68_90881.jpg?sign=1739366369-jv5kZ4z8VwNlvoVrCNbPH9LKvMAG4Qb9-0-a35b843738eb88245d2c282642b7e5bc)
在使用const关键字定义指针时,也可以将const关键字放置在指针变量的前面,但是指针变量的性质发生了改变。观察如下代码:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25807.jpg?sign=1739366369-zLXGe777YsgPFltdksOmRYq12644OOpm-0-5ce0936441a51be0a1cf2b0eb580b775)
上面的代码定义了一个常量指针pvar,使用户不能够修改pvar指向的地址,但是可以修改pvar指向的数据。
在定义指针时也可以同时使用两个const关键字。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25832.jpg?sign=1739366369-IIlWxv2Wth8YgEOwYdcUxTy2zjsnN40O-0-eea5a02abfbaba35f62a03a0e1819f28)
在上面的代码中,用户既不能修改pvar指向的地址,也不能修改pvar指向的数据。例如:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25842.jpg?sign=1739366369-9nC3oEGJzUQlrdu1h502rLWlycLnkzyT-0-145f2e0cfcd560998a980a73237a21d9)
2.3.9 引用类型
引用可以认为是一个“别名”,即目标的代名词。当定义一个引用时,需要为其指定一个对象,即目标。此时,引用就成了目标的代名词,操作引用与操作实际的目标对象是相同的。定义引用的格式如下:
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25857.jpg?sign=1739366369-DU5OPwIRI8hsuT3hqe0N3jFaDQQoP3Zd-0-1b3d430402107ca90807843be6594e3a)
下面的代码定义了一个引用对象。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25862.jpg?sign=1739366369-tZLhnwUM9EpD1QRpF62ZXWiUkhjFKT29-0-7d004159b845918a340f5c618105a0ec)
在定义引用对象后,即可使用引用对象操作目标对象。
【例2.11】 使用引用对象代替目标对象。(实例位置:资源包\TM\sl\2\8)
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P69_25872.jpg?sign=1739366369-JjGOZCNUTX6gA0bdCMpitQ5kkitXK2Lq-0-19e345037d4ace8d3bc31b5218e995de)
执行上述代码,结果如图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=1739366369-9ujdIyfS74kgzgUPzFDGjCdK7H4ty1ee-0-b71f359b3290f9c151f5a63a05d35a3c)
执行上述代码,结果如图2.10所示。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25984.jpg?sign=1739366369-tlplWVXRjH93SyOyPTbyaYtZk4qxl6Jj-0-42a68a61aace9e36c307d4c68012f7bf)
图2.9 使用引用操作对象
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25985.jpg?sign=1739366369-zqLlYiad9FUjj9ctBexwWKfM2BTxj3e3-0-cc5a3bfd40fa79b77abfd837002fbce9)
图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=1739366369-HqGWIeKYlJwaRuNMUBxbtJGkVdr1o3uM-0-cde0d37fa193328aad01133fbb5299d2)
例如,下面的代码定义了一个UINT数据类型。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25976.jpg?sign=1739366369-8vPWEhaAmMGQZilmmZjw2L6M1yDxmgyw-0-d2b04f874edb8f1040a9b75c263c98d2)
当定义完新的数据类型后,就可以像定义普通数据类型变量一样定义新数据类型的变量。例如,下面的代码定义了一个UINT类型的变量。
![](https://epubservercos.yuewen.com/771DC2/15825992505222206/epubprivate/OEBPS/Images/Figure-P70_25981.jpg?sign=1739366369-KTz3eUK1HPAcJ3588GdRcdAlcjUgDeBz-0-68334c250888cbd9aef10a442c7a716a)
在程序中使用自定义类型的好处是能够提高程序的移植性。同一种数据类型,在不同机器或不同操作系统上,其长度或性质可能是不同的。如果程序中统一使用了自定义类型,在修改程序时,只需要修改自定义类型的基类型即可,代码的其他地方不需要改动。