2.3C++的数据类型 3.1C++的数据类型及类型修饰符 数据是C++程序的重要组成部分,是程序操作的对象,它们具有一定的数据名称、数据 类型、存储类型、作用域和生存期等属性 数据名称是程序员为某一数据所指定的标识符。数据类型确定了数据占用内存区域的大 小和数据存放形式。存储类型则规定了数据在内存中的位置和生存期。作用域确定了数据可 以使用的范围。生存期则说明了数据占用的内存时间 2.3.1.1数据分类 可以按照不同的属性将数据进行分类 按构造方式进行分类—一最常用的数据分类方法(默认值) 构造方式确定了数据在内存中的存储方式和对数据可实施的操作。在C++中,数据按其 构造方式可分为基本数据类型和派生/聚合数据类型两大类,如图2.2所示 字符型 算木类型 基本类型 b01类型(布尔型) 匚艘精 数据类刑 指钅 函数 派生/聚合类型—枚举类型(emm) 构体 基同体 用户类型 图2.2C++数据类型 (1)、基本数据类型及其类型修饰符 基本数据类型是C+语言预定义的数据类型。对于多数微机,表2.1给出了基本数据 类型的字长和表示范围 表2.1基本数据类型的字长和表示范围 bool 0和1 char 字符型 0~255 16 -32768-32767 float 3.4e-38~3.4c+38 double 双精度型64 1.7e-308~1.7e+308 wchar t宽字符型 32768~32767 空值型 无值 注表中的字长和表示范围假定机器的字长为16位。 空值型数据主要用在两种情况:①确定函数无返回值:②设置类属指针。 除了空值型数据以外,基本数据类型的前面还可以加各种类型修饰符。类型修饰符可以 改变基本数据类型的含义,以更精确地适应各种实际应用的需求。C++中的类型修饰符共有 四种,如下所示 //有符号,修饰字符型和整型
2.3 C++的数据类型 2.3.1 C++的数据类型及类型修饰符 数据是 C++程序的重要组成部分,是程序操作的对象,它们具有一定的数据名称、数据 类型、存储类型、作用域和生存期等属性。 数据名称是程序员为某一数据所指定的标识符。数据类型确定了数据占用内存区域的大 小和数据存放形式。存储类型则规定了数据在内存中的位置和生存期。作用域确定了数据可 以使用的范围。生存期则说明了数据占用的内存时间。 2.3.1.1 数据分类 可以按照不同的属性将数据进行分类。 1、按构造方式进行分类——最常用的数据分类方法(默认值) 构造方式确定了数据在内存中的存储方式和对数据可实施的操作。在 C++中,数据按其 构造方式可分为基本数据类型和派生/聚合数据类型两大类,如图 2.2 所示。 图 2.2 C++数据类型 (1)、基本数据类型及其类型修饰符 基本数据类型是 C++语言预定义的数据类型。对于多数微机,表2.1给出了基本数据 类型的字长和表示范围。 表2.1 基本数据类型的字长和表示范围 类型 名称 字长(bit) 表示范围 bool 布尔型 1 0 和 1 char 字符型 8 0~255 int 整型 16 -32768~32767 float 浮点型 32 3.4e-38~3.4 e+38 double 双精度型 64 1.7e-308~1.7e+308 wchar_t 宽字符型 16 -32768~32767 void 空值型 0 无值 注 表中的字长和表示范围假定机器的字长为 16 位。 空值型数据主要用在两种情况:①确定函数无返回值;②设置类属指针。 除了空值型数据以外,基本数据类型的前面还可以加各种类型修饰符。类型修饰符可以 改变基本数据类型的含义,以更精确地适应各种实际应用的需求。C++中的类型修饰符共有 四种,如下所示: signed //有符号,修饰字符型和整型
unsigned//无符号,修饰字符型和整型 /长型,修饰整型和双精度浮点型 short //短型,修饰整型 P40表2.2给出了C++允许的所有基本数据类型和类型修饰符的组合及其字长和表示范围。 值得注意的是,当这四种修饰符用来修饰整型数据类型(int)时,关键字int可以省略, 只需给出类型修饰符,如 unsigned var unsigned int var signed var: signed int var short var ==== short int var 等等 另外不带任何类型修饰符的int被认为是有符号的(即 signed int)。而对于字符型数 据类型(char)的情况,不同的编译系统有不同的规定。 (2)派生/聚合数据类型 除了基本数据类型之外,C++还提供了指针、枚举、数组、函数、结构体、共用体、类 等几种派生/聚合数据类型。这些复杂的数据类型将在后续章节中进行详细讨论 2、按作用域进行分类 数据的作用域指的是该数据可被访问的程序区域 可以按两种方式决定数据的作用域 (1)对该数据进行说明的语句在程序中所处的位置 (2)在数据定义语句前面所施加的作用域算符。 按作用域的大小不同,数据又可以分为全局数据和局部数据 全局数据是在所有函数体和类之外定义(即程序的全局说明部分)进行说明的数据。全 局数据自说明后在程序的运行过程中始终存在,并可以被主函数及各子函数访问。全局数据 是伴随该程序的退出而消亡的 注意:各函数内的局部数据的标识符不能与全局数据的标识符相同 局部数据是在某一个函数(主函数或子函数)内进行说明的数据。局部数据的作用域仅 限于说明该数据的函数内,即任何函数(包括主函数)都不能访问在其他函数中被说明的局 部数据。局部函数在说明他的函数被调用时产生,并在该函数调用完毕返回时消亡 注意:不同函数的局部数据的标识符可以相同,编译器将把它们当作不同数据处理 3、按存储类型进行分类 在一个程序运行时,其代码和数据是在内存中进行存储的。一个C+程序在内存中所占 用的空间可分为三个区域:程序区、静态存储区和动态存储区。程序区用来存放函数的代码 而静态存储区和动态存储区都可以用来存放数据。数据在不同区域中进行存储、体现了其不 同的生存期,即数据占有的内存期限 静态存储区用来存放静态存储的数据,这些数据在程序开始运行时便获得所分配的内存 单元,并在程序的运行过程中一直占用着为其内存单元。直到程序执行完毕,被静态数据所
unsigned //无符号,修饰字符型和整型 long //长型,修饰整型和双精度浮点型 short //短型,修饰整型 P40 表 2.2 给出了 C++允许的所有基本数据类型和类型修饰符的组合及其字长和表示范围。 值得注意的是,当这四种修饰符用来修饰整型数据类型(int)时,关键字 int 可以省略, 只需给出类型修饰符,如: unsigned var; ==== unsigned int var; signed var; ==== signed int var; short var; ==== short int var; 等等。 另外不带任何类型修饰符的 int 被认为是有符号的(即 signed int)。而对于字符型数 据类型(char)的情况,不同的编译系统有不同的规定。 (2)派生/聚合数据类型 除了基本数据类型之外,C++还提供了指针、枚举、数组、函数、结构体、共用体、类 等几种派生/聚合数据类型。这些复杂的数据类型将在后续章节中进行详细讨论。 2、按作用域进行分类 数据的作用域指的是该数据可被访问的程序区域。 可以按两种方式决定数据的作用域: (1)对该数据进行说明的语句在程序中所处的位置; (2)在数据定义语句前面所施加的作用域算符。 按作用域的大小不同,数据又可以分为全局数据和局部数据。 全局数据是在所有函数体和类之外定义(即程序的全局说明部分)进行说明的数据。全 局数据自说明后在程序的运行过程中始终存在,并可以被主函数及各子函数访问。全局数据 是伴随该程序的退出而消亡的。 注意:各函数内的局部数据的标识符不能与全局数据的标识符相同。 局部数据是在某一个函数(主函数或子函数)内进行说明的数据。局部数据的作用域仅 限于说明该数据的函数内,即任何函数(包括主函数)都不能访问在其他函数中被说明的局 部数据。局部函数在说明他的函数被调用时产生,并在该函数调用完毕返回时消亡。 注意:不同函数的局部数据的标识符可以相同,编译器将把它们当作不同数据处理。 3、按存储类型进行分类 在一个程序运行时,其代码和数据是在内存中进行存储的。一个 C++程序在内存中所占 用的空间可分为三个区域:程序区、静态存储区和动态存储区。程序区用来存放函数的代码, 而静态存储区和动态存储区都可以用来存放数据。数据在不同区域中进行存储、体现了其不 同的生存期,即数据占有的内存期限。 静态存储区用来存放静态存储的数据,这些数据在程序开始运行时便获得所分配的内存 单元,并在程序的运行过程中一直占用着为其内存单元。直到程序执行完毕,被静态数据所
占用的内存单元才被释放。静态数据在程序运行的整个运行过程中只进行一次初始化,每次 访问某一静态数据时,该数据保持上次被访问修改后的值 动态存储区用来存放动态存储的数据,这些数据在其作用域的代码开始执行时才被分给 所需的内存单元,在其作用域的代码运行结束时,这些内存单元将被释放,进行重新分配。 动态数据在每次其作用域被调用而为动态数据分配内存单元,该数据获得的内存单元内存在 的数据内容是不可预测的。因此动态数据需要在其作用域每次重新被调用时进行初始化,否 则将发生错误。 过多地使用静态存储数据会引起程序运行所占用的内存的急剧增加,影响程序的运行效 率。因此在静态数据和动态数据的使用上应根据实际要求决定,不可滥用。 在C++语言中,根据存储类型的不同,数据可分为四种 (1)自动存储类型数据:用关键字auto进行说明,为此类数据分配存储空间及回收它 们所占用的存储空间的工作都是由系统自动处理的,属于动态存储数据类型。C++编译器将 所有局部数据默认为自动存储类型,所以auto在实际编程中很少使用。 (2)静态存储类型数据:用关键字 static进行说明,由于该类数据是按静态存储方式 进行保存的,因而数据在其作用域之外仍能保留其值,以便下次进入其作用域时能继续使用 该值 (3)寄存器存储类型数据:用关键字 regist进行说明,该类型数据彩动态存储方式进 行保存,但与auto类型不同的是,编译器会尽可能地将所说明的该类数据存储在CP的寄 存器中。其目的是为了提高访问效率。若在程序运行的某一时期CPU暂时没有空闲的寄存器, 则编译系统的优化功能会当作自动存储类型数据处理:反之也可以。因此很少用到寄存器存 储类型数据 值得注意的是全局数据及静态数据不能说明为寄存器存储类型,否则两者的说明发生矛 (4)外部存储类型数据:用关键字 extern进行说明,该类型数据主要用在由多个源文 件组成的程序中,向编译器说明该数据在其它文件中已经定义过了。不带 extern说明的全 局数据属于定义性说明。在一程序的多个源文件中,对同一个数据只能在一个文件中进行一 个定义性说明,此时编译将为该文件中说明的数据分配内存。 注意:①变量的初始化也属于定义性说明,不能在其他文件中再对其进行初始化。 ②若程序中的所有源文件对某一全局数据所作的全是外部说明,也没有初始化 则编译器将从中任意选取其中一个外部数据的说明作为其定义性说明。 例2.6自动存储类型数据和静态存储类型数据比较示例 //EX2 6. CPP /自动存储类型数据和静态存储类型数据比较示例 #includeiostream. h> void display( int var);/子函数的引用说明 void main(/程序的主函数 Int 1,J; display (i)
占用的内存单元才被释放。静态数据在程序运行的整个运行过程中只进行一次初始化,每次 访问某一静态数据时,该数据保持上次被访问修改后的值。 动态存储区用来存放动态存储的数据,这些数据在其作用域的代码开始执行时才被分给 所需的内存单元,在其作用域的代码运行结束时,这些内存单元将被释放,进行重新分配。 动态数据在每次其作用域被调用而为动态数据分配内存单元,该数据获得的内存单元内存在 的数据内容是不可预测的。因此动态数据需要在其作用域每次重新被调用时进行初始化,否 则将发生错误。 过多地使用静态存储数据会引起程序运行所占用的内存的急剧增加,影响程序的运行效 率。因此在静态数据和动态数据的使用上应根据实际要求决定,不可滥用。 在 C++语言中,根据存储类型的不同,数据可分为四种: (1)自动存储类型数据:用关键字 auto 进行说明,为此类数据分配存储空间及回收它 们所占用的存储空间的工作都是由系统自动处理的,属于动态存储数据类型。C++ 编译器将 所有局部数据默认为自动存储类型,所以 auto 在实际编程中很少使用。 (2)静态存储类型数据:用关键字 static 进行说明,由于该类数据是按静态存储方式 进行保存的,因而数据在其作用域之外仍能保留其值,以便下次进入其作用域时能继续使用 该值。 (3)寄存器存储类型数据:用关键字 regist 进行说明,该类型数据彩动态存储方式进 行保存,但与 auto 类型不同的是,编译器会尽可能地将所说明的该类数据存储在 CPU 的寄 存器中。其目的是为了提高访问效率。若在程序运行的某一时期 CPU 暂时没有空闲的寄存器, 则编译系统的优化功能会当作自动存储类型数据处理;反之也可以。因此很少用到寄存器存 储类型数据。 值得注意的是全局数据及静态数据不能说明为寄存器存储类型,否则两者的说明发生矛 盾。 (4)外部存储类型数据:用关键字 extern 进行说明,该类型数据主要用在由多个源文 件组成的程序中,向编译器说明该数据在其它文件中已经定义过了。不带 extern 说明的全 局数据属于定义性说明。在一程序的多个源文件中,对同一个数据只能在一个文件中进行一 个定义性说明,此时编译将为该文件中说明的数据分配内存。 注意:①变量的初始化也属于定义性说明,不能在其他文件中再对其进行初始化。 ②若程序中的所有源文件对某一全局数据所作的全是外部说明,也没有初始化, 则编译器将从中任意选取其中一个外部数据的说明作为其定义性说明。 例 2.6 自动存储类型数据和静态存储类型数据比较示例 //EX2_6.CPP //自动存储类型数据和静态存储类型数据比较示例 #include<iostream.h> void display(int var);//子函数的引用说明 void main()//程序的主函数 { int i,j; i=19; j=91; display(i);
display (j) void display (int var) int auto var=lo //自动存储类型数据,初始化 static int static var=10;/靜静态存储类型数据,初始化 auto vart=var: static vart=va cout<<"由自动存储类型变量求得的和为:"< auto var<Ⅶn cout<<"由静态存储类型变量求得的和为:"<< static var<<"n\n"; 4、按访问特性进行分类 数据的访问特性指的是对数据进行访问时的权限规定。在C++中有两种访问修正符: const和 volatile。在C艹+中,数据的访问特性有只读和读写两种。其对应的数据类型为常 量(用 cons t说明)和变量(用 volatile说明)。 常量是指其值在程序运行的过程中固定不变的数据。又分为: (1)普通常量一一是指直接用值来表示,不需要进行任何说明就可以直接使用 (2)符号常量一一是指用一定标识符来表示,且在程序运行过程中,只在程序开 始运行阶段赋一次初值勤,其后便是不可改写的词法符号。在程序运行的过程中,对符号常 量的访问是只读的,因此在说明符号常量的同时,必须对该常量赋值 变量是指在程序运行的过程中,其值可以多次被修改的数据。在程序的运行过程中 变量的访问既可读取数据,又可以对其进行赋值。 注意:若在变量的说明时没有为其赋初值,则对该变量的第一次访问必须是对其赋值, 否则读取的数据是不可预测的。 2.3.1.2数据说明 使用数据的一个基本原则是数据必须先说明,后使用。在对数据进行说明时,编译器为 其分配相应的内存单元。在对该数据进行访问之前,必须对数据进行初始化 在进行数据说明时应指定该数据的存储类型、数据类型及其标标识符。数据说明的形式 如下所示 存储类型>数据类型标识符 在C艹中分别使用auto、 static、 regist、 extern进行说明,存储类型向编译器指定 了该数据的存储位置 数据类型确定了为该数据所分配的内存单元的大小及数据保存和读取的形式。 标识符即程序员为该数据指定的名称。在某一数据的作用域内,标识符与数据一一对应, 可以通过标识符访问指定的数据。 数据的存储类型可以缺省。缺省时,编译器会根据数据的类型和作用域为其指定相应的 存储类型。如函数的缺省存储类型为 extern,全局数据的缺省存储类型为 static,而局部数 据的存储类型为auto 数据的作用域则由数据说明语句在程序中所处的位置决定。在进行数据说明时,可同时
display(j); } void display(int var) { int auto_var=10; //自动存储类型数据,初始化 static int static_var=10; //静态存储类型数据,初始化 auto_var+=var; static_var+=var; cout<<"由自动存储类型变量求得的和为:"<<auto_var<<'\n'; cout<<"由静态存储类型变量求得的和为:"<<static_var<<"\n\n"; } 4、按访问特性进行分类 数据的访问特性指的是对数据进行访问时的权限规定。在 C++中有两种访问修正符: const 和 volatile。在 C++中,数据的访问特性有只读和读写两种。其对应的数据类型为常 量(用 const 说明)和变量(用 volatile 说明)。 常量是指其值在程序运行的过程中固定不变的数据。又分为: (1) 普通常量——是指直接用值来表示,不需要进行任何说明就可以直接使用。 (2) 符号常量——是指用一定标识符来表示,且在程序运行过程中,只在程序开 始运行阶段赋一次初值勤,其后便是不可改写的词法符号。在程序运行的过程中,对符号常 量的访问是只读的,因此在说明符号常量的同时,必须对该常量赋值。 变量是指在程序运行的过程中,其值可以多次被修改的数据。在程序的运行过程中,对 变量的访问既可读取数据,又可以对其进行赋值。 注意:若在变量的说明时没有为其赋初值,则对该变量的第一次访问必须是对其赋值, 否则读取的数据是不可预测的。 2.3.1.2 数据说明 使用数据的一个基本原则是数据必须先说明,后使用。在对数据进行说明时,编译器为 其分配相应的内存单元。在对该数据进行访问之前,必须对数据进行初始化。 在进行数据说明时应指定该数据的存储类型、数据类型及其标标识符。数据说明的形式 如下所示: <存储类型>数据类型 标识符; 在 C++中分别使用 auto、static、regist、extern 进行说明,存储类型向编译器指定 了该数据的存储位置。 数据类型确定了为该数据所分配的内存单元的大小及数据保存和读取的形式。 标识符即程序员为该数据指定的名称。在某一数据的作用域内,标识符与数据一一对应, 可以通过标识符访问指定的数据。 数据的存储类型可以缺省。缺省时,编译器会根据数据的类型和作用域为其指定相应的 存储类型。如函数的缺省存储类型为 extern,全局数据的缺省存储类型为 static,而局部数 据的存储类型为 auto。 数据的作用域则由数据说明语句在程序中所处的位置决定。在进行数据说明时,可同时
对数据进行初始化,也可放在后面进行(P45例) 3.2常量 常量是指用来表示固定的数据或字符值的词法符号。对于符号常量,在对其进行说明的 同时赋予初值,且其值在程序的运行过程中不允许进行修改。在C++中,有以下几种不同 类型的常量:整型常量、浮点数常量、字符串常量和枚举型常量 1、整型常量 整型常量可以用八进制、十进制、十六进制来表 八进制整型常量由07这8个数字组成,且其右端第一个数字必须为0。 十进制整型常量由0~9这10个数字组成,且第一个数字不能为0。 十进六制整型常量必须以0x(或0X)开头。其中的字母可以大写也可以小写。 这三种进制的整型常量前面都可以加正负号(+/-)来表示其数值的正负,正号可以不 同时,可以在整型常量的末尾添加一定的标识符将某一常量标识符为特定类型的常量。 整型常量末尾的字符L或1将该常量标识为long型的数值(建议用L表示);整型常量末尾 同时加上字符U或u将该常量标识为 unsigned型的数值:也可以将以上两种方式进行组合 如:3645L,0x89Lu,0256UL 此外为了使得程序中各常量的含义更加明确,增加程序的可读性,可采用符号常量。符 号常量可采用预处理宏替换指令# define或 const类型修饰符进行说明(一一对应),以便 在程序中通过某标识符来访问常量 利用预处理宏替换指令对符号常量进行说明的形式如下: # define符号常量标识符常量值(例如:# define count20) 在C艹中,提供了类型修饰符 cons t对符号常量进行标识,其形式如下: const数据类型符号常量标识符=常量值 例如: const int bufsize=1024; 注意:(1)、必须对符号常量赋初值——常量值,之后不能修改。否则会出现错误 (2)、不能把一个符号常量的地址赋给一个普通指针,否则会出现编译错误。因 为常量的值有可能会通过指针间接地进行修改。(详见后续章节) 例如: const int count=120; int*pt=& count;//错误,将符号常量的地址赋给普通指针 当然,符号常量的地址也可以用特殊的指针来保存,即定义一个指向常量的指针,例如: const int *pt 此处,pt是一个指向整型常量的指针,为该指针所分配的内存单元内保存着一个整型 数据的内存地址,通过该地址可以对该整型数据进行访问。在程序中,pt可以指向任何 个整型数据(包括常量和变量),但是pt所指向的数据不可以通过pt来改变其数值。一个 常量的地址只能赋给一个常指针,但是一个常量既可以保存常量的地址,也可以保存变量的 地址。指向常量的指针通常用于定义函数的正规参数。(?) 2、浮点型常量 浮点型常量可以用十进制表示法或科学计数法表示。在采用十进制表示时,该常量都应 该带有小数点。在采用科学计数法进行表示时,其形式如下:
对数据进行初始化,也可放在后面进行(P45 例)。 2.3.2 常量 常量是指用来表示固定的数据或字符值的词法符号。对于符号常量,在对其进行说明的 同时赋予初值,且其值在程序的运行过程中不允许进行修改。在 C++ 中,有以下几种不同 类型的常量:整型常量、浮点数常量、字符串常量和枚举型常量。 1、整型常量 整型常量可以用八进制、十进制、十六进制来表示。 八进制整型常量由 0~7 这 8 个数字组成,且其右端第一个数字必须为 0。 十进制整型常量由 0~9 这 10 个数字组成,且第一个数字不能为 0。 十进六制整型常量必须以 0x(或 0X)开头。其中的字母可以大写也可以小写。 这三种进制的整型常量前面都可以加正负号(+/- )来表示其数值的正负,正号可以不 写。 同时,可以在整型常量的末尾添加一定的标识符将某一常量标识符为特定类型的常量。 整型常量末尾的字符 L 或 l 将该常量标识为 long 型的数值(建议用 L 表示);整型常量末尾 同时加上字符 U 或 u 将该常量标识为 unsigned 型的数值;也可以将以上两种方式进行组合。 如:3645L,0x89Lu,0256UL 此外为了使得程序中各常量的含义更加明确,增加程序的可读性,可采用符号常量。符 号常量可采用预处理宏替换指令#define 或 const 类型修饰符进行说明(一一对应),以便 在程序中通过某标识符来访问常量。 利用预处理宏替换指令对符号常量进行说明的形式如下: #define 符号常量标识符 常量值 (例如:#define count 20) 在 C++中,提供了类型修饰符 const 对符号常量进行标识,其形式如下: const 数据类型 符号常量标识符=常量值; 例如:const int bufsize=1024; 注意:(1)、必须对符号常量赋初值——常量值,之后不能修改。否则会出现错误 (2)、不能把一个符号常量的地址赋给一个普通指针,否则会出现编译错误。因 为常量的值有可能会通过指针间接地进行修改。(详见后续章节) 例如:const int count=120; int *pt=&count;//错误,将符号常量的地址赋给普通指针。 当然,符号常量的地址也可以用特殊的指针来保存,即定义一个指向常量的指针,例如: const int *pt; 此处,pt 是一个指向整型常量的指针,为该指针所分配的内存单元内保存着一个整型 数据的内存地址,通过该地址可以对该整型数据进行访问。在程序中,pt 可以指向任何一 个整型数据(包括常量和变量),但是 pt 所指向的数据不可以通过 pt 来改变其数值。一个 常量的地址只能赋给一个常指针,但是一个常量既可以保存常量的地址,也可以保存变量的 地址。指向常量的指针通常用于定义函数的正规参数。(?) 2、浮点型常量 浮点型常量可以用十进制表示法或科学计数法表示。在采用十进制表示时,该常量都应 该带有小数点。在采用科学计数法进行表示时,其形式如下: