第1章--基本C++语言[247页]课件

PPT
  • 阅读 67 次
  • 下载 0 次
  • 页数 247 页
  • 大小 1.755 MB
  • 2022-11-24 上传
  • 收藏
  • 违规举报
  • © 版权认领
下载文档40.00 元 加入VIP免费下载
此文档由【小橙橙】提供上传,收益归文档提供者,本网站只提供存储服务。若此文档侵犯了您的版权,欢迎进行违规举报版权认领
第1章--基本C++语言[247页]课件
可在后台配置第一页与第二页中间广告代码
第1章--基本C++语言[247页]课件
可在后台配置第二页与第三页中间广告代码
第1章--基本C++语言[247页]课件
可在后台配置第三页与第四页中间广告代码
第1章--基本C++语言[247页]课件
第1章--基本C++语言[247页]课件
还剩10页未读,继续阅读
【这是免费文档,您可以免费阅读】
/ 247
  • 收藏
  • 违规举报
  • © 版权认领
下载文档40.00 元 加入VIP免费下载
文本内容

【文档说明】第1章--基本C++语言[247页]课件.pptx,共(247)页,1.755 MB,由小橙橙上传

转载请保留链接:https://www.ichengzhen.cn/view-44634.html

以下为本文档部分文字说明:

VisualC++实用教程(VisualStudio版)(第6版)第1章基本C++语言——C++程序结构目录01C++概述C++概述C++是在C语言基础上由贝尔实验室的BjarneStroustrup在1980年创建的。研制C++的一个重

要目标是使C++首先是一个更好的C,所以C++根除了C中存在的问题(如对数据类型检查机制比较弱,缺少支持代码重用的结构,是一种面向过程的编程语言等)。C++的另一个重要目标就是面向对象的程序设计,因此在C++中引入了类的机制。最初的C++被称为“带类的C”,1983年正式命名为C++(CP

lusPlus)。以后经过不断完善,形成了目前的C++。为了使C++具有良好的可移植性,1990年,美国国家标准局(ANSI)设立了ANSIX3J16委员会,专门负责制定C++标准。很快,国际标准化组织(ISO)也成立了自己的委员会(ISO-WG-

21)。同年,ANSI与ISO将两个委员会合并,统称为ANSI/ISO,共同合作进行标准化工作。经过长达9年的努力,C++的国际标准(ISO/IEC)在1998年获得了ISO、IEC(国际电工技术委员会)和ANSI的批准,这是第一个C++的国际标准ISO/IEC14882:1998,常称为C+

+98、标准C++或ANSI/ISOC++。目录02C++程序创建1.创建工作文件夹2.启动MicrosoftVisualStudio20083.创建项目并添加C++程序4.生成和运行5.添加和移除C+

+程序创建使用C++等高级语言编写的程序称为源程序。由于计算机只能识别和执行的是由0和1组成的二进制指令,称为机器代码,因而C++源程序是不能被计算机直接执行的,必须转换成机器代码才能被计算机执行。这个转换过程就是编译器对源代码进行编译和连接的过程。如图1.1所示。源代码编译器目标代码连接程序可执

行代码库其他代码C++程序创建事实上,对于C++程序的源代码编辑、编译和连接的步骤,许多C++编程工具软件商都提供了各自的C++集成开发环境(IntegratedDevelopmentEnvironment,IDE)用于程序的一体化操作,常见的有Micros

oftVisualStudio(MicrosoftVisualC++)、各种版本的BorlandC++(如TurboC++、C++Builder等)、IBMVisualAgeC++和Bloodshed

免费的Dev-C++等。但MicrosoftVisualStudio在项目文件管理、调试以及操作的亲和力等方面都略胜一筹,从而成为目前使用极为广泛的基于Windows平台的可视化编程环境。如图1.2所示。C++程序创建1.创建工作文件夹创建Visu

alC++的工作文件夹“D:\VisualC++程序”,以后所有创建的C++程序都在此文件夹下。在文件夹“D:\VisualC++程序”下再创建一个子文件夹“第1章”用于存放第1章中的C++程序;对于第2章程序就存放在子文件夹“第2章”中,以

此类推。2.启动MicrosoftVisualStudio2008在Windows7(及其以后操作系统)中,选择“开始”→“所有程序”→“MicrosoftVisualStudio2008”→“MicrosoftVisualStudio

2008”菜单命令,运行MicrosoftVisualStudio2008。C++程序创建第一次运行时,会出现如图1.3所示的“选择默认环境设置”对话框。对于VisualC++用户来说,为了能沿续以往的环境布局和操作习惯,应选中“VisualC++开发设置”,然后单击按钮。稍等片刻后,出

现VisualStudio2008开发环境(参见前图1.2)。C++程序创建3.创建项目并添加C++程序(1)选择“文件”→“新建”→“项目”菜单命令或按快捷键【Ctrl+Shift+N】或单击标准工具栏

中的按钮,弹出“新建项目”对话框,在“项目类型”栏中选中“VisualC++”下的“Win32”,在“模板”栏中选中;单击按钮,将项目位置定位到“D:\VisualC++程序\第1章”文件夹中,在“名称”栏中输入项

目名称“Ex_1”(双引号不输入)。特别地,要去除“创建解决方案的目录”选项(不然文件夹的层次有点多),如图1.4所示。C++程序创建(2)单击按钮,弹出“Win32应用程序向导”对话框,单击按钮,进入“应用程序设置

”页面,一定要选中“附加选项”的“空项目”,如图1.5所示,单击按钮,系统开始创建Ex_1空项目。C++程序创建(3)选择“项目”→“添加新项”菜单命令或按快捷键【Ctrl+Shift+A】或单击标准工具栏中的按钮,弹出“添加新项”对话框,在“类别”栏

中选中“VisualC++”下的“代码”,在“模板”栏中选中;在“名称”栏中输入文件名称“Ex_Simple1”(双引号不输入,扩展名.cpp可省略),如图1.6所示。C++程序创建(4)单击按钮,在打开的文档窗口中输入下列

C++代码。【例Ex_Simple1】一个简单的C++程序/*第一个简单的C++程序*/#include<iostream>usingnamespacestd;intmain(){doubler,area;//定义变量r,area双精度整数类型co

ut<<"输入圆的半径:";//显示提示信息cin>>r;//从键盘上输入的值存放到r中area=3.14159*r*r;//计算圆面积,结果存放到area中cout<<"圆的面积为:"<<area<<"\n";//输出结果return0;//指定返回值}C++程序创

建4.生成和运行(1)选择“生成”→“生成解决方案”菜单命令或直接按快捷键【F7】,系统开始对Ex_Simple1.cpp进行编译、连接,同时在输出窗口中显示编连信息,当出现“Ex_1-0个错误,0个警告

”时表示可执行文件Ex_1.exe已经正确无误地生成了。(2)选择“调试”→“开始执行(不调试)”菜单命令或直接按快捷键【Ctrl+F5】,就可以运行刚刚生成的Ex_1.exe了,结果弹出下面的窗口(其属性已被修改过,具体修改

方法见实验1),它称为控制台窗口,是一种为兼容传统DOS程序而设定的屏幕窗口:此时等待用户输入一个数。当输入10并按【Enter】键后,控制台窗口显示为C++程序创建5.添加和移除(1)再次选择“项目”

→“添加新项”菜单命令或按快捷键【Ctrl+Shift+A】或单击标准工具栏中的按钮,弹出“添加新项”对话框,在“类别”栏中选中“VisualC++”下的“代码”,在“模板”栏中选中;在“名称”栏中输入文件名称“Ex_Simple2”(双引号不输入,扩展名.cpp可省略),单击按钮,在打开的文档

窗口中输入下列C++代码。【例Ex_Simple2】函数调用输出三角星阵//输出星号的三角形阵列#include<iostream>usingnamespacestd;voidShowTriStars(intnum);//声明一个全局函数intmain

(){ShowTriStars(5);//函数的调用return0;//指定返回值}voidShowTriStars(intnum)//函数的定义{for(inti=0;i<num;i++){for(intj=0;j<=i;j++)

cout<<'*';cout<<'\n';}}C++程序创建(2)在源文件节点处右击鼠标,从弹出的快捷菜单中选中“从项目中排除”命令,如图1.7所示,这样就将最前面的Ex_Simple1.cpp源文件排除出项目。C++程序创建(3)选择“调试”→“开始执行(不调试)”菜单命令或直接按快捷键【Ct

rl+F5】,弹出对话框,提示“此项目已过期,...,要生成它吗?”,单击按钮,运行的结果如下面的窗口:目录03C++代码结构1.main函数2.输入输出3.预处理指令4.注释5.缩进C++代码结构1.main函数代码中,main表示主函数,由于每一个程序执行时都必须从

main开始,而不管该函数在整个程序中的具体位置,因此每一个C++程序或由多个源文件组成的C++项目都必须包含一个且只有一个main函数。在main函数代码中,“intmain()”称为main函数的函数头,函数头下面是用一对花括

号“{”和“}”括起来的部分,称为main函数的函数体,函数体中包括若干条语句(按书写次序依次顺序执行),每一条语句都由分号“;”结束。由于main函数名的前面有一个int,它表示main函数的类型是整型,须在函数体中使用关键字return,用来将其后面的

值作为函数的返回值。C++代码结构2.输入输出main函数体内的第1条语句是用来定义两个双精度实型(double)变量r和area,第2条语句是一条输出语句,它将双引号中的内容(即字符串)输出到屏幕上,cout

表示标准输出流对象(屏幕),“<<”是插入符,它将后面的内容插入到cout中,即输出到屏幕上;第3条语句是一条输入语句,cin表示标准输入流对象(键盘),“>>”是提取符,用来将用户键入的内容保存到后面的变量r中;“return0;”之前的最后一条语句是采用多个“<<”将字符串和变量ar

ea的内容输出到屏幕中,后面的“\n”是换行符,即在内容输出后回车换行。C++代码结构3.预处理指令#include<iostream>称为预处理指令(即编译之前进行的指令,以后还会讨论)。iostream是C++编译器自带的

文件,称为C++库文件,它定义了标准输入/输出流的相关数据及其操作。由于程序用到了输入/输出流对象cin和cout,因而需要用#include将其合并到程序中。又由于它们总是被放置在源程序文件的起始处,

所以这些文件被称为头文件(HeaderFile)。C++编译器自带了许多这样的头文件,每个头文件都支持一组特定的“功能”,用于实现基本输入输出、数值计算、字符串处理等方面的操作。需要说明的是,为了避免与早期库文件相冲突,C

++引用了“名称空间(namespace)”这个特性,并重新对库文件命名,去掉了早期库文件中的扩展名.h。又由于iostream是C++标准组件库,它所定义的类、函数和变量均放入名称空间std中,因此需要

在程序文件的开始位置处指定“usingnamespacestd;”,以便能被后面的程序所使用。事实上,cin和cout就是std中已定义的流对象,若不使用“usingnamespacestd;”,还应在调用

时通过域作用运算符“::”来指定它所属的名称空间,即如下述格式来使用:std::cout<<"输入圆的半径:";//::是域作用运算符,表示cout是std域中的对象std::cin>>r;C++代码结构4.注释在C++中,“

/*...*/”之间的内容称为块注释,它可以出现在程序中的任何位置,包括在语句或表达式之间。而“//”只能实现单行的注释,它是将“//”开始一直到行尾的内容作为注释,称为行注释。注释的目的只是为了提高程序的可读性,对编

译和运行并不起作用。正是因为这一点,所注释的内容既可以用汉字来表示(如Ex_Simple1、Ex_Simple2中的注释),也可以用英文来说明,只要便于理解就行。5.缩进缩进是指程序在书写时不要将程序的每一行都由第一列开始,而是在适当的地方加进

一些空格,和注释一样,也是为了提高程序的可读性。通常,在书写代码时,每个“}”花括号占一行,并与使用花括号的语句对齐。花括号内的语句采用缩进书写格式,缩进量为4个字符(一个默认的制表符)。除缩进外,程序代码还应注意对齐和分段(块)。所谓对齐,即同一层次的语句需从同一列开始,同一层次的左右

花括号分开时应在同一列上。而分段(块)是指将程序代码根据其作用、功能和属性分成几个段落或几个块,段落或块之间添加一个或多个空行。VisualC++实用教程(VisualStudio版)(第6版)第1章基本C++语言——数

据类型和基本输入/输出目录01基本数据类型基本数据类型为了能精确表征数据在计算机内存中的存储(格式及大小)和操作,C++将数据类型分为基本数据类型、派生类型和复合类型三类,后两种类型又可统称为构造类型,如图1.8所示。基本数据类型C++基本数据类型有int(整型)、float(单精度实型)、

double(双精度实型)、char(字符型)和bool(布尔型,值为false或true,而false用0表示,true用1表示)等。对于上述基本数据类型,还可以使用short(短型)、long(长型)、signed(有符号)和un

signed(无符号)来区分,以便更准确地适应各种情况的需要。表1.1列出了C++各种基本数据的类型、字宽(以字节数为单位)和范围,它们是根据ANSI标准而定的。类型名类型描述字宽范围bool布尔型1false(0)或true(1)ch

ar单字符型1-128~127unsignedchar无符号字符型10~255(0xff)signedchar有符号字符型1-128~127wchar_t宽字符型2视系统而定short[int]短整型2-32768~3

2767unsignedshort[int]无符号短整型20~65535(0xffff)signedshort[int]有符号短整型(与shortint相同)2-32768~32767int整型4-2147483648~2147483647unsigned[int]无符号整型40~42949672

95(0xffffffff)signed[int]有符号整型(与int相同)4-2147483648~2147483647long[int]长整型4-2147483648~2147483647unsignedlon

g[int]无符号长整型40~4294967295(0xffffffff)signedlong[int]有符号长整型(与longint相同)4-2147483648~2147483647float单精度实型47位有效位double双精度实型815位有效位longdouble长双精度实型1019

位有效位,视系统而定目录02字面常量1.整数常量2.实数常量3.字符常量4.字符串常量*字面常量1.整数常量C++中的整数可用十进制、八进制和十六进制来表示。其中,八进制整数是以数字0开头且由0~7的数字组成的数。如045,即(45)8,表示八进制数45,等于十进制数37;-023表示八进制数-2

3,等于十进制数-19。而十六进制整数是以0x或0X开头且由0~9、A~F或a~f组成的数。如0x7B,即(7B)16,等于十进制的123,-0X1a等于十进制的-26。需要说明的是,整数后面还可以有后缀l

、L、u、U等。2.实数常量实数即浮点数,它有十进制数和指数两种表示形式。十进制数形式是由整数部分和小数部分组成的(注意必须有小数点)。例如0.12、.12、1.2、12.0、12.、0.0都是合法的十进制数形式实数。指数形式采用科学表示法,它能表示出很大或很小的实数。例如1.2e9或1.

2E9都表示1.2×109,注意字母E(或e)前必须有数字,且E(或e)后面的指数必须是整数。需要说明的是,若实数是以F(或f)结尾的,如1.2f,则表示单精度浮点数(float),以L(或小写字母l)结尾的,如1.2L,表示长双精度浮点数(longdouble)。字面常量

3.字符常量在C++中,用单引号将其括起来的字符称为字符常量。如‘B’、‘b’、‘%’、‘’等都是合法的字符,但若只有一对单引号‘’则是不合法的,因为C++不支持空字符常量。注意‘B’和‘b’是两个不同的字符。除了上述形式的字符常量外,C++还可以用“\”开头的字符序列来表示

特殊形式的字符。例如在以前程序中的‘\n’,它代表回车换行,即相当于按【Enter】键,而不是表示字母n。这种将反斜杠(\)后面的字符转换成另外意义的方法称为转义序列表示法。‘\n’称为转义字符,“\

”称为转义字符引导符,单独使用没有任何意义,因此若要表示反斜杠字符,则应为‘\\’。表1.2列出了常见的转义序列符。字符形式含义ASCII码值\a响铃(BEL)07H\b退格(相当于按Backspace键)(BS)08H\n换行(相当于

按Enter键)(CR、LF)0DH、0AH\r回车(CR)0DH\t水平制表(相当于按Tab键)(HT)09H\v垂直制表(仅对打印机有效)(VT)0BH\'单引号27H\"双引号22H\\反斜杠5CH\?问号3FH\ooo用1位、2位或3

位八制数表示的字符(ooo)8\xhh用1位或多位十六制数表示的字符hhH字面常量4.字符串常量*C++语言除了允许使用字符常量外,还允许使用字符串常量。字符串常量是由一对双引号括起来的字符序列,简称为字符串。字符串常量中除一般字符外,还可以包含空格、转义序列

符或其他字符(如汉字)等。例如:"Hello,World!\n""C++语言"都是合法的字符串常量。字符串常量的字符个数称为字符串长度。若只有一对双引号“”,则这样的字符串常量的长度为0,称为空字符串

。由于双引号是字符串的分界符,因此如果需要在字符串中出现双引号则必须用“\"”表示。例如:"Pleasepress\"F1\"tohelp!"这个字符串被解释为:Pleasepress"F1"tohelp!字符

串常量应尽量在同一行书写,若一行写不下,可用“\”来连接,例如:"ABCD\EFGHIJK…"字面常量注意不要将字符常量和字符串常量混淆不清,它们主要的区别如下:(1)字符常量是用单引号括起来的,仅占1个字节;而

字符串常量是用双引号括起来的,至少需要2字节,但空字符串除外,它只需1个字节。例如,字符串“a”的字符个数为1,即长度为1,但它所需要的字节大小不是1而是2,因为除了字符a需要1个字节外,字符串结束符‘\0’还需1个字节。如图1.9所示。(2)内存中,字符是以ASCII

码值来存储的,因此可将字符看作整型常量的特殊形式,它可以参与常用的算术运算,而字符串常量则不能。例如:intb='a'+3;//结果b为100,这是因为让'a'的ASCII码值97参与了运算目录03变量及其命名规则1.变量名命名2.变量定义3.变量赋值和初

