第3单元 基本数据类型本单元教学目标
介绍C++的基本数据类型以及常数、变量和数组的使用方法。
学习要求通过本单元的学习,掌握几种基本数据类型,包括字符型、整型、长整型、浮点和双精度数据类型的基本概念,以及常数、变量和数组的使用方法。
授课内容
3.1 数据类型程序处理的对象是数据。数据有许多形式,如数值数据、文字数据、图象数据以及声音数据等,但其中最基本的、也是最常用的是数值数据和文字数据。
无论什么数据,计算机在对其进行处理时都要先存放在内存中。显然,不同类型的数据在存储器中存放的格式也不相同,甚至同一类数据,为了处理方便起见也可以使用不同的存储格式。例如数值数据,其存储格式又可以分为整型、长整型、浮点型和双精度型等几种类型; 文字数据也可以分为单个字符和字符串。因此在程序中在对各种数据进行处理之前都要对其类型 (也就是存储格式) 预先加以说明,这样做一是便于为这些数据分配相应的存储空间,二是说明了程序处理数据时应采用何种具体运算方法。
C++的数据有两种基本形式,一是常数,一是变量。常数的用法比较简单,通过本身的书写格式就说明了该常数的类型; 而在程序中使用变量之前必须先声明其类型,否则程序无法为该变量分配存储。也就是说,变量要“先声明,后使用”。这条原则不仅适合于变量,同样适合于C++程序的其他成分,如函数、类型和宏等。
C++的一个主要特点就是它的数据类型相当丰富,不但有字符型、短整型、整型、长整型、浮点型和双精度型等基本数据类型以及由它们构成的数组,还可以通过类的概念描述较复杂的数据对象。在本单元中,我们主要介绍几种基本数据类型的声明和使用方法。
3.1.1 整数数据的表示方法在C++中,存放一个整数数据可以使用字符型、短整型、整型和长整型等4种类型。这4种类型的格式相似,其最高位均为符号位,0表示正值,1表示负值。字符型数据占用一个字节存储空间,短整型数据占用两个字节,整型和长整型数据要占用4个字节的存储空间,见图3-1。
字符型数据占用一个字节,共8个2进制位; 其中第7位是符号位,因此数值部分可用7个2进制位表示,即字符型可以表现的数值范围为(27 ~ 27(1 ((128 ~ 127); 同理,短整型数据占用2个字节,可以表示的数值范围为(215 ~ 215(1 ((32768~32767); 而整型和长整型数据占用4个字节,可以表示的数值范围为(231到231(1。
在编写程序时应根据数据的实际情况选用相应的数据类型。一般的整数数据,大多选用整型表示。至于字符型,因其表示范围太小,通常很少用其存放整型数据,而是用来存放字符的代码(ASCII码)。
整型常数的表示方法比较简单,直接写出其数值即可。例如:
0,1,(2,637,32767,(32768,...
如果要指明一个整数数值使用长整型格式存放,可以在数值之后写一个字母l或L。由于小写l很容易和数字1相混,我们建议使用大写字母L表示长整形常数。例如,
0L,1L,(2L,637L,32767L,(32768L,...
如果要为一个整型变量分配存储空间,则要使用变量声明语句。C++的数据变量声明语句的格式为:
<类型说明符> <变量名1> [,<变量名2>,...,..,<变量名n>];
4种C++整数数据类型的说明符分别为:
char <字符类型变量表>;
short <短整型变量表>
int <整型变量表>;
long <长整型变量表>;
下面列出几个变量声明语句的例子:
char c1,c2; // 声明了2个字符型变量
int i,j,k; // 声明了3个整型变量
long len; // 声明了1个长整型变量
3.1.2 一般数值数据的表示方法在日常生活或工程实践中,大多数数据既可以取整数数值,也可以取带有小数部分的非整数数值,例如物体的尺寸、重量,货物的金额等。在C++中,可以使用浮点类型表示这类数据。浮点数据类型使用科学记数法表示数值,将数值分为尾数部分和指数部分,前者是一个纯小数,且小数点后第1位不为0; 后者是一个整数值。这两部分均可以为正或为负。实际数值等于尾数部分乘上10的指数部分的幂次。例如,圆周率π可以写成:
0.3141593×101
C++的浮点类型常数可以使用两种方式书写,一种是小数形式,例如
0.0,1.0,(2.68,3.141593,637.312,32767.0,(32768.0,...
这时应注意即使浮点类型的常数没有小数部分也应补上“.0”,否则会与整型常数混淆。另一种是科学记数形式,其中用字母e或者E表示10的幂次,例如:
0.0E0,6.226e(4,(6.226E(4,1.267E20,...
由于浮点类型仅使用了4个字节存放数据,所以其精度有限,一般只有6~7位有效数字。有时可能需要进行精度特别高的计算,这时可以使用双精度类型。双精度类型数据共占用8个字节,其有效数字可达16~17位。
当然,在程序中也可声明浮点类型和双精度类型的变量。这两种数据类型的说明符分别为:
float <浮点类型变量名表>;
double <双精度类型变量名表>;
举出两个变量声明语句的例子:
float average,sum; // 声明了两个浮点类型的变量
double distance,weight; // 声明了两个双精度类型的变量
[例3-1] 利用牛顿迭代公式求平方根。设,则迭代公式为

迭代结束条件取相对误差。
算 法,
声明两个工作变量x0和x1;
x1 = 1; // 迭代初值取1
do
{ x0 = x1;
;
}while(x1与x0的相对误差大于控制参数ε);
程 序:
// Example 3-1:用牛顿迭代公式求平方根
#include <iostream.h>
#include <math.h>
#define EPS 1.0e-10
// 函数 newton_sqrt(),用牛顿迭代法求平方根
double newton_sqrt(double x)
{
double x0,x1;
x1 = 1.0;
if(x>0.0)
{
do
{
x0 = x1;
x1 = (x0+x/x0)/2;
}while(fabs((x0-x1)/x1)>=EPS);
return x1;
}
else
return x;
}
// 用于计算平方根的主函数
void main()
{
double x,y;
cout << "Please input the value,";
cin >> x;
y = newton_sqrt(x);
if(y<0)
cout << "Negative Value have not square root !" << endl;
else
cout << "The square root of " << x << " is " << y << endl;
}
输 入,Please input the value,2.0
输 出,The square root of 2 is 1.41421
分 析,我们将求平方根的工作编为一个子程序,并在其中加上了简单的数据检验,当参数x的值小于或等于0时,不再进入迭代,直接返回x。这样就可以避免对负数迭代可能引起的溢出错误。在编写程序时加上完善的数据检测功能,是程序应用的基本保证。
3.1.3 文字数据的表示方法在C++中,文字数据有两种,一是单个的字符,一是字符串。对于字符数据来说,实际上存储的是其编码。由于英语中的基本符号较少,只有52个大小写字母、10个数字、空格和若干标点符号,再加上一些控制字符,如回车、换行、蜂鸣器等,总共不过100多个。因此,可以使用一个整数表示某个字符的代码。目前最常用的代码标准是ASCII码,ASCII码共使用了128个符号,分别使用整数0~127表示,可以参看附录1:“ASCII码表”。一般来说,在用C++编写程序时,单个的字符变量多选用整型变量存放,因为其数目有限,占用存储不多,而现在计算机的CPU中的数据字长多为16位以上,使用整型的运算速度比较快。但是对于字符串数据,由于占用的存储比较多,所以均选用字符型数组存放,一个数组元素 (字符类型的变量) 正好存放一个字符的ASCII码。
字符型常数实际上就是单个字符的ASCII码。 但是在程序中直接使用码值很不直观,例如从码值48和97很难看出它们实际上代表的是字符“0”和“a”。因此在C语言中引入了一套助记符号表表示ASCII码。 对于字母、数字和标点符号等可见字符来说,其助记码就是在该符号两边加上单引号。例如:
'a','A','1',' ','+',...
而那些控制字符和单、双引号、反斜杠符等可以使用由一个反斜杠符和一个符号组成的转义字符表示:
'\n'(换行),'\r'(回车),'\t'(横向跳格),'\''(单引号),...
常用的转义字符可以参看附录2,常用转义字符”。
注意上述助记符实际上仍是一个整数,因此也可以参加运算。例如:
c = 'A'+2; // c被赋值为字母C;
if(x>='0' && x<='9') // 如果x是一数字的ASCII码
x = x('0'; // 将其转换为相应的数值
[例3-2] 编制一个函数mylower(),将大写字母转换为小写字母。
算 法,我们知道,在ASCII表中,所有的大写字母从A到Z是连续排列的,所有的小写字母从a到z也是连续排列的,但大写字母和小写字母并没有排在一起。因此,如果一个字符是大写字母,我们可以通过对其ASCII码作如下运算将其转换为对应的小写字母的ASCII码:
大写字母的ASCII码值('A'+'a' = 对应的小写字母的ASCII码值程 序,
// Example 3-2:将大写字母转换为小写字母
int mylower(int ch)
{ if(ch>='A' && ch<='Z')
ch = ch('A'+'a';
return ch;
}
分 析,字符数据以整型或字符型格式存放,实际存放的是字符的ASCII码。从而可以使用数值数据的运算方法来处理字符数据。在函数mylower()中,如果一个字符不是大写字母,则不进行转换。
字符串常数即用双引号括起来的一串字符,例如:
"Visual C++","12.34","This is a string.\n",...
字符串常数在内存占用的实际存储字节数要比字符串中的字符个数多1个,即在字符串的尾部还要添加一个数值为0的字符,用以表示字符串的结束。该字符也可以使用转义序列'\0'表示。以字符串"MONDAY"为例,其实际存储形式见图3-2。
因此,'B'与"B"是有区别的,前者是一个字符型常量,而后者是字符串常量,由两个字符'B'和'\0'组成。
3.2 数组变量和常数只能用来表示少量互相之间没有内在联系的数据,大量的成批数据要使用数组来存放。所谓数组是一组相同类型的变量,用一个数组名标识,其中每个变量(称为数组元素)通过该变量在数组中的相对位置(称为下标)来引用。数组可以是一维的,也可以是二维或者更高维的。图3-3分别给出了一维、二维和三维数组中的数组元素排列方法。
数组的声明方法与变量相同,只是要在数组名后面加上用方括号括起来的各维维长。例如:
int array1[10]; // 声明了一个有10个元素的整型数组
float matrix[20][20]; // 声明了一个20行20列的浮点型矩阵数组元素的下标从0开始编号。例如,array1[0]是数组array1中的第一个数组元素; matrix[0][0]是矩阵matrix中的第1行第1列元素,位于矩阵的左上角。
同一个数组的所有数组元素在存储器中占用一片连续的存储单元。
对于数组来说,最常用的处理方法是在通过循环处理数组中的元素。例如
// 将数组中的所有元素置零
for(int i = 0; i < N; i = i+1)
array1[i] = 0;
// 将矩阵matrix置成单位矩阵
for(int i = 0; i < 20; i = i+1)
{ for(int j = 0; j < 20; j = j+1)
matrix[i][j] = 0.0;
matrix[i][i] = 1.0;
}

[例3-3] 找出一个数组中最大的元素。
算 法,找数组中的最大元素这类问题可以利用扫描法解决。即以数组的第一个元素为基准,向后比较,如果遇到有比基准元素更大的元素则将基准元素替换为该元素,直到数组中所有的元素均被扫描。这时得到的最新的基准元素就是数组中最大的元素。
程 序,
// Example 3-3:求数组中的最大元素
int max_element(int array[],int count)
{
int big = array[0];
for(int i=0;i<count;i=i+1)
if(array[i]>big)
big = array[i];
return big;
}
3.3 字符型数组和字符串处理库函数
C++使用字符型数组存放字符串数据。由前述字符串常数的存储格式可知,字符串包括一个结束符'\0',所以在计算用于存放字符串的数组的大小时要考虑到这一点。例如,如果要设计一个能够存放最大长度为80个字符的字符串的数组,其长度应为81。
字符型数组的用法和普通数组相同。例如,我们设计一个字符型数组weekday用于存放星期的名称,并将字符串"MONDAY"存入其中,可以这样设计:
char weekday[11];
weekday[0] = 'M';
weekday[1] = 'O';
weekday[2] = 'N';
weekday[3] = 'D';
weekday[4] = 'A';
weekday[5] = 'Y';
weekday[6] = '\0';
其中最后一句也可以直接写成
weekday[6] = 0;
可以看出,这样操作相当烦琐。因此,C++提供了一批用于字符串处理的库函数,可以完成许多常用的字符串操作:
strcpy(),字符串拷贝;
strcat(),字符串连接;
strchr(),在字符串中查找字符;
strcmp(),字符串比较;
strlen(),求字符串长度;
strlwr(),将字符串中的大写字母转换为小写字母;
strrev(),反转字符串;
strstr(),在字符串中查找另一个字符串;
strupr(),将字符串中的小写字母转换为大写字母;
...,..
因为这些库函数的声明存放在头文件string.h中,所以如果我们要在程序中调用这些函数,还应该在源程序的最前面加上一个文件包含的编译预处理命令:
#include <string.h>
下面我们介绍其中几个常用的字符串操作函数的用法:
(1)求字符串的长度:
int strlen(char *s);
其中的参数说明char *s意为s是一个指向字符类型的指针。指针类型在第6单元中有介绍,目前我们只需知道该参数既可以使用字符串常数,也可以使用字符型数组就可以了。该函数的返回值即为字符串中字符的个数 (不包括字符串结束符)。例如语句
len = strlen("This is a sample.");
执行后,变量len会被赋值17。
(2)复制字符串:
strcpy(char *destin,char *source);
该函数的功能为将字符串source的内容复制到字符型数组destin中。注意,destin的长度一定要比字符串source的实际长度大,否则会引起严重的运行错误。例如:
char weekday[11];
strcpy(weekday,"MONDAY");
(3)连接字符串:
strcat(char *destin,char *source);
该函数的功能为将字符串source的内容复制到字符型数组destin中原来的字符串的后面,使两个字符串合并成一个字符串。使用该函数时特别要注意保证字符型数组destin的长度一定能够放得下合并后的整个字符串(包括最后的字符串结束符)。否则也会引起严重的运行错误。
(4)字符串比较,
int strcmp(char *string1,char *string2);
该函数的功能为对两个字符串进行比较。比较是按字典序进行的,即在字典中排在前面的单词小于排在其后的单词。当然,一般的字符串中不但可以有英文字母,还可能有其他符号,这时各个符号之间的比较按ASCII码的顺序进行。
如果字符串string1小于字符串string2,该函数返回一个负整数值; 如果字符串string1 等于字符串string2,该函数返回0; 如果字符串string1 大于字符串string2,该函数返回一个正整数值。例如
if(strcmp(weekday,"SUNDAY")==0)
cout<<"Today we have a party."<<endl;
(5)将字符串中的小写字母转换为大写字母或者将大写字母转换为小写字母:
strlwr(char *string);
strupr(char *string);
这两个函数的功能类似,都是转换字符串中的英文字母,对字符串中的其他符号没有影响。例如
strlwr(weekday);
如果转换前字符型数组中存放着字符串"MONDAY",则转换后其内容变为"monday"。
其实,这些标准库函数并不神秘,我们也完全可以编写出同样功能的程序来。
[例3-4] 自己编写一个函数mystrlen(),用来计算字符串的长度。
程 序,
// Example 3-4:求字符串的长度
int mystrlen(char string[])
{
int len = 0;
while(string[len]!='\0')
len = len+1;
return len;
}
分 析,该函数的构造非常简单。值得注意的有两点,一是作为参数的一维数组可以不写明数组元素的个数。但C++规定,2维以上的数组,除了第1维以外均应注明维长。例如:
void set_empty(double matrix[][10])
{
...,..
}
另外,要注意区别字符串的长度和存放字符串的字符型数组的长度两个不同的概念。字符串靠结束符'\0'表示字符串的结束,字符串的长度是到字符串结束符之前的字符个数 (不包括字符串结束符)。因此,字符串的长度要小于字符型数组的大小。
自学内容
3.4 变量的初始化
C++允许在声明变量的同时对变量赋一个初值,例如:
int count = 0;
double pi = 3.141592658979D0;
int upper = 'A';
另一种初始化变量的方法如下:
<类型> <变量>(<表达式>)
例如
int i(5);
char ch(‘a’+count);
3.5 类型修饰符和常量修饰符基本类型声明语句的前面还可以加上各种修饰符。修饰符用来改变基本类型的意义,以便更准确地适应各种情况的需求。C++提供的修饰符如下:
signed ---- 有符号
unsigned ---- 无符号
signed的意义为带符号。由于基本类型char,short,int,long等均为带符号位的类型,所以signed修饰符的用途不大。unsigned适用于char,short,int和long四种整数类型,其意义为取消符号位,只表示正值。这样,unsigned char 的表示范围就变为0~255,unsigned short类型的表示范围变为0~65535,而unsigned int (可以直接写成unsigned) 类型和unsigned long类型的表示范围变为0~232(1。
另外,在Visual C++中,还可以使用类型_int8,int16,int32和int64等整型类型,其中的数字直接指出该整数类型的位数。例如,_int8为8位整型(即char型),_int32为32位整型(即int型)。
综合类型修饰符和类型名,在Visual C++中可使用下列类型声明:
char,signed char,_int8, (8位整型)
unsigned char, (无符号8位整型)
short,short int,signed short int,_int16, (16位整型)
unsigned short,unsigned short int, (无符号16位整型)
int,signed int,signed,_int32, (32位整型)
unsigned int,unsigned, (无符号32位整型)
long,long int,signed long int, (32位整型)
unsigned long,unsigned long int, (无符号32位整型)
_int64, (64位整型)
float, (32位浮点型)
double, (64位浮点型)
long double(在Windows95和Windows NT中与double类型的格式相同)
如果要表示某个变量的值不能修改,可使用常量修饰符const。常量修饰符多用于修饰函数的参数。例如:
double func(const double arr[],const int count)
{
… …
}
表示在函数体内参数arr和count的值不变,不能出现对它们的赋值等操作。如用const修饰一般变量,则需同时初始化该变量:
const int person_count = 1000;
3.6 枚举类型如果某个数据项只可能取少数几种可能的值,则可以将该数据项声明为枚举类型数据。枚举类型的声明格式为
enum <枚举类型名>
{
<枚举符号表>
};
例如,一周的天数可以声明为
// 声明星期几类型
enum weekday_type
{
SUNDAY,// 星期日
MONDAY,// 星期一
TUESDAY,// 星期二
WEDNESDAY,// 星期三
THURSDAY,// 星期四
FRIDAY,// 星期五
SATURDAY // 星期六
};
可以声明枚举类型的变量:
enum weekday_type workday;
变量workday只能取枚举类型中列出的符号值。例如
workday = MONDAY;
掌握枚举类型的关键在于,每个枚举符号实际上是一个整数值。例如,对于枚举类型enum weekday_type来说,MONDAY等于1。因此,如果我们要打印变量workday的值,只能使用整型输出格式符,打印出的值为1。
一般情况下,一个枚举类型中的各枚举值从0开始顺序取值。在上面的例子中,从SUNDAY到SATURDAY分别取值0,1,…,6。另外,在声明枚举类型时,也可以对各枚举符号进行初始化,改变其对应的整数值。例如
// 声明星期几类型
enum weekday_type
{
MONDAY = 1, // 星期一
TUESDAY, // 星期二
WEDNESDAY, // 星期三
THURSDAY, // 星期四
FRIDAY, // 星期五
SATURDAY, // 星期六
SUNDAY // 星期日
};
则从MONDAY到SUNDAY所对应的值分别为1,2,…,7。实际上,枚举符号也可以作为符号常数赋给整型变量,或者作为整数值参加运算。
3.7 typedef语句
typedef语句(类型说明语句) 的功能是利用某个已有的数据类型定义一个新的数据类型。其格式为:
typedef <数据类型或数据类型名> <新数据类型名>
例如,为float类型取一个别名real可以使用类型说明语句:
typedef float real;
此后的程序中可以使用real代替float声明浮点型变量:
real x,y;
等价于语句
float x,y;
调试技术
3.8 Developer Studio的文件处理功能
Developer Studio提供了很完整的文件处理功能,可处理程序文本文件、项目文件、WORD文档和EXCEL文档等。对于上述文件,可选的操作有建立(New…)、打开(Open…)、编辑(Edit)、保存(Save)和关闭(Close)等。
在Developer Studio中,可使用多种方法进行文件操作,如通过菜单、使用快捷键和工具条中的图标等。其实,不仅文件处理,Developer Studio的多数常用功能都有若干种调用方式,用户可根据实际情况选用最方便的一种。
Developer Studio的File子菜单共有14项,分为6组,组与组之间用横线隔开。第1组用于建立、打开和关闭文件处理的对象,包括项目、文件、工作区和其他文档:
建立新对象(New…,快捷键为CTRL+N)。选择该菜单项,可打开一个有若干卡片的对话框,各卡片的内容分别为:
项目(Projects):用于建立项目。项目即要开发的应用程序,Developer Studio可用于开发各种类型的应用程序,如控制台应用程序(Win32 Console Application)、32位Windows应用程序(Win32 Application)和MFC应用向导程序(MFC AppWizard)等。对于不同类型的项目,建立的具体文件也不同。
文件(Files):用于建立各种文件,包括源程序文件(Source File,文件名后缀为cpp)、头文件(Header File,文件名后缀为h)、文本文件(Text File,文件名后缀为txt)、位图文件(Bitmap File,文件名后缀为bmp)等。
工作区(Workspaces):每个正在开发的项目要占用一个工作区。一般来说,在建立项目的同时即为其建立了工作区。但也可用本选项建立一个空的工作区。
其他文档(Other Documents),用于建立一些文档文件,如MS Excel工作表,MS Excel图表,MS PowerPoint演示文稿和MS Word排版文档等。
(2)打开已有对象(Open…,快捷键为CTRL+O)。用于打开一个已存在的项目、文件或文档。选择该菜单项,会弹出一个文件路径对话框,用于确定要打开的内容。
(3)关闭文件(Close)。用于关闭当前打开并激活的文件。
第2组用于处理工作区。包括:
(4)打开工作区(Open Workspace…)。用于一个已存在的工作区。工作区的有关参数(包括应用程序的结构体系,特别是其类、资源、文件和帮助信息等的参数)存放在后缀名为dsw和mdp的文件中。与打开文件菜单项类似,选择该菜单项会弹出一个文件路径对话框,用于确定工作区文件的位置。
(5)保存工作区(Save Workspace)。用于保存当前打开的工作区文件。
(6)关闭工作区(Close Workspace)。用于关闭当前打开的工作区文件。
第3组用于处理当前文件,包括:
(7)保存文件(Save,快捷键为CTRL+S)。用于保存当前正在使用的文件。
(8)另存文件(Save As…)。将当前文件换一个名字保存,原来的文件内容不变。选择该菜单项会弹出文件路径对话框,以确定新文件的文件名和存放位置。
(9)保存所有文件(Save All)。保存当前打开的所有文件。
第4组用于打印当前文件,包括:
(10)页面设置(Page Setup…)。设置打印页面格式,为打印当前文件作准备。选择该项会弹出一对话框,可在其中设置打印页面格式等参数。
(11)打印当前文件(Print…,快捷键为CTRL+P)。用于打印当前文件。选择该项时弹出一对话框,可在其中对打印机参数进行设置。
第5组用于快速打开或切换文件和工作区。包括:
(12)最近使用过的文件( Recent Files)。用于直接打开最近几次在Developer Studio 中使用过的文件,可在弹出的下级菜单中直接选取。
(13)最近使用过的工作区(Recent Workspaces)。用于直接打开最近几次在Developer Studio中打开过的工作区,可在弹出的下级菜单中直接选取。
最后1组只有一个菜单项:
(14)退出Developer Studio(Exit)。选择该菜单项可以关闭当前打开的所有对象,包括项目、工作区和文件等,退出Developer Studio,返回Windows98操作系统界面。
3.9 Visual C++程序的编译、连接和运行
Developer Studio提供了一整套功能,用于应用程序的编译、连接和运行(包括调试运行)。
用于编译、连接和运行应用程序的功能集中在创建(Build)子菜单中,但其中多数功能也可通过快捷键和工具条调用。
Developer Studio的Build子菜单共有11项,分为4组,组与组之间用横线隔开。第1组包括编译、连接等功能:
(1)编译当前项目(Compile,快捷键为Ctrl+F7)。用于将源程序编译为目标代码。编译结果及编译错误信息在输出窗口(Output)显示。
(2)编译、连接当前项目(Build,快捷键为F7)。在对当前项目的源程序编译之后,还进行连接(Link)操作,即将目标代码与系统或用户类库连接并生成可执行的程序(或动态连接库.DLL等)。编译、连接结果及编译、连接的错误信息在输出窗口(Output)显示。该选项的特点是可只对新修改的文件进行编译和连接,因此速度较快,是编程、调试的常用功能。通常可用鼠标点击工具条上的对应图标调用该功能,非常方便。
(3)重新编译、连接当前项目(Rebuild All)。功能与<Build>基本相同,只是无论是否修改过,对所有文件都重新进行编译和连接工作。
(4)以批处理方式编译、连接当前项目(Batch Build)。功能与<Build>基本相同,只是同时产生调试版和发行版执行程序。
(5)清除临时文件( Clean)。用于清除上一次编译、连接时产生的临时文件和输出文件,以整理程序目录。
第2组用于调试程序,包括开始调试(Start Debug)和远程调试链接(Debugger Remote Connect)(详见5.14节)。
第3组用于执行应用程序。包括:
(6)执行当前项目的可执行程序(Execute,快捷键为Ctrl+F5)。用于执行当前项目经编译、连接生成的可执行程序。如果是控制台应用程序,结果在弹出的字符界面窗口中显示;如果是Windows应用程序,则应用程序的中窗口覆盖在Developer Studio窗口之上。
第4组用于设置编译和连接工作的参数。包括:
(7)设置项目的版本类型(Set Active Configuration…)。Developer Studio生成的可执行文件有两种版本,一种是调试版本(Win32 Debug),内含调试代码,体积稍大,主要在编程调试过程中使用。另一种是发放版本(Win32 Release),其中不包含调试代码,体积小,用于在程序调试结束后提交用户。
(8)管理项目版本(Configuration…)。用于管理项目的调试版本和发放版本。
(9)Profile…
3.10 查看和修改编译、连接错误编译的目的是将C++源程序转换为机器指令代码。在编译过程中,如果遇到程序中有语法错误,则在Developer Studio底部的输出(Output)窗口中显示相应的错误信息,提示程序员修改程序。刚编写好的程序含有错误是正常的,即使是熟练的专业程序员也很难一次就编写出完全没有错误的源程序来。实际上,重要的不是程序中是否有错误,而是怎样将这些错误找出来并改正之。一般来说,一段源程序从输入编辑到通过编译,往往要重复若干次编译-修改-再编译的过程。
如果编译成功,则生成目标文件存放在磁盘上。如果在编译的过程中发现了错误,则进入编辑查错状态。这时在屏幕下方的Output窗口中会显示出错误的类型、错误发生的位置以及错误的原因。错误信息的格式为:
<源程序路径>(行)<错误代码>,<错误内容>
错误有两种,一种是Error,表示这是一个严重错误,非改不可。另一种是Warning,表示源程序这里有可能是错误的,也有可能不是错误,编译程序自己也拿不准。一般来说,如果只出现警告信息,还是可以继续连接、运行程序,有些程序员因此而经常忽视这些编译警告,继续连接、运行程序,直到出现了某种运行错误后再回过头来检查这些警告信息。这是非常糟糕的工作习惯,因为运行错误比编译错误更难于检查和修改,严重的运行错误还会引起“死机”现象。因此,我们建议在出现编译警告时最好还是仔细检查一下,设法消除引起警告的原因。
错误发生的位置包括源程序的路径和文件名以及错误所在行。必需说明的是C++编译程序的“智力”并不十分高,虽然能够查出错误,但对错误的说明可能并不十分准确,而且一个实际错误往往会引出若干条错误说明,使人不容易摸清到底错在什么地方。错误的原因其实可能很简单,例如少写了一个括号、分号或拼错了一个单词,都可能引起一连串的错误提示。真正的错误之处也可能在此之前的某个语句。而且指出的错误条数可能偏多,常常是由于一处出错而引发了一系列错误提示信息。
用鼠标双击一条错误信息可使文本编辑器作出反应,其左框上显示一个箭头指出对应的出错语句,以便修改源程序。在检查程序时要细心,首先查看第一个错误出现的地方及其前面的一小段程序。在查出并改正这个错误之后,可以看一看其后的几个错误说明中的错误位置是否和第一个错误的位置相邻近。如果是,则有可能反映的还是那一个错误,这时可以再编译一次,往往会发现错误的数目已经大为减少。重复这个过程直到所有的错误均已纠正,然后再次连接、运行该程序。
在连接阶段也可能出现一些错误提示。与编译错误提示信息不同的是连接错误不指出错误发生的详细位置,这是因为连接的对象是目标程序,和源程序格式有很大差别,不易确定错误的准确位置。
连接阶段出现的错误一般比较少,大多数是因为在程序中调用了某个函数,而连接程序却找不到该函数的定义。这时最有可能的是函数名字拼写错误。另外,如果程序的规模较大,需要分为若干个源程序文件分别编译然后连接,则也可能出现全局变量重复声明或找不到等错误现象。
在找到连接错误的原因并改正以后,一定要重新编译后才能再次连接。否则,虽然源程序已经修改,但进行连接的目标程序还是以前有错误的目标程序,再次连接仍然会产生同样的错误。
程序设计举例
[例3-5] 矩阵相乘。
原 理:设有l行m列矩阵Al(m和m行n列矩阵Bm(n(即第一矩阵之列数等于第二矩阵的行数),则由线性代数得知其积为一l行n列的矩阵Cl(n,
Cl×n =Al×m×Bm×n
其中

算 法,用两重循环实现对Cij的求值:
for(i=0; i<l; i=i+1)
for(j=0; i<n; j=j+1)
求Cij;
其中“求Cij”又可以细化为:
Cij = 0;
for(k=0; k<m; k=k+1)
Cij = Cij+Aik×Bkj
据此编写一个通用的矩阵相乘函数。由于C++要求在声明二维数组时要明确写出第二维的长度,这不利于编写通用的计算函数,所以我们在函数中用一维数组模拟二维矩阵。显然,要进行两个矩阵的乘法,不但要提供这两个矩阵,还要提供存放计算结果的矩阵以及这3个矩阵各维的长度。
程 序
// Example 3-5:计算两个矩阵的乘积
// 函数matrix_multi(),计算两个矩阵的乘积
#include <iostream.h>
void matrix_multi(double a[],double b[],double c[],int l,int m,int n)
{
int i,j,k;
for(i=0;i<l;i=i+1)
for(j=0;j<n;j=j+1)
{
c[i*n+j] = 0;
for(k=0;k<m;k=k+1)
c[i*n+j] += a[i*m+k]*b[k*n+j];
}
}
// 测试上述矩阵相乘函数的主程序
void main()
{
double a[20]=
{
1.0,3.0,-2.0,0.0,4.0,
-2.0,-1.0,5.0,-7.0,2.0,
0.0,8.0,4.0,1.0,-5.0,
3.0,-3.0,2.0,-4.0,1.0
};
double b[15]=
{
4.0,5.0,-1.0,
2.0,-2.0,6.0,
7.0,8.0,1.0,
0.0,3.0,-5.0,
9.0,8.0,-6.0
};
double c[12];
matrix_multi(a,b,c,4,5,3);
cout << "The result is c=" << endl;
for(int i=0;i<4;i=i+1)
{
for(int j=0;j<3;j=j+1)
cout << c[i*3+j] << " ";
cout << endl;
}
}
输 出,The result is c=
32 15 -9
43 27 24
-1 -21 77
29 33 -5
分 析,我们为矩阵相乘函数编写了一个测试用的主函数。在主函数中,我们要计算4行5列矩阵a和5行3列矩阵b的乘积。这两个矩阵的数据用赋初值的方法提供。对于矩阵(二维数组)来说,输出应使用两重循环实现。
[例3-6] 编写一个用于对整型数组进行排序的函数,排序方法使用简单的交换排序法。
算 法,交换排序法也称冒泡排序法,其思路是将相邻的元素进行比较,如果不符合所要求的顺序(通常是先小后大,又称升序)则交换这两个元素。对整个数组中所有的元素反复运用上法,直到所有的元素都排好序为止。
程 序,
// Example 3-6:交换排序
// 函数 bubble_up(),冒泡法排序
#include <iostream.h>
void bubble_up(int list[],int count)
{
for(int i=0; i<count; i=i+1)
for(int j=count-1; j>i; j=j-1)
if(list[j-1]>list[j])
{
int tmp = list[j-1];
list[j-1] = list[j];
list[j] = tmp;
}
}
// 测试冒泡法排序的主程序
void main()
{
int list[16]=
{
503,87,512,61,908,170,897,275,
653,426,154,509,612,677,765,703
};
bubble_up(list,16);
cout << "The result is," << endl;
for(int i=0;i<16;i++)
cout << list[i] << " " << endl;
}
输 出,The result is,
61 87 154 170 275 426 503 509 512 612 653 677 703 765 897 908
分 析,冒泡排序是一种效率较低的排序方法,排序所用的时间与表长的平方成正比。因此,如果需要排序的表比较长,冒泡排序所花费的时间就很可观。
[例3-7] 编写一个字符串处理函数,可以将一个字符串之中的所有小写字母转换为相应的大写字母。
程 序:
// Example 3-7:将字符串中所有的小写字母转换为大写字母
void mystrupr(char string[])
{
int i = 0;
while(string[i]!=0)
{
if(string[i]>='a' && string[i]<='z')
string[i] = string[i]-'a'+'A';
i = i+1;
}
}
分 析,我们知道,在ASCII码表中所有的小写字母的代码是按照由小到大的顺序排列好的,所有的大写字母的代码也是按照由小到大的顺序排列好的,但大写字母和小写字母并不相邻。因此,如果一个字符c是小写字母,可以使用表达式c-'a'+'A'将其转换为大写字母。
[例3-8] 编写一个用于字符串比较的函数mystrcmp()。
算 法,字符串的比较应按字典序判断。例如,由于单词“word”在辞典中排在单词“work”的前面,所以我们讲单词“word”小于单词“work”。实际上进行两个字符串的比较时,要按字符串中的各个字符在ASCII码表中的次序进行比较,这是因为在字符串中不仅可以出现字母,还可能出现其他符号。只有当两个字符串中所有对应位置上的符号分别相同时,才能认为这两个字符串相等。
程 序:
// Example 3-8:比较两个字符串
int mystrcmp(char s1[],char s2[])
{
int i = 0;
while(s1[i]==s2[i] && s1[i]!=0 && s2[i]!=0)
i++;
return s1[i](s2[i];
}
分 析,我们设计了一个循环,从两个字符串的第一个字符开始比较,直到出现不同的字符,或者有一个字符串已经结束为止。从程序中可以看出,这时如果两个字符串相等,则函数mystrcmp()返回0;如果字符串s1大于字符串s2,则返回一个正数; 如果字符串s1小于字符串s2,则函数返回一个负数。
单元上机练习题目用数组来处理求斐波那挈数列的第n项和前n之和。
打印出以下的杨辉三角形(要求打印出10行)
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
...,..
编写一个函数,求给定的一个二维数组( N X N )的转置,即行列互换。要求编出主函数进行验证。
4,矩阵相加。
原 理:设有矩阵Am×n和矩阵Bm×n,则其和亦为一m行n列矩阵Cm×n:
Cm×n=Am×n+Bm×n
其中
Cij=Aij+Bij (i=1,2,...,m,j = 1,2,...,n)
可仿照例3-7自己设计算法,并用其编写程序用于计算3行3列的方阵之和。
5,编写一个字符串处理函数,可以将一个字符串之中的所有大写字母转换为相应的小写字母,并编写相应的主函数验证之。
函数格式
void mystrlwr(char string[])
{
,..,..
}