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 //无符号,修饰字符型和整型
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类型不同的是,编译器会尽可能地将所说明的该类数据存储在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=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例)。
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、浮点型常量浮点型常量可以用十进制表示法或科学计数法表示。在采用十进制表示时,该常量都应该带有小数点。在采用科学计数法进行表示时,其形式如下:
尾数部分+E(或e)+指数部分一个浮点数常量可以用跟在常数后的字母F或f将其标识为float型。
例如:3,0.5f 5e7 2.0e-5
与整型常量相似,也可以定义符号常量表示浮点型常量。定义方法与在整型常量中所述的方法相同。例如;#define PI 3.14159265
有关符号常量及其指针的一些规则,在对整型常量一节中已进行讨论。这些规则对任何类型的常量都适用,具有一般性,此处不在论述。
3、字符型常量字符型常量是一个用单引号括起来的单一字符。例如:’A’ ‘7’ 。其字符的集合并不限于ASCII码字符集。
注意:单引号本身不是字符常量的内容。
若想使用不可打印输出的字符、单引号、双引号和反斜线等字符时,可以使用转义字符序列进行表示,例如:
换行符 (newline) \n
水平制表符 (horizontal tab) \t
垂直制表符 (vertical tab) \v
退格符 (backspace) \b
回车符 (carriage return) \r
换页符 (formfeed) \f
响铃 (alert bell) \a
反斜线 (backslash) \\
问号 (question mark) \?
单撇号 (single quote) \’
双撇号 (double quote) \”
另外,还可以用一个八进制数来表示一个字符常量,其形式如下:
\nnn
其中,nnn代表一个3位八进制数,其数值表示该字符在内部字符集中的序号。
例如:\0 空字符 (null)
\7 响铃 (alert bell)
\064 符号@ (@)
字符常量也可以用符号常量来表示,其定义方法同整型常量。
4、字符串常量字符串常量是一组连续的字符序列,该字符序列用双引(撇)号括起来,其中的非输出字符可以由它们的转义字符序列表示。
注意:双引(撇)号只起到定界符的作用,它本身并不是字符串常量的一部分,若在字符串中包含双撇号时,必须使用其转义字符表示。
例如:”,,”\n Name,\t\”Tsinghua\”[CHN]\n”
一个字符串可以在连续的几行中书写,在行末加一个续行符(\)表示下一行文本是本行中字符串常量的延续。例如:
,Beijing,China\n\
Tsinghua university\n\
Civil Engineer.\n”
在保存字符串常量时,除了组成字符串常量的字符序列本身外,系统还自动在该字符串的结尾处添加一个空字符null,用于标识一个字符串的终结。因此所占据的内存单元比该字符串的元素所用的内存单元长度多一个字节。
例如,‘A’
41
,A”
41
0
也可以采用指向字符型数据的常量指针来表示字符串常量,方法类似于整型常量。
2.3.3 变量
变量是内存中用一具标识符命名的存储单元,可以用来存储一个特定类型的数据,且数据的值在程序的运行过程中可以进行修改。
在C++中,使用某变量之前必须对该变量进行说明。变量说明通知编译器为变量分配内存空间。变量说明的一般形式如下:
<存储类型> 数据类型 变量1<,变量2,...>;
存储类型即为auto,regist,static,extern中之一,缺省时,编译器将根据对该变量进行说明的语句的位置,即该变量的作用域,为该变量指定相应的存储类型(参照数据分类的有关内容)。
数据类型指的是按构造进行分类的基本数据类型或聚合数据类型中的一种。它决定了该变量可以存储的数据的种类,编译器将根据该类型数据的存储特性为该变量分配相应大小的内存单元,同时规定了在该变量上可施加的操作集。
变量名是程序员为该变量指定的标识符,它的组成应该满足C++标识符命名的所有原则。
在C++中,一个语句的结束以分号“;”进行标识。在对多个变量进行说明时,如果需要,某一说明语句可以跨越多行,且无需任何续行符,说明语句的结束以遇到的第一个分号为标志。例如:
unsigned int count;
double mathScore,phyScore,
geoscore,engScore; //说明了4个双精度型变量
注意:(1)、C++是一种区分大小写的语言。
(2)、在某一变量的作用域,同名变量只能作一次定义性说明;不同作用域内的变量,它们的标识符(变量名)可以相同。
(3)、变量在使用之前一定要赋初值,否则将导致计算结果的错误或有可能死循环或死机。
(4)、C++的变量说明语句可以放在程序的任何位置,只要在该变量的使用之前甚至在使用它的同时说明即可。
下面通过一个例子体会C++变量说明的灵活性。
[例2.7] 乘法表打印程序——体会C++变量说明的灵活性。
//EX2_7.cpp
//乘法表打印程序--体会C++变量说明的灵活性。
#include<iostream.h>
void main()
{
cout<<"基本乘法表:"<<endl;//输出表头信息并换行
cout<<"**";//输出标题行首字符
for (int i=1;i<=9;i++)
{
cout<<" "<<i;//输出标题行各列标题
}
cout<<endl;
for(i=1;i<=9;i++) //共进行9次循环,循环变量从1到9
{
cout<<i<<"x";//输出各行的标题
for (int j=1;j<=i;j++)//共进行i次循环,循环变量从1到i
{
cout<<" "<<i*j;//输出两循环变量相乘结果
}
cout<<endl;//结束一行输出,进行换行。
}
}
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 //无符号,修饰字符型和整型
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类型不同的是,编译器会尽可能地将所说明的该类数据存储在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=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例)。
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、浮点型常量浮点型常量可以用十进制表示法或科学计数法表示。在采用十进制表示时,该常量都应该带有小数点。在采用科学计数法进行表示时,其形式如下:
尾数部分+E(或e)+指数部分一个浮点数常量可以用跟在常数后的字母F或f将其标识为float型。
例如:3,0.5f 5e7 2.0e-5
与整型常量相似,也可以定义符号常量表示浮点型常量。定义方法与在整型常量中所述的方法相同。例如;#define PI 3.14159265
有关符号常量及其指针的一些规则,在对整型常量一节中已进行讨论。这些规则对任何类型的常量都适用,具有一般性,此处不在论述。
3、字符型常量字符型常量是一个用单引号括起来的单一字符。例如:’A’ ‘7’ 。其字符的集合并不限于ASCII码字符集。
注意:单引号本身不是字符常量的内容。
若想使用不可打印输出的字符、单引号、双引号和反斜线等字符时,可以使用转义字符序列进行表示,例如:
换行符 (newline) \n
水平制表符 (horizontal tab) \t
垂直制表符 (vertical tab) \v
退格符 (backspace) \b
回车符 (carriage return) \r
换页符 (formfeed) \f
响铃 (alert bell) \a
反斜线 (backslash) \\
问号 (question mark) \?
单撇号 (single quote) \’
双撇号 (double quote) \”
另外,还可以用一个八进制数来表示一个字符常量,其形式如下:
\nnn
其中,nnn代表一个3位八进制数,其数值表示该字符在内部字符集中的序号。
例如:\0 空字符 (null)
\7 响铃 (alert bell)
\064 符号@ (@)
字符常量也可以用符号常量来表示,其定义方法同整型常量。
4、字符串常量字符串常量是一组连续的字符序列,该字符序列用双引(撇)号括起来,其中的非输出字符可以由它们的转义字符序列表示。
注意:双引(撇)号只起到定界符的作用,它本身并不是字符串常量的一部分,若在字符串中包含双撇号时,必须使用其转义字符表示。
例如:”,,”\n Name,\t\”Tsinghua\”[CHN]\n”
一个字符串可以在连续的几行中书写,在行末加一个续行符(\)表示下一行文本是本行中字符串常量的延续。例如:
,Beijing,China\n\
Tsinghua university\n\
Civil Engineer.\n”
在保存字符串常量时,除了组成字符串常量的字符序列本身外,系统还自动在该字符串的结尾处添加一个空字符null,用于标识一个字符串的终结。因此所占据的内存单元比该字符串的元素所用的内存单元长度多一个字节。
例如,‘A’
41
,A”
41
0
也可以采用指向字符型数据的常量指针来表示字符串常量,方法类似于整型常量。
2.3.3 变量
变量是内存中用一具标识符命名的存储单元,可以用来存储一个特定类型的数据,且数据的值在程序的运行过程中可以进行修改。
在C++中,使用某变量之前必须对该变量进行说明。变量说明通知编译器为变量分配内存空间。变量说明的一般形式如下:
<存储类型> 数据类型 变量1<,变量2,...>;
存储类型即为auto,regist,static,extern中之一,缺省时,编译器将根据对该变量进行说明的语句的位置,即该变量的作用域,为该变量指定相应的存储类型(参照数据分类的有关内容)。
数据类型指的是按构造进行分类的基本数据类型或聚合数据类型中的一种。它决定了该变量可以存储的数据的种类,编译器将根据该类型数据的存储特性为该变量分配相应大小的内存单元,同时规定了在该变量上可施加的操作集。
变量名是程序员为该变量指定的标识符,它的组成应该满足C++标识符命名的所有原则。
在C++中,一个语句的结束以分号“;”进行标识。在对多个变量进行说明时,如果需要,某一说明语句可以跨越多行,且无需任何续行符,说明语句的结束以遇到的第一个分号为标志。例如:
unsigned int count;
double mathScore,phyScore,
geoscore,engScore; //说明了4个双精度型变量
注意:(1)、C++是一种区分大小写的语言。
(2)、在某一变量的作用域,同名变量只能作一次定义性说明;不同作用域内的变量,它们的标识符(变量名)可以相同。
(3)、变量在使用之前一定要赋初值,否则将导致计算结果的错误或有可能死循环或死机。
(4)、C++的变量说明语句可以放在程序的任何位置,只要在该变量的使用之前甚至在使用它的同时说明即可。
下面通过一个例子体会C++变量说明的灵活性。
[例2.7] 乘法表打印程序——体会C++变量说明的灵活性。
//EX2_7.cpp
//乘法表打印程序--体会C++变量说明的灵活性。
#include<iostream.h>
void main()
{
cout<<"基本乘法表:"<<endl;//输出表头信息并换行
cout<<"**";//输出标题行首字符
for (int i=1;i<=9;i++)
{
cout<<" "<<i;//输出标题行各列标题
}
cout<<endl;
for(i=1;i<=9;i++) //共进行9次循环,循环变量从1到9
{
cout<<i<<"x";//输出各行的标题
for (int j=1;j<=i;j++)//共进行i次循环,循环变量从1到i
{
cout<<" "<<i*j;//输出两循环变量相乘结果
}
cout<<endl;//结束一行输出,进行换行。
}
}