始化变量及其命名规则1.变量名命名变量名需用标识符来标识。所谓标识符,是用来标识变量名、函数名、数组名、类名、对象名等的有效字符序列。标识符命名的好坏直接影响程序的可读性,下面几个原则是命名时所必须注意的。(1)合法性。C++规定标识符由大小写字母、数字字

符(0~9)和下划线组成,且第一个字符必须为字母或下划线。任何标识符中都不能有空格、标点符号及其他字符,例如下面的标识符是不合法的:93Salary,Peter.Ding,$178,#5f68,r<d而且,用户定义的标识符不能和系统关键字同名。以下是63个

ANSI/ISOC++标准关键字:asmautoboolbreakcasecatchcharclassconstconst_castcontinuedefaultdeletedodoubledynamic_ca

stelseenumexplicitexportexternfalsefloatforfriendgotoifinlineintlongmutablenamespacenewoperatorprivateprote

ctedpublicregisterreinterpret_castreturnshortsignedsizeofstaticstatic_caststructswitchtemplatethisthrowtr

uetrytypedeftypeidtypenameunionunsignedusingvirtualvoidvolatilewchar_twhile需要说明的是,程序中定义的标识符除了不能与关键字同名外,还不能与系统库文件中预定义的标

识符同名,如以前遇到的cin、cout等。变量及其命名规则(2)有效性。因为有的编译器只能识别前32个字符,也就是说前32个字符相同的两个不同标识符被有的系统认为是同一个标识符。因此,虽然标识符的长度(组成标识

符的字符个数)是任意的,但最好不能超过32个。(3)易读性。在定义标识符时,若能做到“见名知意”就可以达到易读性的目的。实际上,许多程序员还采用“匈牙利标记法”来定义标识符(见附录D),这种方法是在每个变量名前面加上表示数

据类型的小写字符,变量名中每个单词的首字母均大写。例如,用nWidth或iWidth(宽度)表示整型(int)变量。变量及其命名规则2.变量定义C++中,定义变量的最简单的方法是先写数据类型,然后是变量名,数据类型和

变量名之间必须用1个或多个空格来分隔,最后以分号来结尾,即如下列格式的语句:<数据类型><变量名1>[,<变量名2>,…];数据类型是告诉编译器要为由变量名指定的变量分配多少字节的内存空间,以及变量中要存取的是什么类型的数据

。例如:doublex;//双精度实型变量这样,x占用了8个字节连续的内存空间,存取的数据类型是double型,称为双精度实型变量。再如:floaty;//单精度实型变量则y占用了4个字节连续的内存空间,存取的数据类型是float型,称为单精度实型变量。此后,变量x

、y就分别对应于各自的内存空间,换句话说,开辟的那块8字节的内存空间就叫x,那块4字节的内存空间就叫y。又如:intnNum1;//整型变量intnNum2;//整型变量intnNum3;//整型变量变量及其命名规则则nNum1、nNum2、nNum3分别占用4个字节的内存空间,其存取的

数据类型是int型,称为整型变量。由于它们都是同一类型的变量,因此为了使代码简洁,可将同类型的变量定义在一行语句中,不过同类型的变量名要用逗号(,)分隔(逗号前后可以有0个或多个空格)。例如上述三个整型变量可这样定义(注意,只有最后一个变量nNum

3的后面才有分号):intnNum1,nNum2,nNum3;需要说明的是,除了上述整型变量、实型变量外,还可有字符型变量,即用char定义的变量。这些都是最基本的数据类型变量。实际上,只要是合法的C++数据类型,均可以用来定义变量。例如:unsign

edshortx,y,z;//无符号短整型变量longdoublepi;//长双精度实型变量在C++中没有基本数据类型的字符串变量。字符串变量是用字符类型的数组、指针或string类来定义的(以后会讨论)。变量及其命名规则在同一个作用域(以后会讨

论)中,不能对同一个变量重新定义。或者说,在同一个作用域中,不能有两个或两个以上的变量名相同。例如:floatx,y,z;//单精度实型变量intx;//错误,变量x重复定义floaty;//错误,变量y重复定义C++变量满足

即用即定义的编程习惯,也就是说,变量定义的位置可以不固定,比较自由,但一定要遵循先定义后使用的原则。例如:intx;//即用即定义x=8;inty;cout<<z<<endl;//错误,z还没有定义变量及其命名规则3

.变量赋值和初始化变量一旦定义后,就可以通过变量名来引用变量进行赋值等操作。所谓引用变量,就是使用变量名对其内存空间进行操作。例如:intx,y;x=8;//给x赋值y=x;//将x的值赋给y“x=8;”和“y=x;”都是变量的赋值操作,“=”是赋值运算符(

以后还会讨论)。由于变量名x和y标识它们的内存空间,因此,“x=8;”是将“=”右边的数据8存储到左边变量x的内存空间中。而“y=x;”这个操作则包括两个过程:先获取x的内存空间中存储的值(此时为8),然后将该值存储到y的内存空间中。变量及其命名规则

当首次引用一个变量时,变量必须有一个确定的值,这个值就是变量的初值。在C++中,可用下列形式或方法给变量赋初值。(1)在变量定义后,使用赋值语句来赋初值。如前面的“x=8;”和“y=x;”,使x和y的初值都设为8。(2)在变量定义

的同时赋给变量初值,这个过程称为变量初始化。例如:intnNum1=3;//指定nNum1为整型变量,初值为3doublex=1.28;//指定x为双精度实变量,初值为1.28charc='G';//指定c为字符变量,初值为'G'(3)也可以在多个变量的定义语句中单独对某个变量进行初

始化,如:intnNum1,nNum2=3,nNum3;表示nNum1、nNum2、nNum3为整型变量,但只有nNum2的初值为3。(4)在C++中,变量的初始化还有另外一种形式,例如:intnX(1),n

Y(3),nZ;表示nX、nY和nZ都是整型变量,其中紧随nX和nY后面的括号中的数值1和3分别为nX和nY的初值。目录04标识符常量和枚举1.const只读变量2.枚举常量标识符常量和枚举与变量相似,标识

符常量在使用前同样需要先作声明(所谓声明,就是告诉编译器这个标识符要被使用,声明不同于定义,由于声明时不会分配任何内存空间,所以声明可以多次。而定义不同,它是要分配内存空间的,只能定义一次)。在C++中,标识符常量

可以有const修饰的只读变量、enum类型的枚举常量及#define定义的常量3种形式。这里先介绍前面两种。1.const只读变量在变量定义时,可以使用关键字const来修饰,这样的变量是只读的,即在

程序中对其只能读取不能修改。由于不可修改,因而它是一个标识符常量,且在定义时必须初始化。需要说明的是,通常将标识符常量中的标识符写成大写字母以与其他标识符相区别。例如:constfloatPI=3.14159265f;//

指定后缀f使其类型相同,否则会有警告错误因π字符不能作为C++的标识符,因此这里用PI来表示。PI被定义成一个float类型的只读变量,由于float变量只能存储7位有效位精度的实数,因此PI的实际值为3.141592

。若将PI定义成double,则全部接受上述数字。事实上,const还可放在类型名之后(它们的区别以后会讨论),如下列语句:doubleconstPI=3.14159265;标识符常量和枚举【例Ex_PI】用const定义标识符常量#includ

e<iostream>usingnamespacestd;constdoublePI=3.14159265;//PI是一个只读变量intmain(){doubler=100.0,area;area=PI*r*r

;//引用PIcout<<"圆的面积是:"<<area<<"\n";return0;//指定返回值}程序运行结果如下:圆的面积是:31415.9需要说明的是,由于const标识符常量的值不能修改,因此下列语句是错误的

:constfloatPI;//此时PI的值无法确定PI=3.14159265;//错误:只读变量不能放在赋值运算符的左边标识符常量和枚举2.枚举常量枚举常量是在由关键字enum指定的枚举类型中定义的。枚举类型属于构造类型,它是一系列有标识符的整型常量的集合,因此每一个枚举常量实质上就是一个整

型标识符常量。定义时,先写关键字enum,然后是要定义的枚举类型名、一对花括号({}),最后以分号结尾。enum和类型名之间至少要有一个空格,花括号里面是指定的各个枚举常量名,各枚举常量名之间要用逗号分隔。即如

下列格式:enum<枚举类型名>{<枚举常量1,枚举常量2,…>};例如:enumCOLORS{Black,Red,Green,Blue,White};其中COLORS是要定义的枚举类型名,通常将枚举类型名写成大

写字母以与其他标识符相区别。它有5个枚举常量(又称为枚举值、枚举元素),系统默认为每一个枚举常量对应一个整数,并从0开始,逐个增1,也就是说枚举常量Black等于0,Red等于1,Green等于2,以此类推。标识符常量和枚举当然,这些枚举常量默认的值

可单独重新指定,也可部分指定,例如:enumCOLORS{Black=5,Red,Green=3,Blue,White=7};由于Red没有赋值,则其值自动为前一个枚举常量值增1,即为6。同样,Blue为4,这样各枚举常量的值依次为5,6,3,4,7。以后就可直接使用这些枚举常量了

,例如:intn=Red;//n的初值为6cout<<Blue+White<<endl;//输出11事实上,在枚举定义时可不指定枚举类型名。例如:enum{Black=5,Red,Green=3,Blue,White=

7};显然,用enum一次可以定义多个标识符常量,不像const和#define每次只能定义一个。又如,若在程序中使用TRUE表示true,FALSE表示false,则可定义为:enum{FALSE,TRUE};//或enum{TRUE=true,FALSE=false};目录

05基本输入/输出1.输入流(cin)2.输出流(cout)3.使用格式算子oct、dec和hex基本输入/输出1.输入流(cin)cin可以获得多个键盘的输入值,它具有下列格式:cin>><变量1>[>><变量2>…];其中,提取

运算符“>>”可以连续写多个,每个提取运算符后面跟一个获得输入值的变量。例如:intnNum1,nNum2,nNum3;cin>>nNum1>>nNum2>>nNum3;要求从键盘上输入三个整数。输入时,必须在3个数值之间加上一些空格来分隔,空格个数不限,最后用回车键结束输入;或者在每

个数值之后按回车键。例如,上述输入语句执行时,可以输入:12␣9␣20或12920基本输入/输出此后变量nNum1、nNum2和nNum3的值分别为12、9和20。需要说明的是,提取运算符“>>”能自动将cin输入值转换成相应变量的数据类型,但从键盘输入数据的个数、数据类型及顺序,

必须与cin中列举的变量一一匹配。如:charc;inti;floatf;longl;cin>>c>>i>>f>>l;上述语句运行后,若输入:1␣2␣9␣20则变量c等于字符‘1’,i等于2,f等于9.0

f,l等于20L。要注意输入字符时,不能像字符常量那样输入‘1’,而是直接输入字符,否则不会有正确的结果。例如,当输入:'1'␣2␣9␣20由于c是字符型变量,占一个字节,故无论输入的字符后面是否有空格,c

总是等于输入的第1个字符,即为一个单引号。此后,i就等于“1'”,由于i需要输入的是一个整数,而此时的输入值有一个单引号,因而产生错误,但单引号前面有一个“1”,于是就将1提取给i,故i的值为1。一旦产生错误,输入语句运行中断,后

面的输入就变为无效,因此f和l都不会有正确的值。基本输入/输出2.输出流(cout)与cin相对应,通过cout可以输出一个整数、实数、字符及字符串等,如下列格式:cout<<<对象1>[<<<对象2>...];cout中的插入运算符“<

<”可以连续写多个,每个后面可以跟一个要输出的常量、变量、转义序列符及表达式等,例如:【例Ex_Cout】cout的输出及endl算子#include<iostream>usingnamespacestd;intmain(){cout<<"ABCD

\t"<<1234<<"\t"<<endl;return0;//指定返回值}执行该程序,结果如下:ABCD1234程序中,转义字符‘\t’是制表符,endl是C++中控制输出流的一个操作算子(预定义对象),它的作用和‘\n’等

价,都是结束当前行并另起一行。基本输入/输出3.使用格式算子oct、dec和hex格式算子oct、dec和hex能分别将输入或输出的整数转换成八进制、十进制及十六进制。【例Ex_ODH】格式算子的使用#include<io

stream>usingnamespacestd;intmain(){intnNum;cout<<"PleaseinputaHexinteger:";cin>>hex>>nNum;cout<<"Oct\t"<<oct<<nNum<<endl;cout<<"Dec\t"<<dec<<nNum<<e

ndl;cout<<"Hex\t"<<hex<<nNum<<endl;return0;}程序运行后,其结果如下:PleaseinputaHexinteger:7bOct173Dec123Hex7bVisualC++实用教程(VisualStudio版)(第6版)第1章基本C++语言——运算

符和表达式目录01算术运算符算术运算符由操作数和算术运算符构成的算术表达式常用于数值运算,与数学中的代数表达式相对应。C++算术运算符有双目的加减乘除四则运算符、求余运算符及单目的正负运算符,如下所示:+正号运算符,如+4,+1.22等-负号运算符,如-4,-1.22

等*乘法运算符,如6*8,1.4*3.56等/除法运算符,如6/8,1.4/3.56等%模运算符或求余运算符,如40%11等+加法运算符,如6+8,1.4+3.56等-减法运算符,如6-8,1.4-3.56等在算术表达式

中,C++算术运算符和数学运算的概念及运算方法是一致的,但要注意以下几点。(1)除法运算。两个整数相除,结果为整数,如7/5的结果为1,它是将小数部分去掉,而不是四舍五入。若除数和被除数中有一个是实数,则进行实数除法,

结果是实型。如7/5.0、7.0/5、7.0/5.0的结果都是1.4。(2)求余运算。求余运算要求参与运算的两个操作数都是整型,其结果是两个数相除的余数。例如40%5的结果是0,40%11的结果是7。要理解负值的求余

运算,例如40%-11的结果是7,-40%11的结果是-7,-40%-11的结果也是-7。算术运算符(3)优先级和结合性。在算术表达式中,先乘、除后加、减的运算规则是由运算符的优先级来保证的。其中,单目的正负运算符的优先级最高,其次是乘、除和求余,最后是加、减。优先级相同的

运算符,则按它们的结合性进行处理。所谓运算符的结合性是指运算符和操作数的结合方式,它有“从左至右”和“从右至左”两种。“从左至右”的结合是指运算符左边的操作数先与运算符相结合,再与运算符右边的操作数进行运算;而“自右至左”的结合次序刚好

相反,它是将运算符右边的操作数先与运算符相结合。在算术运算符中,除单目运算符外,其余运算符的结合性都是从左至右。要注意,只有当两个同级运算符共用一个操作数时,结合性才会起作用。例如2*3+4*5,则2*3和

4*5不会按其结合性来运算,究竟是先计算2*3还是4*5由编译器来决定。若有2*3*4,则因为两个“*”运算符共用一个操作数3,因此按其结合性来运算,即先计算2*3,然后再与4进行“*”运算。算术运算符(4)关于书写格式。在使用运算符进行数值运算时,往往要在双目运算符的两边

加上一些空格,否则编译器会做出与自己理解完全不同的结果。例如:-5*-6--7和-5␣*␣-6␣-␣-7//注意空格结果是不一样的。前者发生编译错误,而后果的结果是37。但对于单目运算符来说,虽然也可以与操作数之间存在空格,但最好与操

作数写在一起。目录02赋值运算符1.左值和右值2.数值截取和数值溢出3.复合赋值4.多重赋值赋值运算符1.左值和右值赋值运算符“=”的结合性从右到左,其作用是将赋值符右边操作数的值存储到左边的操作数所在的内存空间中,显然,左边的操作数应是一个左值。所谓左值(L-Value,L是Le

ft的首字母),即出现在赋值运算符左边(Left)的操作数,但它还必须满足两个条件:一是必须对应于一块内存空间,二是所对应的内存空间中的内容必须可以改变,也就是说左值的值必须可以改变。2.数值截取和数值溢出每一个合法的表达式在求值后都有一个确定的值和类型。对于赋值表达式来说,其值和类型就是

左值的值和类型。例如:floatfTemp;fTemp=18;//fTemp是左值,整数18是右值对实型变量fTemp的赋值表达式“fTemp=18”完成后,该赋值表达式的类型是左值fTemp的类型float,表达式的值经类

型自动转换后变成18.0f,即左值fTemp的值和类型。显然,在赋值表达式中,当右值的数据类型低于左值的数据类型时,C++会自动进行数据类型的转换。但若右值的数据类型高于左值的数据类型,且不超过左值的范围时,则C++会自动进行数值截取。例如,若有“fTemp=18.0”,因为常量18

.0默认时是double型,高于fTemp指定的float型,但18.0没有超出float型数值范围。因而此时编译后,会出现警告,但不会影响fTemp结果的正确性。赋值运算符但如果一个数值超出一个数据类型所表示的

数据范围时,则会出现数值溢出。数值溢出的一个典型的特例是当某数除以0,这种严重情况编译器将报告错误并终止程序运行。而超出一个数据类型所表示的数据范围的溢出在编译时往往不会显示错误信息,也不会引起程序终止,因此在编程时需要特别小心。【例Ex_OverFlow】一个整数溢出的例子#inclu

de<iostream>usingnamespacestd;intmain(){shortnTotal,nNum1,nNum2;nNum1=nNum2=1000;nTotal=nNum1*nNum2;cout<<nTotal<<"\n";return0;}程序运行后,输出nTotal的

计算结果16960。赋值运算符3.复合赋值在C++中,规定了下列10种复合赋值运算符:+=加赋值&=位与赋值-=减赋值|=位或赋值*=乘赋值^=位异或赋值/=除赋值<<=左移位赋值%=求余赋值>>=右移位赋值它们都是在赋值符“=”之前加上其他运算符而构成的

,其中算术复合赋值运算符的含义如表1.3所示,其他复合赋值运算符的含义均与其相似。运算符含义例子等效表示+=加赋值a+=ba=a+b-=减赋值a-=ba=a-b*=乘赋值a*=ba=a*b/=除赋值a/=ba=a/b%=求余赋值nNum%=8n

Num=nNum%8赋值运算符尽管复合赋值运算符看起来有些古怪,但它却能简化代码,使程序精练,更主要的是在编译时能产生高效的执行代码。需要说明的是,在复合赋值运算符之间不能有空格,例如+=不能写成+=,否则编译时将提示出错信息。复合赋值运算符的优先级

和赋值符“=”的优先级一样,在C++的所有运算符中只高于逗号运算符,而且复合赋值运算符的结合性也和赋值符“=”一样,也是从右至左。因此,在组成复杂的表达式时要特别小心。例如:a*=b-4/c+d等效于a=a*(b-4/c+d)而不等效于a=a*b-4/c+d赋

值运算符4.多重赋值所谓多重赋值是指在一个赋值表达式中出现两个或更多的赋值符“=”,例如:nNum1=nNum2=nNum3=100//若结尾有分号“;”,则表示是一条语句由于赋值符的结合性是从右至左的,因此上述的赋值是这样的过程:首先对赋值表达式nNum3=100求值,即将100赋值

给nNum3,同时该赋值表达式的结果是其左值nNum3,值为100。然后将nNum3的值赋给nNum2,这是第二个赋值表达式,该赋值表达式的结果是其左值nNum2,值也为100。最后将nNum2的值赋给nNum1,整个表达式的

结果是左值nNum1。由于赋值是一个表达式,因而几乎可以出现在程序的任何地方,由于赋值运算符的等级较低,因此这时的赋值表达式两边应加上圆括号。例如:a=7+(b=8)//赋值表达式值为15,a值为15,b值为8a=(c=7)+(b=8)//赋值表达式值为15,a值为15,c值为

7,b值为8(a=6)=(c=7)+(b=8)//赋值表达式值为15,a值为15,c值为7,b值为8要注意上面最后一个表达式的运算次序:由于圆括号运算符的优先级在该表达式中是最高的,因此先运算(a=6)、(c=7)和(b=8),究竟这3个表达式谁先运算,取决于编译器。由于

这三个表达式都是赋值表达式,其结果分别为它们的左值a、c和b,因此整个表达式等效于a=c+b,结果为a=15、b=8、c=7,整个表达式的结果是左值a。需要说明的是,当赋值表达式出现在cout中时,需将赋值表达式两边加上圆括号。例如:cout<<(a=6

)<<endl;//输出结果为6cout<<(a=6)+(b=5)<<endl;//输出结果为11目录03数据类型转换1.自动转换2.强制转换数据类型转换1.自动转换自动转换是将数据类型按从低到高的顺序自动进行转换

,如图1.10所示,箭头的方向表示转换的方向。由于这种转换不会丢失有效的数据位,因而是安全的。例如,10+'a'+2*1.25-5.0/4L的运算次序如下:(1)进行2*1.25的运算,将2和1.25都转换成double型,结果为double型的2.5。(2)进行5.0/4L

的运算,将长整型4L和5.0都转换成double型,结果值为1.25。(3)进行10+'a'的运算,先将'a'转换成int型整数97,运算结果为107。(4)整数107和2.5相加,先将整数107转换成double型,结果为double型,值为109.5。(5

)进行109.5-1.25的运算,结果为double型的108.25。数据类型转换2.强制转换强制转换是在程序中通过指定数据类型来改变如图1.10所示的类型转换顺序,将一个变量从其定义的类型改变成为另一种不同的类型。由于这种转换可能会丢失有效的数据位,因而是不安全的。在强制转

换操作时,C++有下列两种基本格式:(<类型名>)<表达式><类型名>(<表达式>)这里的类型名是任何合法的C++数据类型,如float、int等。通过类型的强制转换可以将表达式(含常量、变量等)转换成类型名指定的类型,如:do

ublef=3.56;intnNum;nNum=(int)f;//强制使double转换成int,小数部分被截去或者nNum=int(f);//或者nNum=(int)(f);都是将nNum的值变为3。目录04关系运算符关系运算符关系运算是逻辑运算中比较简单的一种。所谓关系运算实际上是比较两

个操作数是否符合给定的条件。在C++中,若符合条件(“真”)或为非0,则关系表达式值为bool型的true,否则条件为“假”或为0时,则为bool型的false。由于关系运算需要两个操作数,所以关系运算符都是双目运算符,其结合性是从左至右。C++提供

了下列6种关系运算符:<小于,若表达式e1<e2成立,则结果为true,否则为false<=小于等于,若表达式e1<=e2成立,则结果为true,否则为false>大于,若表达式e1>e2成立,则结果为true,否则为

false>=大于等于,若表达式e1>=e2成立,则结果为true,否则为false==相等于,若表达式e1==e2成立,则结果为true,否则为false!=不等于,若表达式e1!=e2成立,则结果为

true,否则为false其中,前4种的优先级相同且高于后面的2种。例如,若有表达式:a==b>c则等效于a==(b>c)。若设整型变量a=3、b=4、c=5,则表达式中,先运算b>c,结果该条件不满足,值为false(以0表示),然后再运算a==0,显

然也为false,故整个表达式的值是false。需要注意的是,关系运算符“==”不要误写成赋值运算符“=”。为了避免这种情况发生,作为技巧,若操作数有常量,则应将常量写在“==”的左边。如“3==a”,这样即使

不小心写成“3=a”,由于3不能作为左值,因此编译时会检测出它的语法错误。目录05逻辑运算符逻辑运算符逻辑运算符用于将多个关系表达式或逻辑量(true或false)组成一个逻辑表达式。同样,逻辑表达式的结果也是bool型,要么为tru

e,要么为false。C++提供了下列3种逻辑运算符:!逻辑非(单目)&&逻辑与(双目)||逻辑或(双目)逻辑非“!”是指将操作数的值为true时变成false,为false时变成true。逻辑与“&&”是指当两个操作数都是

true时,结果才为true,否则为false。逻辑或“||”是指当两个操作数中有一个是true时,结果就为true,而只有当它们都为false时,结果才为false。“逻辑非”“逻辑与”和“逻辑或”的优先级依次从高到低,且“逻辑非”的优

先级还比算术运算符和关系运算符高,而“逻辑与”和“逻辑或”的优先级却比关系运算符要低。逻辑运算符需要说明的是,C++对逻辑表达式的运算次序进行了优化。当有e1&&e2时,若表达式e1为false,则表达式e2不会计算,因为无论

e2是何值,整个表达式都为false。类似的,当有e1||e2时,若e1为true,则e2也不会计算,因为无论e2是何值,整个表达式都为true。例如,若inta,b=3,c=0,则在下面的表达式中(a=0)&&(c=a+b);//注意这里的a=0是赋值表达式因(a=0)

的表达式值为0(false),故(c=a+b)不会被执行。这样,a、b和c的值分别为0、3、0。若有(a=2)||(c=a+b);//注意这里的a=2是赋值表达式因(a=2)的表达式值为2(true),故(c

=a+b)也不会被执行(注意此时的逻辑符为“或”)。目录06位运算符位运算符位运算符是对操作数按其在计算机内表示的二进制数逐位地进行逻辑运算或移位运算,参与运算的操作数只能是整型常量或整型变量。C++语言提供了6种位运算符:~按位求反(单目)&按位与(双目)^按位异或(双目)

|按位或(双目)<<左移(双目)>>右移(双目)按位求反“~”是将一个二进制数的每一位求反,0变成1,1变成0。按位与“&”是将两操作数对应的每个二进制位分别进行逻辑与操作。按位异或“^”是将两操作数对应的每个二进制位分别进行异或操作,相同为0,不同为1。按位或“|”是将两操作数对应的每个二进

制位分别进行逻辑或操作。位运算符操作数<<移位的位数左移后,低位补0,移出的高位舍弃。例如:表达式4<<2的结果是16(二进制为00010000),其中4是操作数,二进制为00000100,2是左移的位数。右移“>>”(两个>符号连写)是将左操作数的二进制值向右移动指定的位

数,它的操作格式与“左移”相似,即具有下列格式:操作数>>移位的位数左移“<<”(两个<符号连写)是将左操作数的二进制值向左移动指定的位数,它具有下列格式:右移后,移出的低位舍弃。如果是无符号数则高位补0;如果

是有符号数,则高位补符号位(补1)或补0,不同的编译器对此有不同的处理方法,VisualC++6.0采用的是补符号位(补1)的方法。目录07条件运算符条件运算符条件运算符“?:”是C++中唯一的一个三目运

算符,它具有下列格式:<e1>?<e2>:<e3>其中,表达式e1是C++中可以产生true和false结果的任何表达式。其功能是:如果表达式e1的结果为true,则执行表达式e2,否则执行表达式e3

。例如:nNum=(a>b)?10:8;当(a>b)为true时,则表达式(a>b)?10:8的结果为10,从而nNum=10;否则(a>b)?10:8的结果为8,nNum=8。需要说明的是,由于条件运算

符“?:”的优先级比较低,仅高于赋值运算符,因此“nNum=(a>b)?10:8”中的条件表达式“(a>b)”两边可以不加圆括号。即可写成:nNum=a>b?10:8;目录08sizeof运算符sizeof运算符si

zeof的目的是返回操作数所占的内存空间大小(字节数),它具有下列两种格式:sizeof(<表达式>)sizeof(<数据类型>)例如:sizeof("Hello")//计算"Hello"所占内存的字节大小,结果为6sizeof(int)//计算整型int所占内存的字节数需要

说明的是,由于同一类型的操作数在不同的计算机中占用的存储字节数可能不同,因此sizeof的结果有可能不一样。例如sizeof(int)的值可能是4,也可能是2。目录09逗号运算符逗号运算符逗号运算符“,”是优先级最低的运算符,它用于把多个表达式连接起来,构成一个逗号表达式。逗号表达式的一

般形式为:表达式1,表达式2,表达式3,…,表达式n在计算时,C++将从左至右逐个计算每个表达式,最终整个表达式的结果是最后计算的那个表达式的类型和值,即表达式n的类型和值。例如:a=1,b=a+2,c=b+3该表达式依次从左至右计算,最终的类型和值为最后一个表达

式“c=b+3”的类型和值,结果为左值c(c值为6)。要注意逗号运算符“,”的优先级是最低的,必要时要注意加上圆括号,以使逗号表达式的运算次序先于其他表达式。例如:j=(i=12,i+8)则整个表达式可解释为一个赋值表达式。圆括号中,i=12,i+8是逗号表达式,计算

次序是先计算表达式i=12,然后再计算i+8。整个表达式的类型和值是j的类型和值(为20)。若不加上圆括号,则含义完全不一样。试比较:j=i=12,i+8目录10自增和自减自增和自减单目运算符自增(++)和自减(--)为变量左值加1或减1

提供一种非常有效的方法。++和自减--既可放在左值的左边也可以出现在左值的右边,分别称为前缀运算符和后缀运算符。这里的左值可以是变量或结果为左值的表达式等,但不能是常量或其他右值。例如:inti=5;i++;//合法:后缀自增,等效于i=i+1

;或i+=1;++i;//合法:前缀自增,等效于i=i+1;或i+=1;i--;//合法:后缀自减,等效于i=i-1;或i-=1;--i;//合法:前缀自减,等效于i=i-1;或i-=1;5++;或++5;//错误:5是常量,不能作左值(i+1)++;或++(i+1);//错误:i

+1是一个右值表达式floatf1,f2=3.0f;f1=f2++;//合法:f1的值为3.0f,f2的值为4.0f(f1=5.0f)++;//合法:f1=5.0f表达式的结果是f1,可作为左值要注意前缀和后缀自增自减运算符

含义的不同。若前缀运算符和后缀运算符仅用于某个变量的增1和减1,则这两者是等价的。例如,若a的初值为5,a++和++a都是使a变成6。但如果将这两个运算符和其他的运算符组合在一起,在求值次序上就会产生根本

的不同。自增和自减如果用前缀运算符对一个变量增1(减1),则在将该变量增1(减1)后,用新的值在表达式中进行其他的运算。如果用后缀运算符对一个变量增1(减1),则用该变量的原值在表达式进行其他的运

算后,再将该变量增1(减1)。例如:a=5;b=++a;//A:相当于a=a+1;b=a;和a=5;b=a++;//B:相当于b=a;a=a+1;运行后,a值的结果都是6,但b的结果却不一样,前者(A)为6,后者(B)为5。自增和自减还需说明的是:(1)前缀自增自减表达式的结果仍为一个左值,

而后缀自增自减表达式的结果不是左值。例如:inta=3;(++a)++;//A:合法++a++;//B:错误++(++a);//C:合法a++++;//D:错误++++a;//E:合法在ANSI/ISOC++中,由于后

缀自增自减的运算符优先级比前缀的要高,因此++a++等效于++(a++)。在C++中,对于等级相同的单目运算符来说,哪一个运算符靠近操作数,就跟哪个运算符先结合。即a++++等效于(a++)++,++++a等效于++(++a)。这也是为什么后缀自增自减运算符的结合性是“从左至右”,而前缀自增自

减运算符的结合性是“从右至左”的原因了。A中,++a仍可作为左值,因此(++a)++是合法的。B中,++a++等效于++(a++),由于a++不可以作为左值,所以++a++是不合法的。类似的,可对C、D和E的结果进行分析。自增和自减(2)自增或自减运算符是两个“+”或两个“-”的

一个整体,中间不能有空格。如果有多于两个“+”或两个“-”连写情况,则编译会首先识别自增或自减运算符。例如:inta=1,b=3,c;c=a++b;//A:错误c=a+++b;//B:合法c=a++++b;//C:错误c=a+++++b;//D:错误A

中,编译会将其理解为a++␣b。由于b前面没有运算符,因而会出现错误提示:缺少“;”(在标识符“b”的前面)。B中,编译会将其理解为a++␣+␣b,因此是合法的,结果c为4。C中,编译会将其理解为a++␣++␣b,即为(a++)++␣b。由于a++不能作

为左值,因此会出现错误提示:“++”需要左值。且由于b前面没有运算符,因而还有另一条与A相同的错误提示。D中,编译将其理解为a++␣++␣+␣b,即为(a++)++␣+␣b。由于a++不能作为左值,因此会出现错误提示:“++”需要左值。所以

,在书写这些表达式时,一定要有意识地加上一些空格或圆括号。例如,对于D,若写成:c=a++␣+␣++b;VisualC++实用教程(VisualStudio版)(第6版)第1章基本C++语言——基本语句目录01顺序语句和块1.说明语句2.表达式语句3.块语句顺序语句和块1.说明语

句在C++中,把完成对数据结构的定义和描述、对变量或标识符常量的属性说明(如初值、类型等)称为说明语句或声明语句。说明语句的目的是用来在程序中引入一个新的标识符,本身一般不执行操作。例如:inta=8,b;//变量定义intsum(intx,in

ty)//函数定义,函数的使用以后会讨论{return(x+y);}classCStudent//类声明,以后还会讨论{//…};顺序语句和块2.表达式语句表达式语句是C++程序中最简单也是最常用的语句。任何一个表达式加上分号就是一个表达式语句,例如

:x+y;nNum=5;这里的“x+y;”是一个由算术运算符“+”构成的表达式语句,其作用是完成“x+y”的操作,但由于不保留计算结果,所以无实际意义。“nNum=5;”是一个由赋值运算符“=”构成的表达式语句,简称为赋值语句

,其作用是改变nNum变量的值。在书写格式上,可以将几个简单的表达式语句同时写在一行上,但此时的语句之间必须插入一些空格以提高程序的可读性。例如:a=1;b=2;c=a+b;此时3个赋值语句写在一行,各条语句之间需要增加空格以提高程序的可读性

。顺序语句和块3.块语句块语句简称块(block),是由一对花括号“{}”括起来的,又称为复合语句。例如:{//块开始inti=2,j=3,k=4;cout<<i<<j<<k<<endl;//输出结果是2、3和4}//块结束是由2条语句构成的块语句。其中

,左花括号“{”表示块的开始,右花括号“}”表示块的结束,它们是成对出现的。要注意,块中的语句书写时一定要缩进。目录02选择结构语句1.条件语句2.开关语句选择结构语句1.条件语句条件语句if具有下列一般形式:if(<表达式e>)<语句s1>[else<语句s2>]这里的if、e

lse是C++的关键字。注意,if后的一对圆括号不能省略。当表达式e为true时,将执行语句s1。当表达式e为false,语句s2被执行。其中,else可省略,即变成这样的简单的if语句:if(<表达式e>)<语句s>这样,只有当表达式e为true时,语句s才被执行。选择结构语句【例Ex_

Compare】输入两个整数,比较两者的大小#include<iostream>usingnamespacestd;intmain(){intnNum1,nNum2;cout<<"Pleaseinputtwointegernumbers:";cin>>nNum1>>nNum2;

if(nNum1!=nNum2)if(nNum1>nNum2)cout<<nNum1<<">"<<nNum2<<endl;elsecout<<nNum1<<"<"<<nNum2<<endl;elsecout<<nNum1<<"="<<nNum2

<<endl;return0;}程序运行结果如下:Pleaseinputtwointegernumbers:1012310<123选择结构语句需要说明的是:(1)“表达式e”一般为逻辑表达式或关系表达式,如程序中的“nNum1>nNum2”。

当然,表达式的类型也可以是任意的数值类型(包括整型、实型、字符型等)。例如:if(3)cout<<"Thisisanumber3";执行结果是输出"Thisisanumber3";因为3是一个不为0的数,条件总为true。(2)适当添加花括

号“{}”来增加程序的可读性。例如:例【Ex_Compare】中的if代码还可写成下列形式,其结果是一样的。if(nNum1!=nNum2){if(nNum1>nNum2)cout<<nNum1<<">"<<nNum2<<endl;else

cout<<nNum1<<"<"<<nNum2<<endl;}elsecout<<nNum1<<"="<<nNum2<<endl;选择结构语句(3)若在if、esle后有多条语句(复合语句),则必须用花括号将这些语句括起来,否则只有后面的第一

条语句有效。例如:if(nNum1>nNum2)cout<<nNum1<<">"<<nNum2;//此句才是if后面的有效语句cout<<endl;//此句无论if表达式是否为真都会执行(4)当if中的语句是if语句时,这就形成了if语句的嵌套。例如程序中

if(nNum1!=nNum2)后面的语句也是一条if语句。(5)else不能单独使用,它总是和其前面最近的if相配套。例如,程序中的第1个else属于第2个if(代码中的黑体部分),而第2个else属于第1个if的(代码中的斜体部

分)。选择结构语句2.开关语句当程序有多个条件判断时,若使用if语句则可能使嵌套太多,降低程序的可读性。开关语句switch能很好地解决这种问题,它具有下列形式:switch(<表达式e>){case<常量表达式v1>:[语句s1]case<常量

表达式v2>:[语句s2]...case<常量表达式vn>:[语句sn][default:语句sn+1]}其中switch、case、default都是关键字,当表达式e的值与case中某个常量表达式的值相等时,就执

行该case中“:”号后面的所有语句,直至遇到break语句跳出。若case中所有常量表达式的值都不等于表达式e的值,则执行“default:”后面的语句,若default省略,则跳出switch结构。需要注意的是,switch后面的表达式e可以是整

型、字符型或枚举型的表达式,而case后面的常量表达式的类型则必须与其相一致,且每一个case常量表达式的值必须互不相同(唯一的),否则会出现编译错误。选择结构语句【例Ex_Switch】根据成绩的等级输出相应的分数段#include<iostream>usingnamespacestd

;intmain(){charchGrade;cout<<"Pleaseinputachar(A~E):";cin>>chGrade;switch(chGrade){case'A':case'a':cout<<"90--100"<<endl;break;ca

se'B':case'b':cout<<"80--89"<<endl;break;case'C':case'c':cout<<"70--79"<<endl;case'D':case'd':cout<<"60--69"<<endl;case'E':case'e':c

out<<"<60"<<endl;default:cout<<"error!"<<endl;}return0;}选择结构语句运行时,当输入A,则输出:Pleaseinputachar(A~E):A90--100但当用户输入d时,则结果如下:Pleaseinputachar(

A~E):d60--69<60error!显然,这不是想要的结果,而应该只输出“60--69”。仔细比较这两个结果,可以发现:“case'a':”后面含有break语句,而“case'd':”后面则没有。另外,还需注意的是:(1)多个case可以共有一组执行语句,如程序中的:case'B'

:case'b':cout<<"80--89"<<endl;break;这时,当用户输入B或b时将得到相同的结果。(2)同一个case后面的语句允许有多条,且不需要用花括号“{}”将它们括起来。目录03循环结构语句1.while语

句2.do…while语句3.for语句循环结构语句1.while语句while循环语句具有下列格式:while(<表达式e>)<语句s>其中,while是C++的关键字,语句s是循环体,它可以是一条语句,也可以是多条语句。当为多条语句时,需用花括号“{}”括起来,

使之成为块语句,若不加花括号,则while的循环体s只是紧跟while(e)后面的第1条语句。当表达式e为true时便开始执行while循环体中的语句s,然后反复执行,每次执行都会判断表达式e是否为true,若为fal

se,则终止循环。【例Ex_SumWhile】求整数1~50的和#include<iostream>usingnamespacestd;intmain(){intnNum=1,nTotal=0;while(

nNum<=50){nTotal+=nNum;nNum++;}cout<<"Thesumfrom1to50is:"<<nTotal<<"\n";return0;}程序运行后,结果如下:Thesumfrom1to50is:1275循环结构语句

2.do…while语句do…while循环语句具有下列格式:do<语句s>while(<表达式e>);其中do和while都是C++关键字,语句s是循环体,它可以是一条语句,也可以是块语句。程序从do开始执行,然后执行循环体语句s,当执行到w

hile时,将判断表达式e是否为true,若是,则继续执行循环体语句s,直到下一次表达式e为false时为止。要注意,while后面的表达式e两边的圆括号不能省略,且表达式e后面的分号不能漏掉。【例Ex

_SumDoWhile】求整数1~50的和#include<iostream>usingnamespacestd;intmain(){intnNum=1,nTotal=0;do{nTotal+=nNum;nNum++;}while(nNu

m<=50);cout<<"Thesumfrom1to50is:"<<nTotal<<"\n";return0;}循环结构语句程序运行结果如下:Thesumfrom1to50is:1275从上述例子中可以看出while循环语句和do…while的区别:(1)do…while循环

语句至少执行一次循环体,而while循环语句可能一次都不会执行。(2)从局部来看,while和do…while循环都有“while(表达式e)”。为了区别起见,对于do…while循环来说,无论循环体是单条语句还是多条语句,

习惯上都要用花括号将它们括起来,并将“while(表达式e);”直接写在右花括号“}”的后面。如【例Ex_SumDoWhile】中的格式。循环结构语句3.for语句for循环语句具有下列格式:for([表达式e1];[表达式e2]

;[表达式e3])<语句s>其中for是C++的关键字,语句s是循环体,它可以是一条语句,也可以是块语句。for语句比较独特,其流程如图1.11所示(图中的箭头表示程序运行的方向,称为流向)。图1.11for语句的流程循环结构语句【例Ex_SumFor】求整数1到50的和#incl

ude<iostream>usingnamespacestd;intmain(){intnTotal=0;for(intnNum=1;nNum<=50;nNum++)nTotal+=nNum;cout<<"T

hesumfrom1to50is:"<<nTotal<<"\n";return0;}程序运行结果如下:Thesumfrom1to50is:1275需要说明的是,常将循环相关的一些变量的初始化放在表达式e1中进行,如代码中for语句的“intnNum=1”。但此时nNum的作用

范围仅限于for循环结构中。表达式e1、e2和e3可以是一个简单的表达式,也可以是逗号表达式。例如:for(nNum=1,nTotal=0;nNum<=50;nNum++)nTotal+=nNum;循环体s中的语句也可以是一条空语句,这样的循环往往用于时间延时。例如:for(inti=0;i<1

0000;i++);//注意后面的分号表示一条空语句循环结构语句实际运用时,for循环还有许多变化的形式,这些形式都是将for后面括号中的表达式e1、e2、e3进行部分或全部省略,但要注意起分隔作用的分号“;”不能省略。常见的省略形式有下列几种。(1)若省略“表达式e1”,不影

响循环体的正确执行,但循环体中所需要的一些变量及其相关的数值要在for语句之前定义。例如:intnNum=1;for(;nNum<=50;nNum++)nTotal+=nNum;(2)若省略“表达式e2”,则循环条件默认为true,循环会一直进行下去,因此应在循环体中添加额外代

码使之有跳出或终止循环的可能。例如:for(intnNum=1;;nNum++){nTotal+=nNum;if(nNum>50)break;//当nNum>50时,执行break语句,跳出循环}(3)若省略“表达式e3”,应在设计循环结构时保证“

表达式e2”有为false的可能,以便能终止循环。例如:for(intnNum=1;nNum<=50;){nTotal+=nNum;nNum++;}循环结构语句(4)若省略“表达式e1”和“表达式e3”,它相当于whil

e循环。例如:intnNum=1;for(;nNum<=50;){nTotal+=nNum;nNum++;}intnNum=1;while(nNum<=50){nTotal+=nNum;nNum++;}(5)若表达式全部省略,例如:intnNum=1;for(;;){nTotal+=nN

um;nNum++;if(nNum>50)break;}则循环体中所需要的一些变量及其相关的数值要在for语句之前定义,如“intnNum=1;”,且应在循环体中添加额外代码使之有跳出或终止循环的可能,如“if(nNum>50)break;”。循环

结构语句由于循环体可由任何合法的语句组成,因此在循环体内还可以包含前面的几种循环语句,这样就形成了循环的嵌套。例如:for(…;…;…)while(…){{while(…)for(…;…;…){{}}}}目录04break和continue语句break和c

ontinue语句break和continue语句的一般格式如下:break;continue;break语句用于强制结束switch结构(如【例Ex_Switch】)或从一个循环体跳出,即提前终止循环。要注意,break仅使流程跳出其所在的最近的那一层循环或switch

结构,而不是跳出所有层的循环或switch结构。continue目的是提前结束本次循环。对于while和do…while语句来说,continue提前结束本次循环后,流程转到while后面的“表达式e”。对于for语句来说,continue提前结束本次循环后,其流程转到for

语句的“表达式e3”,然后转到“表达式e2”。【例Ex_Continue】把1~100之间的不能被7整除的数输出#include<iostream>usingnamespacestd;intmain(){for(intnNum=1;nNum<=100;nNum++){if(nNum%7==0

)continue;cout<<nNum<<"";}cout<<"\n";return0;}break和continue语句当nNum能被7整除时,执行continue语句,流程转到for语句中的nNum++,并根据表达式nNum<=100的值来决定是否再做循环。而当n

Num不能被7整除时,才执行cout<<nNum<<""语句。程序运行结果如下:12345689101112131516171819202223242526272930313233343637383940414344454647485051525354555758596061626465

6667686971727374757678798081828385868788899092939495969799100VisualC++实用教程(VisualStudio版)(第6版)第1章基本C++语言——函数和预处理目录01函数的定义和调用

1.函数的定义2.函数的调用3.函数的声明函数的定义和调用1.函数的定义在C++中,定义一个函数的格式如下:<函数类型><函数名>(<形式参数表>){<若干语句>}可以看出,一个函数的定义是由函数名、函

数类型、形式参数表和函数体四部分组成的。函数类型决定了函数所需要的返回值类型,它可以是函数或数组之外的任何有效的C++数据类型,包括引用、指针等。如果不需要函数有返回值,只要将函数类型定义为void即可。函数名应是一个有

效的C++标识符(注意命名规则),函数名后面必须跟一对圆括号“()”,以区别于变量名及其他定义的标识符。函数的形式参数(简称形参)写在括号内,参数表中的每一个形参都由形参的数据类型和形参名构成,形参个

数可以是0,表示没有参数,但圆括号不能省略,也可以是一个或多个形参,但多个形参之间要用逗号分隔。函数的定义和调用函数的函数体由在一对花括号中的若干条语句组成,用于实现这个函数执行的动作。C++不允许在一个函数体中再定义

函数。根据上述定义格式,可以编写一个函数。如下列函数的作用是计算两个整数的绝对值之和:intsum(intx,inty){if(x<0)x=-x;if(y<0)y=-y;intz=x+y;returnz;}其中,x和y是sum函数的形

参。所谓形参,是指调用此函数所需要的参数个数和类型。一般地,只有当函数被调用时,系统才会给形参分配内存单元,而当调用结束后,形参所占的内存单元又会被释放。函数的定义和调用由于return的后面可以是常量、变量或任何合法的表达式,因此

函数sum也可简化为:intsum(intx,inty){if(x<0)x=-x;if(y<0)y=-y;return(x+y);//括号可以省略,即returnx+y;}若函数类型是void,函数体就不需要

return语句或return的后面只有一个分号。需要注意的是,因为return是返回语句,它将退出函数体,所以一旦执行return语句后,在函数体内return后面的语句就不再被执行。例如:void

f1(inta){if(a>10)return;//…}在这里,return语句起了一个改变语句顺序的作用。函数的定义和调用2.函数的调用定义一个函数就是为了以后的调用。调用函数时,先写函数名,然后紧跟圆括号,圆括号里是实际调用该函数时所给定的参数,称为实际参数,简称实参,并与形参相对应。函数

调用的一般形式为:<函数名>(<实际参数表>);调用函数时要注意,实参与形参的个数应相等,类型应一致,且按顺序对应,一一传递数据。例如,下面的示例用来输出一个三角形的图案。【例Ex_Call】函数的调用#include<iostream>usingnamespacest

d;voidprintline(charch,intn){for(inti=0;i<n;i++)cout<<ch;cout<<endl;}intmain(){introw=5;for(inti=0;i<row;i++)printline('*',

i+1);//Areturn0;}函数的定义和调用程序运行结果如下:***************代码中,main函数的for循环语句共调用了5次printline函数(A语句),每次调用时因实参i+1的值不断改变,从而使函数printline打印出来的星号个数也随

之改变。由于printline函数没有返回值,因此它作为一个语句来调用。事实上,对于有返回值的函数也可进行这种方式的调用,只是此时不使用返回值,仅要求函数完成一定的操作。实际上,在C++中,一个函数的调用方式还有很多。例如,对于前面的sum函数还可有下列调用方式:sum(3,4);/

/Bintc=2*sum(4,5);//Cc=sum(c,sum(c,4));//D其中,B是将函数作为一个语句,不使用返回值,只要求函数完成一定的操作;C把函数作为表达式的一部分,将返回值参与运算,结果c=18

;D是将函数作为函数的实参,等价于“c=sum(18,sum(18,4));”,执行函数参数内的sum(18,4)后,等价于“c=sum(18,22);”,最后结果为c=40。函数的定义和调用3.函数的声明在【例

Ex_Call】中,由于函数printline的定义代码位置在调用语句A(在main函数中)之前,因而A语句执行不会有问题。但若将函数printline的定义代码位置放在调用语句A之后,即函数定义在后,而调用在前,就会产生“printline标识符未定义”的编译错误。此时必须

在调用前进行函数声明。函数声明消除了函数定义的位置的影响,也就是说,不管函数是在何处定义的,只要在调用前进行函数的声明就可保证函数调用的合法性。虽然,函数不一定在程序的开始就声明,但为了提高程序的可读性,保证简洁的程序结构,最好将主函数mai

n放在程序的开头,而将函数声明放在主函数main之前。声明一个函数按下列格式进行:<函数类型><函数名>(<形式参数表>);可见,函数声明的格式是在函数头的后面加上分号“;”。但要注意,函数声明的内容应和函数的定义相同。例如,对于前面遇到的sum函数和prin

tline函数可有如下声明:intsum(intx,inty);voidprintline(charch,intn);函数的定义和调用由于函数的声明仅是对函数的原型进行说明,即函数原型声明,其声明的形参名在声明语句中并没有任何语句操作它,因此这里的形参名和函数定义时的形参名可以不同,且函数声

明时的形参名还可以省略,但函数名、函数类型、形参类型及个数应与定义时相同。例如,下面几种形式都是对sum函数原型的合法声明:intsum(inta,intb);//允许原型声明时的形参名与定义时不同intsum(int,

int);//省略全部形参名intsum(inta,int);//省略部分形参名intsum(int,intb);//省略部分形参名目录02函数的参数传递函数的参数传递C++中函数的参数传递有两种方式,一种是按

值传递,另一种是地址传递或引用传递。所谓按值传递(简称值传递),是指当一个函数被调用时,C++根据实参和形参的对应关系将实际参数的值一一传递给形参,供函数执行时使用。函数本身不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也不会受到影响。【例Ex_Swap

Value】交换函数两个参数的值#include<iostream>usingnamespacestd;voidswap(floatx,floaty){floattemp;temp=x;x=y;y=temp;cout<<"x="<<x<<",y="<<y<<"\n";}intmain(

){floata=20,b=40;cout<<"a="<<a<<",b="<<b<<"\n";swap(a,b);cout<<"a="<<a<<",b="<<b<<"\n";return0;}程序运行结果如下:a=2

0,b=40x=40,y=20a=20,b=40目录03带默认形参值的函数带默认形参值的函数在C++中,允许在函数声明或定义时给一个或多个参数指定默认值。这样在调用时,可以不给出实参值,而按指定的默认值进行工作。例如:voiddelay(intloops=

1000);//函数声明//…voiddelay(intloops)//函数定义{if(loops==0)return;for(inti=0;i<loops;i++);//空循环,起延时作用}这样,当调用d

elay();//和delay(1000)等效时,程序都会自动将loops当成1000的值来进行处理。当然,也可重新指定相应的参数值,例如:delay(2000);带默认形参值的函数在设置函数的默认参数值时要注意以下几方面。(1)当函数既有原型声明又有定义时

,默认参数只能在原型声明中指定,而不能在函数定义中指定。例如:voiddelay(intloops);//函数原型声明//…voiddelay(intloops=1000)//错误:此时不能在函数定义中指定默认参数{//…}

(2)当一个函数中需要有多个默认参数时,则在形参分布中,默认参数应严格从右到左逐个定义和指定,中间不能跳开。例如:voiddisplay(inta,intb,intc=3);//合法voiddisplay(int

a,intb=2,intc=3);//合法voiddisplay(inta=1,intb=2,intc=3);//合法:可以对所有的参数设置默认值voiddisplay(inta,intb=2,intc);//错误:默认参数应从最右边开

始voiddisplay(inta=1,intb=2,intc);//错误:默认参数应从最右边开始voiddisplay(inta=1,intb,intc=3);//错误:多个默认参数中间不能有非默认参数带默认形参值的函数(3)当带有默认参数的函数调用时,系统按从左到右的

顺序将实参与形参结合,当实参的数目不足时,系统将按同样的顺序用声明或定义中的默认值来补齐所缺的参数值。【例Ex_Default】在函数定义中设置多个默认参数#include<iostream>usingnamespacestd;voiddisplay(inta,in

tb=2,intc=3)//在函数定义中设置默认参数{cout<<"a="<<a<<",b="<<b<<",c="<<c<<"\n";}intmain(){display(1);display(1,5);displa

y(1,7,9);return0;}程序运行结果如下:a=1,b=2,c=3a=1,b=5,c=3a=1,b=7,c=9带默认形参值的函数(4)在函数声明中指定多个默认参数时,还可用多条函数原型声明语句来指定,但同一个参数的默认值只能指定一次。例如,【例E

x_Default】可改写为://下面2条函数说明语句等效于voiddisplay(inta,intb=2,intc=3);voiddisplay(inta,intb,intc=3);//指定c为默认参数voiddisplay(inta,intb=2,intc);//指定b为默认参数(5)

默认参数值可以是全局变量、全局常量,甚至是一个函数。但不可以是局部变量,因为默认参数的函数调用是在编译时确定的,而局部变量的值在编译时无法确定。目录04递归函数递归函数递归(Recursion)是一种常用的程序方法(算法),相应的函数称为递归函数。例如,用递归函数编程求

n的阶乘n!。n!=n*(n-1)*(n-2)*…*2*1。它也可用下式表示:1当n=0时n*(n-1)!当n>0时n!=【例Ex_Factorial】编程求n的阶乘n!#include<iostream>usingnamespacestd;lo

ngfactorial(intn);intmain(){cout<<factorial(4)<<endl;//结果为24return0;}longfactorial(intn){longresult=0;if(0==n)result=

1;elseresult=n*factorial(n-1);//进行自身调用returnresult;}递归函数主函数main调用了求阶乘的函数factorial,而函数factorial中的语句“result=n*factorial(n-1);”又调用了函数自身,因此函数factorial是一

个递归函数。程序运行结果如下:24下面来分析main函数中“factorial(4);”语句的执行过程,其过程还可用图1.12来表示。递归函数(1)(2)(3)(4)(5)进行函数factorial(4)调用初始化,传递参数值4,分配形参n内存空间,执行函数体中的

代码,此时result=0,因n=4,不等于0,故执行“result=4*factorial(3);”,因语句中有函数factorial(3)调用,故进行下一步操作。进行函数factorial(3)调用初始化,

传递参数值3,分配形参n内存空间,执行函数体中的代码,此时result=0,因n=3,不等于0,故执行“result=4*factorial(2);”,因语句中有函数factorial(2)调用,故进

行下一步操作。进行函数factorial(2)调用初始化,传递参数值2,分配形参n内存空间,执行函数体中的代码,此时result=0,因n=2,不等于0,故执行“result=4*factorial(1);”,因语句中有函数factorial(1)调用,故进行下一步操作。进行函数factoria

l(1)调用初始化,传递参数值1,分配形参n内存空间,执行函数体中的代码,此时result=0,因n=1,不等于0,故执行“result=4*factorial(0);”,因语句中有函数factorial(0)调用,故进

行下一步操作。进行函数factorial(0)调用初始化,传递参数值0,分配形参n内存空间,执行函数体中的代码,此时result=0,因n=0,故执行result=1。然后执行函数后面的语句。递归函数(6)(7)(8)(9)(10)当执行“returnresult;”后,进行调用后处理,

factorial(0)函数返回到主调函数factorial(1)。在主调函数factorial(1)中,result=1*1=1,然后执行函数后面的语句。当执行“returnresult;”后,进行调用后处理,factorial(1

)函数返回到主调函数factorial(2)。在主调函数factorial(2)中,result=2*1=2,然后执行函数后面的语句。当执行“returnresult;”后,进行调用后处理,factorial(2)

函数返回到主调函数factorial(3)。在主调函数factorial(3)中,result=3*2=6,然后执行函数后面的语句。当执行“returnresult;”后,进行调用后处理,factorial(3)函数返回到主调函数factorial(4)。在主调函数fa

ctorial(4)中,result=4*6=24,然后执行函数后面的语句。当执行“returnresult;”后,进行调用后处理,factorial(4)函数返回到主调函数main。在主调函数main中,执行下一条指令,输出结果24。目录05内联函数内联函数内联函数的使用方法与

一般函数相同,只是在内联函数定义时,需在函数的类型前面加上inline关键字。【例Ex_Inline】用内联函数实现求两个实数的最大值#include<iostream>usingnamespacestd;inlinefloatfmax(

floatx,floaty){returnx>y?x:y;}intmain(){floata;a=fmax(5,10);//A语句cout<<"最大的数为:"<<a<<"\n";return0;}这样,当

程序编译时,A语句就变成了:a=5>10?5:10;程序运行结果如下:最大的数为:10内联函数要注意使用内联函数的一些限制:(1)内联函数中不能有数组定义,也不能有任何静态类型(后面会讨论)的定义。(2)内联函数中不能含有循环、switch和复杂嵌套的if语句。(2)内联函数不能是递归函数。目录

06函数重载函数重载函数重载是指C++允许多个同名的函数存在,但同名的各个函数的形参必须有区别:要么形参的个数不同,要么形参的个数相同,但参数类型有所不同。【例Ex_OverLoad】编程求两个或三个数之和#include

<iostream>usingnamespacestd;intsum(intx,inty);intsum(intx,inty,intz);doublesum(doublex,doubley);doublesum(doublex,d

oubley,doublez);intmain(){cout<<sum(2,5)<<endl;//结果为7cout<<sum(2,5,7)<<endl;//结果为14cout<<sum(1.2,5.0,7.5)<<endl;//结果为13.7re

turn0;}intsum(intx,inty){returnx+y;}intsum(intx,inty,intz){returnx+y+z;}doublesum(doublex,doubley){returnx+y;}doublesum(doublex,dou

bley,doublez){returnx+y+z;}函数重载程序的运行结果为:71413.7从上面的例子可以看出,由于使用了函数的重载,因而不仅方便函数名的记忆,更主要的是完善了同一个函数的代码功能,给调用带来了许多方便。需要说

明的是,重载函数必须具有不同的参数个数或不同的参数类型,若只有返回值的类型不同是不行的。例如:voidfun(inta,intb);//第1版本intfun(inta,intb);//第2版本是错误的。因为若有函数调用fun(2,3)时,编译器无法准确地

确定应调用哪个版本的fun函数。同样,当函数的重载带有默认参数时,也要注意避免上述的二义性情况。例如:intfun(inta,intb=0);//第1版本intfun(inta);//第2版本是错误的。因为若有函数调用fun(2)时,编译器也无法准确地确定应调用哪个版本的fu

n函数。目录07作用域和可见性1.块作用域2.函数原型作用域3.函数作用域4.文件作用域作用域和可见性1.块作用域这里的块就是前面已提到过的块语句。在块中声明的标识符,其作用域从声明处开始,一直到结束块的花括号为止。块作

用域也称作局部作用域,具有块作用域的变量是局部变量。例如:voidfun(void)//在形参表中指定void,表示没有形参,void可不要{inta;//a的作用域起始处cin>>a;if(a<0){a=-a;intb;//b的作用域起始处//…}//b的作用域终止处}//a

的作用域终止处代码中,声明的局部变量a和b处在不同的块中。其中变量a是在fun函数的函数体块中,因此在函数体这个范围内,该变量是可见的。而b是在if语句块中声明的,故它的作用域是从声明处开始到if语句结束处终止。作用域和可见性需要说明

的是,当标识符的作用域完全相同时,不允许出现相同的标识符名。而当标识符具有不同的作用域时,允许标识符同名。例如:voidfun(void){//块Ainti;//…{//块Binti;i=100;//…}}代码中,在A和B块中都声明了

变量i,这是允许的。但同时出现另外一个问题,语句“i=100;”中的i是使用A块中的变量i还是使用B中的变量i?C++规定在这种作用域嵌套的情况下,如果内层和外层作用域声明了同名的标识符,那么在外层作用域中声明的标识符对于该内层作用域是不可见

的。也就是说,在块B声明的变量i与块A声明的变量i无关,当块B中的i=100时,不会影响块A中变量i的值。作用域和可见性2.函数原型作用域函数原型作用域是指在声明函数原型时所指定的参数标识符的作用范围。这个作用范围在函数原型声明中的左、右圆括号之间。正因为如此,在函数原型中声明的标识符

可以与函数定义中说明的标识符名称不同。由于所声明的标识符与该函数的定义及调用无关,所以可以在函数原型声明中只作参数的类型声明,而省略参数名。3.函数作用域具有函数作用域的标识符在声明它的函数内可见,但在此函数之外是不可见的。在C++中,只有goto语句中的标号具有函数作用域。由于goto语

句的滥用导致程序流程无规则、可读性差。因此现代程序设计方法不主张使用goto语句。作用域和可见性4.文件作用域在函数外定义的标识符或用extern说明(后面会讨论)的标识符称为全局标识符。全局标识符的作用域称为文件作用域,它从声明之处开

始,直到文件结束一直是可见的。需要说明的是,全局的常量或变量的作用域是文件作用域,它从定义开始到源程序文件结束。若函数定义在后,调用在前,必须进行函数原型声明。若函数定义在前,调用在后,函数定义包含了

函数的原型声明。一旦声明了函数原型,函数标识符的作用域是文件作用域,它从定义开始到源程序文件结束。在C++中,若在块作用域内使用与局部标识符同名的块外标识符时,则需使用域作用符“::”来引用,且该标识符必须是全局标识符,即它具有文件作用域。作用域和可见性【例Ex_Process】在

块作用域内引用文件作用域的同名变量#include<iostream>usingnamespacestd;inti=10;//Aintmain(){inti=20;//B{inti=5;//Cintj;::i=::i+4;

//::i是引用A定义的变量i,不是B中的ij=::i+i;//这里不加::的i是C中定义的变量cout<<"::i="<<::i<<",j="<<j<<"\n";}cout<<"::i="<<::i<<",i="<<i<<"\n";//这里不加::的i是

B中定义的变量return0;}程序的运行结果为:::i=14,j=19::i=14,i=20目录08存储类型1.自动类型(auto)2.寄存器类型(register)3.静态类型(static)4.外部类型(extern)存储类型在C++中,变量有4种存储

类型:自动类型、静态类型、寄存器类型和外部类型,这些存储类型是在变量定义时来指定的,其一般格式如下:<存储类型><数据类型><变量名表>;1.自动类型(auto)一般来说,用自动存储类型声明的变量都限制在某个程序范围内使用,即为局部变量。从

系统角度来说,自动存储类型变量是采用动态分配方式在栈区中分配内存空间。因此,当程序执行到超出该变量的作用域时,就释放它所占用的内存空间,其值也随之消失了。在C++中,声明一个自动存储类型的变量是在变量类型前加上关键字auto,例如:autointi;若自动存储类型

的变量是在函数内或语句块中声明的,则可省略关键字auto,例如:voidfun(){inti;//省略auto//…}存储类型2.寄存器类型(register)使用关键字register声明寄存器类型的变量的目的是将所声明的变量放入寄存器内

,从而加快程序的运行速度。例如:registerinti;//声明寄存器类型变量但有时,在使用register声明时,若系统寄存器已经被其他数据占据,寄存器类型的变量就会自动当作auto变量。3.静态类型(static)从变量的生存期来说,一个变量的存储空间可以是永久的,即在程序运行期间该变

量一直存在,如全局变量;也可以是临时的,如局部变量,当流程执行到它的说明语句时,系统为其在栈区中动态分配一个临时的内存空间,并在它的作用域中有效,一旦流程超出该变量的作用域时,就释放它所占用的内存空间,其值也随之消失。但是,若在声明局部变量类型前面加上关键字static,则将其定义

成一个静态类型的变量。这样的变量虽具有局部变量的作用域,但由于它是用静态分配方式在静态数据区中来分配内存空间,因此,在此方式下,只要程序还在继续执行,静态类型变量的值就一直有效,不会随它所在的函数或语句块的结束而消失。存储类型需要说明的是,静态类型的局部变量只在第一次执行时进行初始化,正因为

如此,在声明静态类型变量时一定要指定其初值,若没有指定,编译器还会将其初值置为0。【例Ex_Static】使用静态类型的局部变量#include<iostream>usingnamespacestd;voidcount(){inti=0;staticintj=0;/

/静态类型i++;j++;cout<<"i="<<i<<",j="<<j<<"\n";}intmain(){count();count();return0;}程序中,当第1次调用函数count时,由于变量j是静态类型,

因此其初值设为0后不再进行初始化。执行j++后,j值为1,并一直有效。第2次调用函数count时,由于j已分配内存且进行过初始化,因此语句“staticintj=0;”被跳过,执行j++后,j值为2。程序运行结果如下:i=1,j=1i=1,j=2存储类型4.外部

类型(extern)使用关键字extern声明的变量称为外部变量,一般是指定义在本程序外部的变量。当某个变量被声明成外部变量时,不必再次为它分配内存就可以在本程序中引用这个变量。在C++中,只有在两种情况下需要

使用外部变量。第1种情况:在同一个源文件中,若定义的变量使用在前,声明在后,这时在使用前要声明为外部变量。第2种情况:当由多个文件组成一个完整的程序时,在一个源程序文件中定义的变量要被其他若干个源文件引用时,引用的文件中要用extern对该变量作外部声明。需要注意的是

,可以对同一个变量进行多次extern的声明。若在声明时,给一个外部变量赋初值,则编译器认为是一个具体的变量定义,而不是一个外部变量的声明,此时要注意同名标识符的重复定义。例如:externintn=1;//变量定义…intn;//错误:变量n重复定

义虽然外部变量对不同源文件中或函数之间的数据传递特别有用,但也应该看到,这种能被许多函数共享的外部变量,其数值的任何一次改变,都将影响到所有引用此变量的函数的执行结果,其危险性是显然的。目录09编译预处理1.宏定义2.带参数的宏定义3.文件包含4.条件编译编

译预处理C++提供的预处理指令主要有三种:宏定义、文件包含和条件编译。这些指令在程序中都是以“#”来引导的,每一条预处理指令必须单独占用一行。由于它不是C++的语句,因此在结尾没有分号(;)。1.宏定义宏定义就是用一个指定的标识符来代替一个字符串,C++中

宏定义是通过宏定义指令#define来实现的,它有两种形式:不带参数的宏定义和带参数的宏定义。以前已提及,用#define可以定义一个标识符常量,如:#definePI3.141593其中,#define是宏定义指令,PI称为宏名。在程序编译时,编译器首先将程序中的PI用

3.141593来替换,然后再进行代码编译。宏后面的内容实际上是字符串,编译器本身不对其进行任何语法检查,仅仅是用来在程序中做与宏名的简单替换。例如,下面的宏定义是合法的:#definePI3.141ABC593宏被定义后,可使用下列指令消除宏定义:#und

ef宏名编译预处理一个定义过的宏名可以用来定义其他新的宏,但要注意其中的括号,例如:#defineWIDTH80#defineLENGTH(WIDTH+10)宏LENGTH等价于:#defineLENGTH(80+10)但其中的括号不能省略,因为当var

=LENGTH*20;若宏LENGTH定义中有括号,则预处理后变成:var=(80+10)*20;若宏LENGTH定义中没有括号,则预处理后变成:var=80+10*20;显然,两者的结果是不一样的。编译预处理2.带参数的宏定义带参数的宏定义的一般格式为:#d

efine<宏名>(参数名表)字符串例如:#defineMAX(a,b)((a)>(b)?(a):(b))其中(a,b)是宏MAX的参数表,如果在程序中出现下列语句:x=MAX(3,9);则预处理后变成:x=((3)>(9)?(3):(9));//结果

为9很显然,带参数的宏相当于一个函数的功能,但却比函数简洁。带参数的宏内容字符串中,参数一定要加圆括号,否则不会有正确的结果。例如:#defineAREA(r)(3.14159*r*r)如果在程序中出现下列语句:x=AREA(3+2);则预处理后变成x=(3.14159*3

+2*3+2);//结果显然不等于3.14159*5*5故此宏定义正确的形式应是:#defineAREA(r)(3.14159*(r)*(r))编译预处理3.文件包含“文件包含”指令是很有用的,它可以节省程序设计人员的重复劳动。例如,在编程中,有时要经常使用一些符号常量(如PI

=3.14159265,E=2.718),可以将这些宏定义组成一个文件,然后其他人都可以用#include指令将这些符号常量包含到自己所写的源文件中,避免了这些符号常量的再定义。C++中,#include指令有下列两种格式:#include<文件名>#i

nclude"文件名"第1种格式是将文件名用尖括号“<>”括起来的,用来包含那些由系统提供的并放在指定子目录中的头文件,称为标准方式。第2种格式是将文件名用双引号括起来的,称为用户方式。在使用#include命令时需要注意的是,一条#include命令只能包含一个

文件,若想包含多个文件需用多条文件包含命令。例如:#include<iostream>#include<cmath>//…编译预处理需要说明的是,为了能在C++使用C语言中的库函数,又能使用C++新的头文件包含格式,ANSI/ISO将有些C语言的头文件去掉.h,并在头文件

前面加上“c”变成C++的头文件,如表1.4所示,实际上它们的内容是基本相同的。C++头文件C头文件作用函数举例cctypectype.h标准C的字符类型处理如:intisdigit(int);判断c是否是数字字符cmat

hmath.h标准C的数值计算如:floatfabs(float);求浮点数x的绝对值cstdiostdio.h标准C的输入输出如:输出printf,输入scanfcstdlibstdlib.h标准C的通用函数如:voidexit(int);退

出程序cstringstring.h标准C的字符串处理如:strcpy是用来复制字符串ctimetime.h标准C的时间处理如:time是用来获取当前系统时间编译预处理4.条件编译一般情况下,源程序中所有的语句都参加编译,但有时也希望程序按一定的条件

去编译源文件的不同部分,这就是条件编译。条件编译使同一源程序在不同的编译条件下得到不同的目标代码。C++提供的条件编译指令有以下三种常用的形式,现分别介绍。(1)第1种形式#ifdef<标识符><程序段1>[#else<程序段2>]#endif其

中,#ifdef、#else和#endif都是关键字,程序段是由若干条预处理指令或语句组成的。这种形式的含义是:如果标识符被#define指令定义过,则编译程序段1,否则编译程序段2。编译预处理【例Ex_UseIfdef】使用#ifde

f条件编译指令#include<iostream>usingnamespacestd;#defineLIintmain(){#ifdefLIcout<<"Hello,LI!\n";#elsecout<<"

Hello,everyone!\n";#endifreturn0;}程序的运行结果为:Hello,LI!编译预处理(2)第2种形式#ifndef<标识符><程序段1>[#else<程序段2>]#endif这与前一种形式的区别仅在于,如果标识符没有被#define指令

定义过,则编译程序段1,否则就编译程序段2。(3)第三种形式#if<表达式1><程序段1>[#elif<表达式2><程序段2>...][#else<程序段n>]#endif其中,#if、#elif、#else和#endif是关键字。它的含义是,

如果表达式1为true就编译程序段1,否则如果表达式2为true就编译程序段2,…,如果各表达式都不为true就编译程序段n。编译预处理【例Ex_UseIf】使用#if条件编译指令#include<iostream

>usingnamespacestd;#defineA-1intmain(){#ifA>0cout<<"a>0\n";#elifA<0cout<<"a<0\n";#elsecout<<"a==0\n";#endifre

turn0;}程序的运行结果为:a<0若将“#defineA-1”中的-1改为0,则程序的运行结果为:a==0VisualC++实用教程(VisualStudio版)(第6版)第1章基本C++语言——数组目录01一维数组1

.一维数组的定义和引用2.一维数组的初始化和赋值一维数组1.一维数组的定义和引用C++中,一维数组的一般定义格式如下:<数据类型><数组名>[<常量表达式>];其中,方括号“[]”是区分数组和变量的特征符号。方括号中的常量表达式的值必须是一个确定的整型数值,且数值必须大于0,它反映一维

数组元素的个数或一维数组的大小、数组的长度。数组名前的“数据类型”必须是C++合法的数据类型,用来指定数组中元素的数据类型,它反映各元素所占内存单元的大小。数组名与变量名一样,遵循标识符命名规则。例如:inta[10

];其中,a表示数组名,方括号里的10表示该数组有10个元素,每个元素的类型都是int。在定义中,还可将同类型的变量或同类型的其他数组的定义写在一行语句中,但它们必须用逗号隔开。例如:inta[10],b[20],n;

其中,a和b被定义成整型数组,n是整型变量。一维数组一般地,数组方括号中的常量表达式中不能包含变量,但可以包括常量和符号常量。如:inta[4-2];//合法,表达式4-2是一个确定的值2floatb[3*6];

//合法,表达式3*6是一个确定的值18constintsize=18;intc[size];//合法,size是一个标识符常量intSIZE=18;intd[SIZE];//不合法,SIZE是一个变量,不能用作数组大小的定义intd[0];//ANSI/ISOC++不合法,定义时,下标必须

大于0需要说明的是,当数组的数据类型是char时,则该数组称为字符数组。由于字符数组的每一个元素都用来存储一个字符,因此字符数组可用来存放一个字符序列,即字符串。一维数组数组定义后,就可以用下标运算符通过指定下标序号来引用和操作数组中的元

素,引用时按下列格式:<数组名>[<下标表达式>]其中,方括号“[]”是C++的下标运算符,下标表达式的值就是下标序号,反映该元素在数组中的位置。需要说明的是,C++数组的下标序号总是从0开始。例如,若有数组定义:inta[5];则由于开始的下标序号为0,也就是说,a

[0]是数组a的第一个元素。由于数组a被定义成具有5个元素的一维数组,因此a[0]、a[1]、a[2]、a[3]、a[4]是数组a的5个元素,a[4]是a的最后一个元素。注意,这里的数组a没有a[5]这个数组元素

。可见,在引用一维数组元素时,若数组定义时指定的大小为n,则下标序号范围为0~(n-1)。在引用数组元素时,下标序号的值必须为整型。它可以是一个整型常量,也可以是一个整型变量,或者结果为一个整型值的表达式等

。例如:intd[10];//…for(inti=0;i<10;i++)cout<<d[i]<<"\t";代码中的d[i]就是一个对数组d元素的合法引用,i是一个整型变量,用来指定下标序号,当i=0时,引用的是元素d[0],当i=1时,引用的是元素d[1],……,以此类推。一维数组2.一维数组的初

始化和赋值与变量一样,在引用数组元素前还可对其进行初始化或赋初值。数组元素既可以在数组定义的同时赋初值,即初始化,也可以在定义后赋值。一维数组的初始化格式如下:<数据类型><数组名>[<常量表达式>]={初值列表};与变量初

始化不同的是,数组元素的初始化是在数组定义格式中,在方括号之后,用“={初值列表}”的形式进行的。其中,初值列表中的初值个数不得多于数组元素个数,且多个初值之间要用逗号隔开。例如:inta[5]={1,2,3,4

,5};是将花括号“{}”里的初值(整数)1,2,3,4,5分别依次填充到数组a的内存空间中,亦即将初值依次赋给数组a的各个元素。它的作用与下列的赋值语句相同:a[0]=1;a[1]=2;a[2]=3;a[3]=4;a[4]=5;一维数组对于一维数组的初始化和赋值需注意以下几点。

(1)可以给其中的一部分元素赋初值,此时其他元素的值均为0。例如:intb[5]={1,2};//A是将数组b的元素b[0]=1,b[1]=2。此时,b[2]、b[3]、b[4]的值均默认为0,若有:intb[5]={0};则使数组b的各个元素的值均设为0。(2)在“={初值列表}”中,花括号中

的初值可以是常量或常量表达式,但不能有变量,且初值个数不能多于数组元素个数。例如:doublef[5]={1.0,3.0*3.14,8.0};//合法doubled=8.0;doubleg[5]={1.0,3.0*3.14,d};//不合法,d是

变量inte[5]={1,2,3,4,5,6};//错误,初始化值个数多于数组元素个数一维数组(3)在对全部一维数组元素赋初值时,有时可以不指定一维数组的长度。例如:intc[]={1,2,3,4,5};编译时将根据数值的个数自动设定c数组的长度,这里是5。要注意,必须让编译器能知道数组的大小

。若只有:intc[];//不合法,未指定数组大小则是错误的。(4)“={初值列表}”只限于数组定义时的初始化,不能出现在赋值语句中。例如:intc[4];//合法c[4]={1,2,3,4};//错误一维数组(5)在“={初值列表}”中,逗号前面必须

有表达式或值。例如:intf[5]={1,,3,4,5};//错误,第2个逗号前面没有值intg[5]={1,2,3,};//ANSI/ISOC++中合法inth[5]={};//ANSI/ISOC++中合法,等价于inth[5]={0};(6)两个一维数

组不能直接进行赋值“=”运算,但数组元素可以。例如:inta1[4]={1,2,3,4};//合法inta2[4];//合法a2=a1;//错误,数组名表示一个地址常量,不能做左值a2[0]=a1[0];//合法:数组元素本质上就是一个变量a1[2]

=a2[1];//合法:数组元素本质上就是一个变量目录02二维数组1.二维数组的定义和引用2.二维数组元素在内存空间存放的次序3.二维数组的初始化和赋值二维数组1.二维数组的定义和引用二维数组定义的格式如下:<数据类型><数组名>[<常量表达式1>][<常

量表达式2>];从中可以看出,二维数组定义的格式与一维数组定义基本相同,只是多了一对方括号。同样,若定义一个三维数组,则在二维数组定义格式的基础上再增加一对方括号,以此类推。显然,对于数组定义的统一格式可表示为:<数据类型>

<数组名>[<常量表达式1>][<常量表达式2>]…[<常量表达式n>];其中,各对方括号中的常量表达式用来指定相应维的大小。例如:floatb[2][3];charc[4][5][6];其中,b是二维数组,每个元素的数据类型都是float型。c是三维数组,每个元素的数据类型都是ch

ar型。二维数组需要说明的是,要注意数组定义中维的高低。如图1.13所示,四维数组d的维的次序依次从右向左逐渐升高,最右边的是最低维,最左边的是最高维。对于多维数组来说,数组元素的个数是各维所指定的大小的乘积。例如,上述定义的二维数组b中的元素个数为2×3

=6个,三维数组c中的元素个数为4×5×6=120个。一旦定义了多维数组,就可以通过下面的格式来引用数组中的元素:<数组名>[<下标表达式1>][<下标表达式2>]…[<下标表达式n>]这里的下标表达式1、下标表达式2等分别与数组定

义时的维相对应。也就是说,对于上述定义“floatb[2][3];”中的二维数组b来说,其元素引用时需写成b[i][j]的形式。二维数组2.二维数组元素在内存空间存放的次序由于内存空间是一维的,因此需要搞清二维(多维)数组元素在内存中存放的次序。在C++中,数组维数

的高低次序依次从右向左逐步升高,类似于十进制数中的个位、十位、千位……的变化次序。在内存中依次存放的数组元素的下标序号总是从低维到高维顺序变化。例如:inta[3][4];则a在内存中存放的元素的次序如图1.14所示。二维数组事

实上,若在程序中通过循环嵌套来引用二维或多维数组的元素,则是最方便的程序方法。此时,循环嵌套的层数应与数组维数相同。例如:inta[3][4],i,j;//输入二维数组a的元素值for(i=0;i<3;i++)for(j=0;

j<4;j++)cin>>a[i][j];//输出二维数组a的全部元素for(i=0;i<3;i++){for(j=0;j<4;j++)cout<<a[i][j]<<"\t";cout<<endl;}二维数组3.二维数组的初始化和赋值在程序设计中,常将二维数组看成一个具有行和列的数据表,例如:i

nta[3][4];由于它在内存空间的存放次序可以写成:a[0]:a[0][0],a[0][1],a[0][2],a[0][3],//第0行a[1]:a[1][0],a[1][1],a[1][2],a[1][3],//第1行a[2]:a[2][0],a[2][1],a[2][2],a[2][3]。

//第2行因此,可以认为在数组a[3][4]中,3表示行数,4表示列数。故在进行二维数组初始化时常常以“行”为单位。在C++中,“行”的数据由“{}”构成,且每一对“{}”根据其书写的次序依次对应于二维数组的第0行

、第1行、第2行……第i行。例如:inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};二维数组其中,{1,2,3,4}是对第0行元素进行初始化,{5,6,7,8}是对第1行元素进行初始化,{9,10,11,12}是对第2行

元素进行初始化,它们是依次进行,行与行之间用逗号分隔。每对花括号里的数据个数均不能大于列数。它等价于inta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};//依次对元素进行初始化需要说明的是,可以只对部分元素赋初值,例如:

inta[3][4]={{1,2},{3},{4,5,6}};凡没有明确列举元素值的元素,其值均为0,即等同于:inta[3][4]={{1,2,0,0},{3,0,0,0},{4,5,6,0}};又如:inta[3][4]={1,2,3};当数据中没有花括号时,则将其按元素在内存空间的存放次序

依次赋初值,即a[0][0]=1,a[0][1]=2,a[0][2]=3,其余各个元素的初值为0。二维数组要注意二维数组中以“行”为单位的混合形式的初始化情况,例如:inta[3][4]={{1,2},{3,4,5},6};则{1,2}对应于a的第0行,{

3,4,5}对应于a的第1行,后面的6无论是否有花括号,都对应于a的下一行。因此上述初始化等同于:inta[3][4]={{1,2,0,0},{3,4,5,0},{6,0,0,0}};要注意花括号前面最好不能有单独的数值,例如:inta[

3][4]={{1,2},3,{4},5};//不要这么做对于多维数组来说,若有初始化,则定义数组时可以忽略最高维的大小,但其他维的大小不能省略。也就是说,在二维数组定义中,最左边方括号中的大小可以不指定,

但最右边方括号中的大小必须指定。例如:intb[][4]={1,2,3,4,5,6,7,8,9,10,11,12};//结果为b[3][4]intb[][4]={{1,2,3,4},{5,6},{7},{8,9,10,11},12};//结果为b[5][4]intb[]

[4]={1,2,3};//结果为b[1][4]intb[][4]={{1},2,3};//结果为b[2][4]目录03字符数组1.一维字符数组2.二维字符数组字符数组1.一维字符数组对于一维字符数组来说,

它的初始化有两种方式。一是:charch[]={'H','e','l','l','o','!','\0'};另一种方式是使用字符串常量来给字符数组赋初值。例如:charch[]={"Hello!"};其中的花括号可以省略,即charc

h[]="Hello!";这几种方式都是使ch[0]='H',ch[1]='e',ch[2]='l',ch[3]='l',ch[4]='o',ch[5]='!',ch[6]='\0'。需要说明的是,如果指定的数组长度大于字符串中的字符个数,那么其余的元素

将自动设定为'\0'。例如:charch[9]="Hello!";因"Hello!"的字符个数为6,但还要包括一个空字符'\0',故数组长度至少是7,从ch[6]开始到ch[8]都等于空字符'\0'。要注意,不能将字符串常量直接通过赋值语句赋给一个字

符数组。例如,下列赋值语句是错误的:Charstr[20];str="Hello!";//错误字符数组2.二维字符数组一维字符数组常用于存取一个字符串,而二维字符数组可存取多个字符串。例如:charstr[][20]={"Ho

w","are","you"};这时,数组元素str[0][0]表示一个char字符,值为'H';而str[0]表示字符串"How",str[1]表示字符串"are",str[2]表示字符串"you"。由于省略了二维

字符数组的最高维的大小,编译器会根据初始化的字符串常量,自动设为3。要注意,二维字符数组最右边的大小应不小于初始化初值列表中最长字符串常量的字符个数+1。目录04数组与函数数组与函数数组也可作为函数的形参和实参。若数组元素作为函数的实参,则其用法与一般变量相同。但当数组名作为函

数的实参和形参时,由于数组名表示数组内存空间的首地址,因此是函数的地址传递。【例Ex_StrChange】改变字符串中的内容#include<iostream>#include<cstring>usingnamespacestd;voi

dchange(charstr1[20]);intmain(){charname[10]="Ding";cout<<name<<endl;change(name);//调用时,只需指定数组名cout<<na

me<<endl;return0;}voidchange(charstr1[20]){strcpy(str1,"Zheng");}数组与函数代码中,函数change的形参是一个字符数组,调用时只要将数组名作为实参即可。由于函数传递的是数组的地址,因此函数中对形参改变的内容,

也同样反映到实参中。程序运行结果如下:DingZheng需要说明的是,函数调用时,实参数组与形参数组的数据类型应一致,如不一致,结果将出错。另外,形参数组也可以不指定大小,但为了满足在被调用函数中处理数组元素的需要,可以另设一个参数,用来指定传递数组元素的个数。例如:flo

atave(intdata[],intn);VisualC++实用教程(VisualStudio版)(第6版)第1章基本C++语言——指针和引用目录01指针和指针变量指针和指针变量在程序中,变量名是变量所对应的内存空间的标识,对变量名的操作也就是对其内存空间的操作。在程序中用变量

名来操作其内存空间的最大好处是不必关心其内存空间的地址,但同时,由于变量一旦定义后,变量名和内存空间的对应关系在编译时就确定下来了,在变量的运行生命期中这种对应关系是不能被改变的。因而,用变量名来操作其他内存空间受到了一定的限制。为了

能像变量名那样来引用它所对应的内存空间,又能在程序中比较自由地访问其他不同的内存空间,C++引入了指针(pointer)这个概念。由于一个内存空间可用其首地址和单元数目(大小)来唯一确定,而不同内存空间的首地址也各不相同,因此为了能让一个指针访问不同的内存空间,则指针本身存放

的值必须是不同内存空间的首地址。由于可以存放地址值,所以指针必须是一个变量,这样就可以在程序中进行定义了,但此时指针的数据类型,不是反映它存取的数值类型,而是用来确定该指针所能访问的内存空间的大小。这样,指针一旦定义并初始

化后,通过指针名和专门的运算符就可在程序中建立、操作和引用不同的内存空间了。指针和指针变量在C++中,定义一个指针变量可按下列格式:<数据类型>*<指针变量名1>[,*<指针变量名2>,...];式中的“*”是一个定义指针变量的说明符,它不是指定指针变量名的一部分

。每个指针变量前面都需要这样的“*”来标明。例如:int*pInt1,*pInt2;//pInt1,pInt2是指向整型变量的指针float*pFloat;//pFloat是一个指向实型变量的指针char*pChar;//pChar是一个指向字符型变量的指针,它通常用来处理字符串则定义

了整型指针pInt1、pInt2,单精度实型指针pFloat和字符型指针pChar。其中,由于指针pInt1和pInt2的类型是int,因此pInt1和pInt2用来指向一个4字节的内存空间。由于指针变量的值是某个内存空间的首地址,而地址的长度都

是一样的,因此指针变量自身所占的内存空间大小都是相同的,在32位机器中都是4个字节。目录02&和*运算符&和*运算符运算符“&”的功能是获取操作对象的指针。对于变量来说,其指针值就是该变量所对应的内存空间的首地址。运算符“*”的功能是引用指针所指向的内存空间。当其作为左值时,则被引用的内存空

间应是可写的;当其作为右值时,则“引用”的操作是读取被引用的内存空间的值。例如:inta=3;//整型变量,初值为3int*p=&a;//指向整型变量的指针,其值等于a的地址intb=*p;//取出指针所指向的内存空间中的内容并赋给b,值为3指针变量的初始化除在定义时进行,还可在程序中

通过赋值语句进行,注意它们的区别。例如:inta=3;//整型变量,初值为3int*pi;//指向整型变量的指针pi=p;//将指针p的地址赋给指针pi,使它们都是指向a的指针//它等价于pi=&a;注意在pi前没有*&和*运算符需

要说明的是,“*”和“&”运算符在逻辑(功能)上是互斥的,即当它们放置在一起时可以相互抵消。例如,若有变量i,则&i用来获取i的指针,此时*(&i)就是引用i的指针的内存空间,即变量i。正因为如此,C++将“*”运算符的功能解释为“解除

&操作”。同样,使用&*p就是使用指针p。另外,还需注意的是,在使用指针变量前,一定要进行初始化或有确定的地址数值。例如下面的操作会产生致命的错误:int*pInt,a=10;*pInt=10;//此时pInt的

指向不明确或*pInt=a;指针变量只能赋一个指针的值,若给指针变量赋了一个变量的值而不是该变量的地址,或者赋了一个常量的值,则系统会以这个值作为地址。根据这个“地址”读写的结果将是致命的。给两个指针

变量进行赋值,必须使这两个指针变量类型相同,这样才能保证操作的内存“单元”的大小是相同的。否则,结果将是不可预测的。例如:int*pi;floatf=1.22,*pFloat=&f;pi=pFloat;//尽管本身的赋

值没有错误,但结果是不可预测的。//因为(*pi)的值不会等于1.22,也不会等于1给指针变量赋值实际上是“间接”地给指针所指向的变量赋值。例如:inta=11,*p=&a;(*p)++;//结果a的值为12&和*运算符下面看一个示例。【例Ex_CompUsePointer】输入

a和b两个整数,按大小顺序输出#include<iostream>usingnamespacestd;intmain(){int*p1,*p2,*p,a,b;cout<<"输入两个整数:";cin>>a>>b;p1=&

a;p2=&b;if(a<b){p=p1;p1=p2;p2=p;}cout<<"a="<<a<<",b="<<b<<endl;cout<<"最大的值是:"<<*p1<<",最小的值是:"<<*p2<<"\n";return0;}

程序中,当a≥b时,指针变量p1指向a,p2指向b;而当a<b时,通过指针交换,p1指向b,p2指向a。因此,上述程序代码总是使p1指向数值最大的变量,使p2指向数值最小的变量。程序运行结果如下:输入两个整数:11␣28a=11,b=28最大的值是:28,最小的值是:11目录03指针运算1.

指针的算术运算2.指针的关系运算指针运算指针的这种运算的意义和通常的数值加减运算的意义是不一样的。这是因为一旦指针赋初值后,指针的指向也就确定了,由于指针指向一块内存空间,因此当一个指针加减一个整数值n时,实际上是将指针的指向向上(减)或向下(加)移动n个位置,因此指针

加上或减去一个整数值n后,其结果仍是一个指针。1.指针的算术运算在实际应用中,指针的算术运算主要是对指针加上或减去一个整数。<指针变量>+n<指针变量>-n例如,若有int*ptr;当指针初始化后,若设当前指向的位置地址值为0012FF70h,则当指

针ptr加上整数2时,即ptr+2,表示指针ptr的当前指向将向下移动2个指向位置,由于指针类型是int,因而指向位置的间距是sizeof(int)个字节,故(ptr+2)指针的位置地址值为0012FF70h+sizeof(int)*

2,即为0012FF78h,如图1.15所示。图1.15指针的算术运算指针运算2.指针的关系运算两个指针变量的关系运算是根据两个指针变量值的大小来进行比较的。在实际应用中,通常是比较两个指针反映地址的前后关系或判断指针变量的值是否为0。【例Ex_PointerOp】将字符数组

a中的n个字符按相反顺序存放#include<iostream>usingnamespacestd;intmain(){chara[]="Chinese";char*p1=a,*p2=a,temp;while(*p2!='\0')p2++;p2

--;//将p2指向a的最后一个元素while(p1<p2){temp=*p1;*p1=*p2;*p2=temp;//交换内容p1++;p2--;}cout<<a<<endl;//输出结果return0;}程序中,先将指针p1和p2分别指向同一个字

符数组a,然后将p2指向字符数组a的最后一个元素,p1从数组a的首地址向后移动,p2从数组a的末地址向前移动,当p1的地址在p2之前时,交换地址的内容,即交换字符数组a的元素内容,从而实现数组a中的字符按相反顺序存放。结果

如下:esenihC目录04指针和数组指针和数组在C++中,若设数组名为a,则下标运算符“[]”具有下列含义:a[i]=*(a+i)由这个等式可知:当i=0时,a[0]=*(a+0)=*a,&a[0]=&(*a);从而a=&a[0]。也就是说,一维数组名a可以看成是一个指针。又由于数组定义

后,编译只为数组每个元素开辟相同大小的内存空间,但没有为数组名本身分配内存空间。事实上,下标运算符“[]”左边的操作对象除可以是指针常量外,还可以是指针变量,甚至是一个指针表达式。例如:(a+i)[j]=*((a+i)+j)=*(a+i+j

)=*(a+(i+j))=a[i+j]若当一个指针变量p指向一维数组a时,由于一维数组名是一个指针常量,因此它可以直接赋给指针变量p。即:inta[5];int*p=a;//或int*p=&a[0];此时,若有:*(p+1)=1;则和a[1]=1;是等价的。由于指针变量和数组的数组名在本质上

是一样,都是反映地址值。因此指向数组的指针变量实际上也可像数组变量那样使用下标,而数组变量又可像指针变量那样使用指针。例如:p[i]与*(p+i)及a[i]是等价的,*(a+i)与*(p+i)是等价的。指针和数组【例Ex_SumUsePoi

nter】用指针运算来计算数组元素的和#include<iostream>usingnamespacestd;intmain(){inta[6]={1,2,3,4,5,6};int*p=a;//用数组名a给指针初始化ints

um=0;for(inti=0;i<6;i++){sum+=*p;p++;}cout<<sum<<endl;//输出结果return0;}程序运行结果如下:21指针和数组设有二维数组a,它有2×3个元素,如下面的定义:inta[2]

[3]={{1,2,5},{7,9,11}};可以理解成:a是数组名,a数组包含两个元素a[0]、a[1],而每一个元素又是一个一维数组,例如a[0]有3个元素:a[0][0]、a[0][1]、a[0][2],它可以用一个指针来表示,例如:int*p1,*p2;p

1=a[0];p2=a[1];而数组名a代表整个二维数组的首地址,又可理解成是指向一维数组的指针的一维数组,也就是说a可以用指向指针的指针来表示:int**p;//该指针又称为二级指针p=a;其中,p[0]或*p等价于p1或a[0],p[1]或*(p+1)等价于p2或a[

1]。指针和数组【例Ex_MultiArrayAndPointer】分析下列程序的输出结果#include<iostream>usingnamespacestd;intmain(){inta[3][3]={1,2,3,4,5,6,7,8,9};inty=0;for(

inti=0;i<3;i++)for(intj=0;j<3;j++)y+=(*(a+i))[j];cout<<y<<endl;return0;}程序中,“y+=(*(a+i))[j];”是理解本程序的关键。事实上,*(a+i)就是a[i]

,因而(*(a+i))[j]就是a[i][j]。这里的“y+=(*(a+i))[j];”语句就是求数组a中各个元素之和。程序运行结果如下:45目录05指针和函数1.指针作为函数的参数2.返回指针的函数3.指向函数的指针指针和函

数1.指针作为函数的参数函数的参数可以是C++中任意的合法变量,自然,也可以是一个指针。如果函数的某个参数是指针,对这一个函数的调用就是传址调用,此时形参内容的改变必将影响实参。在实际应用中,函数可以通过指针类型的参数带回一个或多个值。【例Ex_SwapUsePointer】指针

作为函数参数的调用方式#include<iostream>usingnamespacestd;voidswap(int*x,int*y);intmain(){inta=7,b=11;swap(&a,&b);cout<<"a="<<a<<",b="<<b<<"\n";return0;}voidswa

p(int*x,int*y){inttemp;temp=*x;*x=*y;*y=temp;cout<<"x="<<*x<<",y="<<*y<<"\n";}指针和函数程序运行结果如下:x=11,y=7a=11,b=7这

里,将传递指针的swap函数调用的实现过程归纳如下:(1)函数声明中指明指针参数,即示例中的“voidswap(int*x,int*y);”;(2)函数调用的实参中指明变量的地址,即示例中的“swap(&a,&b);”;(3)函数定义中对形参进行间接访问,即对*x和*y的操

作,它实际上就是访问函数的实参变量a和b,通过局部变量temp的过渡,使变量a和b的值被修改。指针和函数2.返回指针的函数函数可以返回一个指针,如下面的格式:<函数类型>*<函数名>(<形式参数表>){<函数体>

}它与一般函数定义基本相同,只不过在函数名前面增加了一个“*”号,用来指明函数返回的是一个指针,该指针所指向的数据类型由函数类型决定。指针和函数【例Ex_PointerReturn】返回指针的函数:用来将一个字符串逆序输出#in

clude<iostream>usingnamespacestd;char*flip(char*str){char*p1,*p2,ch;p1=p2=str;while(*p2!='\0')p2++;p2--;while(p1<p2){ch=*p2;*p2=*p1;*p1=ch;//交换字符p

1++;p2--;}returnstr;}intmain(){charstr[]="ABCDEFGH";cout<<flip(str)<<"\n";return0;}程序运行结果如下:HGFEDCBA指针和函数3.指向函数的指针与变量相似,每一个函数都有地址。指向函数

地址的指针称为函数指针。在实际应用中,通过函数指针可以调用相应的函数。函数指针的定义如下:<函数类型>(*<指针名>)(<参数表>);例如:int(*func)(chara,charb);就是定义的一个函数指针。int为函数的返回类型,*表示后面的func是

一个指针变量名。该函数具有两个字符型参数a和b。需要说明的是,由于“()”的优先级大于“*”,所以下面是返回指针的函数定义而不是函数指针定义:int*func(chara,charb);指针和函数一旦定义了函数指针变量,就可以给它赋值。由于函数名表示该函数的入口地址,

因此可以将函数名直接赋给指向函数的指针变量。一般来说,赋给函数指针变量的函数的返回值类型与参数个数、顺序要和函数指针变量相同。例如:intfn1(chara,charb);int*fn2(chara,charb);intfn3(intn);int(*fp1)(charx,cha

ry);int(*fp2)(intx);fp1=fn1;//正确,fn1函数与指针fp1指向的函数一致fp1=fn2;//错误,fn2函数的返回值类型与指针fp1指向的函数不一致fp2=fn3;//正确,fn3函数与指针fp2指向的函数一致fp2=fp1;//错误,两个指针指向的函数不一致fp2=

fn3(5);//错误,函数赋给函数指针时,不能加括号函数指针变量赋值后,就可以使用指针来调用函数了。调用函数的格式如下:(*<指针名>)(<实数表>);或<指针名>(<实数表>);例如:(*fp2)(5);//或fp2(5);指针和函数【例Ex_FuncPointer1】函数

指针的使用#include<iostream>usingnamespacestd;doubleadd(doublex,doubley){return(x+y);}doublemul(doublex,doubley){return(x*y);}intmain(){double(*fu

nc)(double,double);//定义一个函数指针变量doublea,b;charop;cout<<"输入两个实数及操作方式,'+'表示'加','*'表示乘:";cin>>a>>b>>op;if(op=

='+')func=add;//将函数名赋给指针elsefunc=mul;cout<<a<<op<<b<<"="<<func(a,b)<<endl;//函数调用return0;}程序运行结果如下:输入两个实数及操作方式,'+'表示'加','*'表示乘:12.0␣25.5␣*

12*25.5=306函数指针变量可用作函数的参数。指针和函数【例Ex_FuncPointer2】函数指针变量可用作函数的参数#include<iostream>usingnamespacestd;doubleadd(doublex,doubley){return(x+y);}doublemul(

doublex,doubley){return(x*y);}voidop(double(*func)(double,double),doublex,doubley){cout<<"x="<<x<<",y="<<y<<",resu

lt="<<func(x,y)<<"\n";}intmain(){cout<<"使用加法函数:";op(add,3,7);cout<<"使用乘法函数:";op(mul,3,7);return0;}指针和函数程序运行结果如下:使用加法函数:x=3,y=7,resu

lt=10使用乘法函数:x=3,y=7,result=21代码中,op函数的第一个参数为函数指针,该指针指向的函数有两个double参数并返回double类型值。定义的add和mul函数也是有两个double参数并返回double类型值,因此它们

可以作为实参赋给函数指针func。与一般变量指针数组一样,函数指针也可构成指针数组。【例Ex_FuncPointerArray】函数指针数组的使用目录06new和deletenew和deleteC++运算符new和delete能有效地、直接地进行动态内存的分配和释放。运算符new返回

指定类型的一个指针,如果分配失败(如没有足够的内存空间)时则返回0(空指针)。例如:double*p;p=newdouble;*p=30.4;//将值存放在开辟的单元中系统自动根据double类型的空间大小开辟一个内存单元,并将地址放在指针p中。当然,也可在开

辟内存单元时,对单元里的值进行初始化。例如上述代码可写成:double*p;p=newdouble(30.4);运算符delete操作是释放new请求到的内存。例如:deletep;它的作用是释放p指针的内存单元,指

针变量p仍然有效,它可以重新指向另一个内存单元。new和delete需要注意的是:(1)new和delete必须配对使用。也就是说,用new为指针分配内存,当使用结束之后,一定要用delete来释放已分配的内存空间。(2)运算符delete必须用于先前new分配的

有效指针。如果delete了未定义的其他任何类型的指针,就会带来严重问题,如系统崩溃等。(3)new可以为数组分配内存,但当释放时,也可告诉delete数组有多少个元素。例如:int*p;p=newint[10];//分配整型数组的内存,

数组中有10个元素if(!p){cout<<"内存分配失败!";exit(1);//中断程序执行}for(inti=0;i<10;i++)p[i]=i;//给数组赋值//…delete[10]p;//告诉delete数组有多少个元素,或delete[]p;目录07引用和引用传递1.

引用定义和使用2.引用传递引用和引用传递1.引用定义和使用定义引用类型变量,实质上是给一个已定义的变量起一个别名,系统不会为引用类型变量分配内存空间,只是使引用类型变量与其相关联的变量使用同一个内存空间。定义引用类型变量的一般格式为:<数据类型>&<引用名>=<变量名>或

<数据类型>&<引用名>(<变量名>)其中,变量名必须是一个已定义过的变量。例如:inta=3;int&ra=a;这样,ra就是一个引用,它是变量a的别名。所有对这个引用ra的操作,实质上就是对被引用对象a的操作。例如:ra=ra+2;

实质上是a加2,a的结果为5。引用和引用传递引用与指针的最大区别是:指针是一个变量,可以把它再赋值成指向别处的地址,而引用一旦初始化后,其地址不会再改变。当然,在使用引用时,还需要注意以下几方面。(1)定义引用类型变量时,必须将其初始化。而且引用变量类型

必须与为它初始化的变量类型相同。例如:floatfVal;int&rfVal=fVal;//错误:类型不同(2)若引用类型变量的初始化值是常数,则必须将该引用定义成const类型。例如:constint&ref

=2;//const类型的引用(3)可以引用一个结构体(以后讨论),但不能引用一个数组,这是因为数组是某个数据类型元素的集合,数组名表示该元素集合空间的起始地址,它自己不是一个真正的数据类型。例如:inta[10];in

t&ra=a;//错误:不能建立数组的引用(4)引用本身不是一种数据类型,所以没有引用的引用,也没有引用的指针。例如:inta;int&ra=a;int&rra=ra;//正确,变量a的另一个引用int&*p=&ra;//错误:企图定义一个引用的指针引

用和引用传递2.引用传递【例Ex_SwapUseReference】引用作为函数参数的调用方式#include<iostream>usingnamespacestd;voidswap(int&x,int&y){inttemp;temp=x;x=y;y=te

mp;cout<<"x="<<x<<",y="<<y<<"\n";}intmain(){inta(7),b(11);swap(a,b);cout<<"a="<<a<<",b="<<b<<"\n";return0;}程序运行结果如下:x=11,y=7a=11,b=7函数swap

中的&x和&y就是形参的引用说明。VisualC++实用教程(VisualStudio版)(第6版)第1章基本C++语言——字符指针和字符串处理目录01字符指针字符指针当一个指针定义时指定的类型是char*时,则这样定义的指针为字符指针。与普通指针变量一

样,在C++中定义一个字符指针变量(指针)的格式如下:char*<指针名1>[,*<指针名2>,...];例如:char*str1,*str2;//字符指针则定义的str1和str2都是字符指针变量。对于字符指针变量的初始化,可以用字符串常量或一维字符数组进行。一个字符串常量由于自身有一个地

址,因而它可直接赋给一个字符指针变量。例如:char*p1="Hello";或char*p1;p1="Hello";都使字符指针变量p1指向“Hello”字符串常量。由于一维字符数组的数组名是一个指向字符串的指针常量,因此它也可用于字符指针变量的初始化或

赋值操作。例如:char*p1,str[]="Hello";p1=str;则使字符指针变量p1指向字符数组str,而str存放的内容是“Hello”字符串常量,因此这种赋值实际上是使p1间接指向“Hello”字符串常量。字符指针字符指针一旦初始化或赋初值后,就可在程序中使用它,

并且以前讨论过的指针操作都可以用于字符指针。例如,下面的示例是将一个字符串逆序输出。【例Ex_StrInv】字符串逆序输出#include<iostream>usingnamespacestd;intmain(){char*

p1="ABCDEFG",*p2=p1;while(*p1!='\0')p1++;/*将指针指向字符常量最后的结束符*/while(p2<=p1--)cout<<*p1;cout<<endl;return0;}程序运行结

果如下:GFEDCBA目录02带参数的main函数带参数的main函数到目前为止,所接触到的main函数都是不带参数的。但在实际应用中,程序有时需要从命令行输入参数。例如:c:\>copyfile1file2这是一个常用的DOS命令。当它运行时,操作系统将命令行参数以字符串的形式传递给mai

n。为了能使程序处理这些参数,需要main带有参数,其最常用的格式是:intmain(intargc,char*argv[])参数列表中,第一个int型参数用来存放命令行参数的个数,实际上argc所存放的数值比命令行参数的个数多1,即将命令字(或称为可执行文件名,如copy)也

计算在内。第二个参数argv是一个一维的指针数组,用来存放命令行中各个参数和命令字的字符串,且规定:argv[0]存放命令字argv[1]存放命令行中第一个参数argv[2]存放命令行中第二个参数argv[3]存放命令行中

第三个参数…带参数的main函数【例Ex_Main】处理命令行参数#include<iostream>usingnamespacestd;intmain(intargc,char*argv[]){cout<<"这个程序的程序名是:"<<argv[0]<<"\n";if(a

rgc<=1)cout<<"没有参数!";else{intnCount=1;while(nCount<argc){cout<<"第"<<nCount<<"个参数是:"<<argv[nCount]<<"\n";nCount++;}}return0;}程序编译连接后

,将Ex_Main.exe复制到C盘,然后切换到DOS命令提示符,输入:C:\>Ex_Main␣ab␣cd␣E␣F则运行结果为这个程序的程序名是:Ex_Main第1个参数是:ab第2个参数是:cd第3个参数是:E第4个参数是:F目录03字符串

处理函数1.strcat和strncat2.strcpy和strncpy3.strcmp和strncmp字符串处理函数1.strcat和strncat函数strcat是“string(字符串)catenate(连接)”的简写,其作用是将两个字

符串连接起来,形成一个新的字符串。它的函数原型如下:char*strcat(char*dest,constchar*src);其功能是将参数src指定的字符串连接到由参数dest指定的字符串的末尾,连接成新的字符串由参数dest返回。函数成功调用后,返回指

向dest内存空间的指针,否则返回空指针NULL。例如:chars1[50]="good";chars2[]="morning";strcat(s1,s2);cout<<s1;结果输出goodmorning。需要说明的是,dest指向的内存空间必须足够大,且是可写的,以便能存下连接的新的字符

串。这就是说,dest位置处的实参不能是字符串常量,也不能是const字符指针。尽管dest和src指定的字符串都有'\0',但连接的时候,dest字符串后面的'\0'被清除,这样连接后的新字符串只有末尾仍保留'\0'结束符。在cstring头文件中,还有一个strncat

函数,其作用也是连接两个字符串,其函数原型如下:char*strncat(char*dest,constchar*src,size_tmaxlen);只不过,它还限定了连接到dest的字符串src的最大字符个数maxlen。字符串处理函数2.strcpy和strncpy函数strcp

y是“stringcopy(字符串复制)”的简写,用于字符串的“赋值”。其函数原型如下:char*strcpy(char*dest,constchar*src);其功能是将参数src指定的字符串复制到由参数dest指定的内存空间中,包括结尾的字符串结束符'\

0'。复制后的字符串由参数dest返回。函数成功调用后,返回指向dest内存空间的指针,否则返回空指针NULL。例如:chars1[50];chars2[]="word";strcpy(s1,s2);cout<<s1;结果输出word,说明s

trcpy已经将s2的字符串复制到了s1中。需要说明的是,复制是内存空间的写入操作,因而需要dest所指向的内存空间足够大,且内存空间是可写入的,以便能容纳被复制的字符串src。要注意,dest所指向的内存空间的大小至少是src字符个数+1,因为末尾还有一个结束符'\0'。

例如,下面的错误代码比较隐蔽:chars2[]="ABC";chars1[3];strcpy(s1,s2);cout<<s1;字符串处理函数不要试图通过指针的指向改变来复制字符串。例如,下面的代码都不是真正的复制:chars2[]="ABC";chars1[10],*ps

tr;s1=s2;/*错误:s1是指针常量,不能作为左值*/pstr=s1;/*pstr指向s1内存空间*/pstr=s2;/*pstr指向s2内存空间*/cout<<s1;虽然输出的结果也是ABC,看似复制成功,但事实上只是pstr指向s2内存空间,并非s1内存空间的

内容是字符串“ABC”。可以使用strncpy函数来限制被复制的字符串src的字符个数。strncpy函数原型如下:char*strncpy(char*dest,constchar*src,size_tmaxlen);其中

,maxlen用来指定被复制字符串src的最大字符个数(不含结束符'\0')。若字符串src字符个数小于或等于maxlen,则等同于strcpy。若字符串src字符个数大于maxlen,则只有字符串src的前maxlen个字符连同结束符'\0'被复制到dest指定的内存空间中。字符串处理

函数3.strcmp和strncmpstring.h头文件中定义的函数strcmp是“stringcompare(字符串比较)”的简写,用于两个字符串的“比较”。其函数原型如下:intstrcmp(constchar*s1

,constchar*s2);其功能是:如果字符串s1和字符串s2完全相等,则函数返回0;如果字符串s1大于字符串s2,则函数返回一个正整数;如果字符串s1小于字符串s2,则函数返回一个负整数。在strcmp函数中,字符串比较的规则是:将两个字符串从左至右逐个字符按照A

SCII码值的大小进行比较,直到出现ASCII码值不相等的字符或遇到'\0'为止。如果所有字符的ASCII码值都相等,则这两个字符串相等。如果出现了不相等的字符,以第一个不相等字符的ASCII码值比较结

果为准。需要说明的是,在字符串比较操作中,不能直接使用“关系运算符”来比较两个字符数组名或字符串常量或字符指针来决定字符串本身是否相等、大于或小于等。例如:chars1[100],s2[100];cin>>s1>>s2;if(s1==s2)cout<<"same!"<<endl;则这

种比较只是比较s1和s2所在的内存空间的首地址,并非是字符串内容的比较。可以使用strncmp函数来限制两个字符串比较的字符个数。strncmp函数原型如下:intstrncmp(constchar*s1,constchar*s2,size_tmaxlen

);其中,maxlen用来指定两个字符串比较的最大字符个数。VisualC++实用教程(VisualStudio版)(第6版)第1章基本C++语言——结构、共用和自定义目录01结构体1.结构体声明2.结构体变量的定义3.结构体变量的初始化4.结构类型变量的引用结构体1.结构体声明在C+

+中,结构体的声明可按下列格式进行:struct[结构体名]{<成员定义1>;<成员定义2>;…<成员定义n>;};结构体声明是以关键字struct开始的,结构体名应是一个有效的合法的标识符,若该结构体以后不再定义变量,则结构体名也可不指定。结构体中的每个成员都必须通过成员定义来确定其数据类型

和成员名。要注意以下几方面。(1)成员的数据类型可以是基本数据类型,也可以是数组、结构体等构造类型或其他已声明的合法的数据类型。(2)结构体的声明仅仅是一个数据类型的说明,编译不会为其分配内存空间,只有当用结构体数据类型定义结构体变量时,编译才会为这种变量分配内存空间。(3)由于结构体声

明是一条语句,因而最后的分号“;”不能漏掉。结构体例如,若声明的学生成绩结构体为:structSTUDENT{intno;//学号floatscore[3];//三门课程成绩floatedit[3];//三门课程的学分floattotal,ave;//总成绩和平均成绩floa

talledit;//总学分};//分号不能漏掉则结构体中的成员变量有no(学号)、score[3](三门课程成绩)、edit[3](三门课程的学分)、total(总成绩)、ave(平均成绩)和alledit(总学分)。需要说明的是,在结构体中,成员变量定义与一般变量定义

规则相同。若多个成员变量的数据类型相同,还可写在一行定义语句中,如total和ave成员变量的定义。结构体2.结构体变量的定义在C++中,定义一个结构体变量可有三种方式。(1)先声明结构体类型,再定义结构体变量,称为声明之后定义方式(推荐方式)。这种方式与基本数据类型变量定义格式相同,即[s

truct]<结构类型名><变量名1>[,<变量名2>,…<变量名n>];例如:structSTUDENTstu1,stu2;其中,结构体名STUDENT前面的关键字struct可以省略。(2)在结构体类型声明的同时定义结构体变

量,称为声明之时定义方式。这种方式是将结构体类型的声明和变量的定义同时进行。在格式上,被定义的结构体变量名应写在最后花括号和分号之间,多个变量名之间要用逗号隔开。例如:structSTUDENT{//…}stu1,stu2;//定义结构体变量(3)在声明结构体类型时,省略结构体名

,直接定义结构体变量。由于这种方式一般只用于程序不再二次使用该结构体类型的场合,因此称这种方式为一次性定义方式。例如:struct{//…}stu1,stu2;//定义结构体变量结构体3.结构体变量的初始化

与一般变量和数组一样,结构体变量也允许在定义的同时赋初值,即结构体变量的初始化,其一般形式是在定义的结构体变量后面加上“={<初值列表>};”。例如:STUDENTstu1={1001,90,95,75,3

,2,2};它是将花括号中的初值按其成员变量定义的顺序依次给成员变量赋初值,也就是说,此时stu1中的no=1001,score[0]=90,score[1]=95,score[2]=75,edit[0]=3,edit[1]=2,edi

t[2]=2。由于其他成员变量的初值未被指定,因此它们的值是默认值或不确定。需要说明的是,可以在上述stu1的初值列表中,适当地增加一些花括号,以增加可读性,例如stu1的成员score和edit都是一维数组,因此可以这样初始化:STUDENTstu1={1001,{90

,95,75},{3,2,2}};结构体4.结构类型变量的引用当一个结构体变量定义之后,就可引用这个变量。使用时,遵循下列规则。(1)只能引用结构体变量中的成员变量,并采用下列格式:<结构体变量名>.<成员变量名>例如:structPOINT{intx,y;}spot={20,30};

cout<<spot.x<<spot.y;其中,“.”是成员运算符,它的优先级很高,仅次于域作用符“::”,因而可以把spot.x和spot.y作为一个整体来看待,它可以像普通变量那样进行赋值或进行其他各种运算。结构体(2)若成员本身又是一个结构体变量,则引用时需要

用多个成员运算符一级一级地找到最低一级的成员。例如:structRECT{POINTptLeftTop;POINTptRightDown;}rc={{10,20},{40,50}};则有cout<<r

c.ptLeftTop.x<<rc.ptLeftTop.y;(3)多数情况下,类型相同的结构体变量之间可以直接赋值,这种赋值等效于各个成员的依次赋值。如:structPOINT{intx,y;};POINTpt1={10,20};POINTpt

2=pt1;//将pt1直接赋给pt2cout<<pt2.x<<"\t"<<pt2.y<<endl;//输出1020其中,pt2=pt1等效于:pt2.x=pt1.x;pt2.y=pt1.y;目录02结构体数组1.结构体数组的初始化2.结构体数组元素的引用结

构体数组1.结构体数组的初始化由于结构体类型声明的是一条记录信息,而一条记录在二维线性表中就表示一个行,因此一维结构体数组的初始化的形式应与二维普通数组相同。例如:structSTUDENT{intno;//学号floatscore[3]

;//三门课程成绩floatedit[3];//三门课程的学分floattotal,ave;//总成绩和平均成绩floatalledit;//总学分};STUDENTstu[3]={{1001,90,9

5,75,3,2,2},{1002,80,90,78,3,2,2},{1003,75,80,72,3,2,2}};此时初值中的花括号起到类似二维数组中的行的作用,并与二维数组初始化中的花括号的使用规则相同。结构体数组2.结构体数组元素的引用一旦定义结构体数组后,就可以在程

序中引用结构体数组元素。由于结构体数组元素等同于一个同类型的结构体变量,因此它的引用与结构体变量相类似,如下列格式:<结构体数组名>[<下标表达式>].<成员>例如:for(inti=0;i<sizeof(s

tu)/sizeof(STUDENT);i++){stu[i].total=stu[i].score[0]+stu[i].score[1]+stu[i].score[2];stu[i].ave=stu[i].total/3.0

;stu[i].alledit=stu[i].edit[0]+stu[i].edit[1]+stu[i].edit[2];if(stu[i].ave>stu[nMax].ave)nMax=i;}目录03结

构体与函数结构体与函数当结构体变量作为函数的参数时,它与普通变量一样,由于结构体变量不是地址,因此这种传递是值传递方式,整个结构体都将被复制到形参中去。【例Ex_StructValue】将结构体的值作为参数传给函数#includ

e<iostream>usingnamespacestd;structPERSON{intage;//年龄floatweight;//体重charname[25];//姓名};voidprint(PERSONone){cou

t<<one.name<<"\t"<<one.age<<"\t"<<one.weight<<"\n";}PERSONall[4]={{20,60,"Zhang"},{28,50,"Fang"},{33,78,"Ding"},{19,65,"Chen"}};

intmain(){for(inti=0;i<4;i++)print(all[i]);return0;}结构体与函数程序运行结果如下:Zhang2060Fang2850Ding3378Chen1965print函数的参数是结构体PERSON变量,main函数调用了4次p

rint函数,实参为结构体PERSON数组的元素。事实上,结构体还可以作为一个函数的返回值。目录04结构体指针结构体指针当定义一个指针变量的数据类型是结构体类型时,则这样的指针变量就称为结构体指针变量,它指向结构体变量。【例Ex_StructPointer】指针在结构体中的应用#in

clude<iostream>#include<cstring>usingnamespacestd;structPERSON{intage;//年龄charsex;//性别floatweight;//体重charname[25];//姓名};intmain(){structPERSONone;

structPERSON*p;//指向PERSON类型的指针变量p=&one;p->age=32;p->sex='M';p->weight=(float)80.2;strcpy(p->name,"LiMing");cout<<"姓名:"<<(*

p).name<<endl;cout<<"性别:"<<(*p).sex<<endl;cout<<"年龄:"<<(*p).age<<endl;cout<<"体重(kg):"<<(*p).weight<<endl

;return0;}结构体指针程序运行结果如下:姓名:LiMing性别:M年龄:32体重(kg):80.2程序中,“->”称为指向运算符,如p->name,它和(*p).name是等价的,都是引用结构体PERSON变量one中的

成员name。由于成员运算符“.”优先于“*”运算符,所以(*p).name中*p两侧的括号不能省,否则*p.name与*(p.name)等价,但这里的*(p.name)是错误的。实际上,指向结构体变量数组的指针操作和指向一般数组的指针操作是一样的。例如若有:P

ERSONmany[10],*pp;pp=many;//等价于pp=&many[0];则pp+i与many+i是等价的,(pp+i)->name与many[i].name是等价的,等等。目录05共用体共用体定义一个共用体可用下列格式:union<共用体名>{<成员定义1>;<成员定义2>;…<成

员定义n>;}[共用体变量名表];//注意最后的分号不要忘记例如:unionNumericType{intiValue;//整型变量,4字节长longlValue;//长整型变量,4字节长floatfValue;/

/实型,8字节长};这时,系统为NumericType开辟了8字节的内存空间,因为成员fValue是实型,故它所占空间最大。需要说明的是,共用体除了关键字(union)与结构体不同外,其使用方法均与结构

体相同。目录06使用typedef1.为基本数据类型添加新的类型名2.为数组类型增加新的类型名3.为结构体增加新的类型名4.为指针类型名增加新的类型名称使用typedef1.为基本数据类型添加新的类型名当使用typedef为基本数据类型名添加新的名称时,可使用下列格式:ty

pedef<基本数据类型名><新的类型名>;其功能是将新的类型名赋予基本数据类型的含义。其中,基本数据类型名可以是char、short、int、long、float、double等,也可以是带有const、unsigned或其他修饰符的基本类型名。例如:typedefintInt;typedefu

nsignedintUInt;typedefconstintCInt;使用typedef书写时,typedef以及类型名之间必须有一个或多个空格,且一条typedef语句只能定义一个新的类型名。这样,上述3条typedef语句就使在原先基本数据类型名的基础

上增加了Int、UInt和CInt类型名。之后,就可直接使用这些新的类型名来定义变量了。例如:UInta,b;//等效于unsignedinta,b;CIntc=8;//等效于constinta=8;再如,若有typedefshortInt16;typedefint

Int32;则新的类型名Int16和Int32可分别反映16位和32位的整型。这在32位系统中类型名和实际是吻合的。若在16位系统中,为了使Int16和Int32也具有上述含义,则可用typedef语句重新定义:typedefintInt16;typedefl

ongInt32;这样就保证了程序的可移植性。使用typedef2.为数组类型增加新的类型名当使用typedef为数组类型增加新的名称时,可使用下列格式:typedef<数组类型名><新的类型名>[<下标>];其功能是将新的类型名

作为一个数组类型名,下标用来指定数组的大小。例如:typedefintInts[10];typedeffloatFloats[20];则新的类型名Ints和Floats分别表示具有10个元素的整型数组类型和具有20个元素的单精度实型数组

类型。这样,就可有:Intsa;//等效于inta[10];Floatsb;//等效于floatb[20];使用typedef3.为结构体增加新的类型名当使用typedef为结构体增加新的类型名称时,可使用下列格式:typedefstru

ct[结构体名]{…}<新的类型名>;这种格式是在结构体声明的同时进行的,其功能是将新类型名作为此结构体的一个新名称。例如:typedefstructstudent{…}STUDENT;STUDENTstu1;//等效于structstudentstu

1;使用typedef4.为指针类型名增加新的类型名称由于指针类型不容易理解,因此typedef常用于指针类型名的重新命名。例如:typedefint*PInt;typedeffloat*PFloat;typedefchar*String;PInta,b;/

/等效于int*a,*b;则PInt、PFloat和String分别被声明成整型指针类型名、单精度实型指针类型名和字符指针类型名。由于字符指针类型常用来操作一个字符串,因此常将字符指针类型名声明为String或STR。可见,用typedef为一个已有

的类型名声明新的类型名称的一般步骤如下。(1)用已有的类型名写出定义一个变量的格式,例如:inta;(2)在格式中将变量名换成要声明的新的类型名称,例如:intInt;(3)在最前面添加上关键字typedef即可完成声明。例如:typedefintInt;(4)之

后,就可使用新的类型名定义变量了。需要说明的是,与struct、enum和union构造类型不同的是,typedef不能用于定义变量,也不会产生新的数据类型,它所声明的仅仅是一个已有数据类型的别名。

小橙橙
小橙橙
文档分享,欢迎浏览!
  • 文档 25747
  • 被下载 7
  • 被收藏 0
相关资源
广告代码123
若发现您的权益受到侵害,请立即联系客服,我们会尽快为您处理。侵权客服QQ:395972555 (支持时间:9:00-21:00) 公众号
Powered by 太赞文库
×
确认删除?