第三讲C++对C的扩充2文档格式.docx
- 文档编号:21150046
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:15
- 大小:37.78KB
第三讲C++对C的扩充2文档格式.docx
《第三讲C++对C的扩充2文档格式.docx》由会员分享,可在线阅读,更多相关《第三讲C++对C的扩充2文档格式.docx(15页珍藏版)》请在冰豆网上搜索。
可以这样写:
inta;
int&
b=a;
//声明b是一个整型变量的引用变量,它被初始化为a
注意:
1、在上述声明中,&
是“引用声明符”,此时它并不代表地址。
不要理解为“把a的值赋给b的地址”。
对变量声明一个引用,并不另开辟内存单元,b和a都代表同一变量单元。
在声明一个引用时,必须同时使之初始化,即声明它代表哪一个变量。
2、由于引用不是独立的变量,编译系统不给它单独分配存储单元,因此在建立引用时只有声明,没有定义,只是声明它和原有的某一变量的关系。
3、声明一个变量的引用后,在本函数执行期间,该引用一直与其代表的变量相联系,不能再作为其他变量的别名。
下面的用法不对:
inta1,a2;
b=a1;
//使b成为变量a1的引用(别名)
b=a2;
//又企图使b成为变量a2的引用(别名)是不行的
2.引用的简单使用
通过下面的例子可以了解引用的简单使用。
例9了解引用和变量的关系。
#include<
iostream>
usingnamespacestd;
intmain()
{inta=10;
b=a;
//声明b是a的引用
a=a*a;
//a的值变化了,b的值也应一起变化
cout<
<
a<
"
"
b<
endl;
b=b/5;
//b的值变化了,a的值也应一起变化
return0;
}
a的值开始为1O,b是a的引用,它的值当然也应该是10,当a的值变为100(a。
a的值)时,b的值也随之变为100,在输出a和b的值后,b的值变为20,显然a的值也应为20。
运行记录如下:
100100
2020
3.关于引用的简单说明
(1)引用并不是一种独立的数据类型,它必须与某一种类型的数据相联系。
声明引用时必须指定它代表的是哪个变量,即对它初始化。
(2)引用与其所代表的变量共享同一内存单元,系统并不为引用另外分配存储空间。
实际上,编译系统使引用和其代表的变量具有相同的地址。
(3)当看到&
a这样的形式时,怎样区别是声明引用变量还是取地址的操作呢?
请记住,当及a的前面有类型符时(如int
&
a),它必然是对引用的声明;
如果前面没有类型符(如p=&
a),此时的&
是取地址运算符。
(4)对引用的初始化,可以用一个变量名,也可以用另一个引用。
(5)引用在初始化后不能再被重新声明为另一变量的别名。
实际上,在C++程序中很少使用独立变量的引用,如果要使用某一个变量,就直接使用它的原名,没有必要故意使用它的别名。
前面举的例子只是为了说明引用的特征和基本的用法。
那么有了变量名,为什么还需要一个别名呢?
4.将引用作为函数参数
C++之所以增加“引用”,主要是利用它作为函数参数,以扩充函数传递数据的功能。
在C语言中,函数的参数传递有以下两种情况。
(1)将变量名作为实参。
这时传给形参的是变量的值。
传递是单向的,在执行函数期间形参值发生变化并不传回给实参,因为在调用函数时,形参和实参不是同一个存储单元。
下面的程序无法实现两个变量的值互换。
例10无法实现两个变量的值互换的程序。
voidswap(inta,intb)
{inttemp;
temp=a;
a=b;
b=temp;
//实现a和b的值互换
{
inti=3,j=5;
swap(i,j);
i<
"
j<
//i和j的值未互换
}
输出i和j的值仍为3和5。
见图2,图2(a)表示调用函数时的数据传递,图2(b)是执行swap函数体后的情况,a和b值的改变不会影响i和j的值。
图2:
i、j值未交换,
图3:
i、j值交换,
(2)传递变量的指针。
为了解决上面这个问题,在C程序中可以用传递变量地址的方法。
使形参得到一个变量的地址,这时形参指针变量指向实参变量单元。
例11使用指针变量作形参,实现两个变量的值互换。
voidswap(int*p1,int*p2)
inttemp;
temp=*p1;
*p1=*p2;
*p2=temp;
swap(&
i,&
j);
(3)传送变量的别名。
C++把变量的引用作为函数形参,就弥补了上面的不足。
这就是向函数传递数据的第三种方法,即传送变量的别名。
例12利用“引用形参”实现两个变量的值互换。
voidswap(int&
a,int&
b)
i="
j="
输出结果为i=5j=3
图4:
别名实现变量的交换
分析使用引用和使用指针变量作函数形参有什么不同?
可以发现:
①不必在swap函数中设立指针变量,指针变量要另外开辟内存单元,其内容是地址。
而引用不是一个独立的变量,不单独占内存单元,在本例中其值为一整数。
②在main函数中调用swap函数时实参不必在变量名前加&
以表示地址。
这种传递方式相当于Pascal语言中的“变量形参”,系统传送的是实参的地址而不是实参的值。
③使用指针变量时,为了表示指针变量所指向的变量,必须使用指针运算符。
(如例11程序内swap函数中的。
pl,*p2),而使用引用时,引用就代表该变量,不必使用指针运算符*(见例12程序内swap函数)。
对比例11和例12中的swap函数,可以发现例12中的swap函数比例11中的swap函数简单。
④用引用能完成的工作,用指针也能完成。
但引用比指针的使用直观、方便,直截了当,不必“兜圈子”,容易理解。
有些过去只能用指针来处理的问题,现在可以用引用来代替,从而降低了程序设计的难度。
5.对引用的进一步说明
(1)不能建立void类型的引用,如:
void&
a=9;
//错误
因为任何实际存在的变量都是属于非void类型的,void的含义是无类型或空类型,void只是在语法上相当于一个类型而已。
(2)不能建立引用的数组。
charc[6]="
hello"
;
char&
rc[6]=c;
企图建立一个包含6个元素的引用的数组,这样是不行的,数组名C只代表数组首元素的地址,本身并不是一个占有存储空间的变量。
(3)可以将变量的引用的地址赋给一个指针,此时指针指向的是原来的变量。
如:
inta=3;
//定义a是整型变量
//声明b是整型变量的别名
int*P=&
b;
//指针变量p指向变量a的引用b,相当于指向a,合法
相当于p指向变量a,其作用与下面一行相同,
即:
int*p=&
a;
如果输出*p的值,就是b的值,也就是a的值。
但是不能定义指向引用类型的指针变量,不能写成:
*p=&
//企图定义指向引用类型的指针变量P,错误
由于引用不是一种独立的数据类型,因此不能建立指向引用类型的指针变量。
(4)可以建立指针变量的引用。
inti=5;
//定义整型变量i,初值为5
i
//定义指针变量P,指向i
int*&
pt=p;
//pt是一个指向整型变量的指针变量的引用,初始化为p
从定义的形式可以看出,&
pt表示pt是一个变量的引用,它代表一个int,类型的数据对象(即指针变量),如果输出。
pt的值,就是*p的值5。
(5)可以用const对引用加以限定,不允许改变该引用的值。
inti=5;
//定义整型变量i,初值为5
constint&
a=i;
//声明常引用,不允许改变a的值
a=3;
//企图改变引用a的值,错误
但是它并不阻止改变引用所代表的变量的值,如
i=3;
//合法
此时输出i和a的值都是3。
这一特征在使用引用作为函数形参时是有用的,因为有时希望保护形参的值不被改变,在第3章中将会看到它的应用。
(6)可以用常量或表达式对引用进行初始化,但此时必须用const作声明。
const&
a=i+3;
//合法
此时编译系统是这样处理的:
生成一个临时变量,用来存放该表达式的值,引用是该临时变量的别名。
系统将"
const=&
a=i+3"
转换为:
inttemp=i+3;
//先将表达式的值存放在临时变量temp中
constint&
a=temp;
//声明a是temp的别名
此时如果输出引用a的值,将是3而不是3.1415926。
因为从根本来说,只能对变量建立引用。
如果在上面声明引用时不用const,则会发生错误。
如
doubled=3.1415926;
//d是double类型变量
int&
a=d;
//未加const,错误
为什么呢?
若允许这样做的话,如果修改了引用a的值(例如a=6.28;
),则临时变量temp的值也变为6,即修改了临时变量temp的值,但不能修改变量d的值,这往往不是用户所希望的,即存在二义性。
与其允许修改引用的值而不能实现用户的目的,还不如不允许修改引用的值。
这就是c++规定对这类引用必须加const的原因。
C++提供的引用机制是非常有用的,尤其用作函数参数时,比用指针简单、易于理解,而且可以减少出错机会,提高程序的执行效率,在许多情况下能代替指针的操作。
在本书的第3章和第4章中会有具体的使用例子。
八、内置函数
调用函数时需要一定的时间,如果有的函数需要频繁使用,则累计所用时间会很长,从而降低程序的执行效率,C++提供一种提高效率的方法,即在编译时将所调用函数的代码嵌入到主函数中。
这种嵌入到主函数中的函数称为内置函数(inlinefunction),又称内嵌函数。
在有些书中把它译成内联函数。
指定内置函数的方法很简单,只须在函数首行的左端加一个关键字inline即可。
例13将函数指定为内置函数。
inlineintmax(inta,intb,intc)//这是一个内置函数,求3个整数中的最大者
if(b>
a)a=b;
if(c>
a)a=c;
returna;
}
{inti=7,j=10,k=25,m;
m=max(i,j,k);
max="
m<
由于在定义函数时指定它为内置函数,因此编译系统在遇到函数调用nmax(i,j,k)时,就用max函数体的代码代替max(i,j,k),同时将实参代替形参。
这样,m=max(i,j,k)就被置换成
b=j;
c=k;
if(b>
a)a=b;
if(c>
a)a=c;
m=a;
内置函数与用#define命令实现的带参宏定义有些相似,但不完全相同。
宏定义是在编译前由预处理程序对其预处理的,它只作简单的字符置换而不作语法检查,往往会出现意想不到的错误。
例14用带参宏定义实现求平方值,
#definepower(x)x*x
intmain()
{cout<
power
(2)<
power(1+1)<
本来程序编写者希望两个cout语句都输出2的平方值,但运行结果却是:
4(输出power(g)的值)
3(输出power(1+1)的值)
第2个结果显然不是程序设计者所希望的,原因是在进行宏替换时只是简单地将字符“1+l”取代x,因此power(1+1)被置换为1+1*l+1,结果为3。
如果不用#define而用内置函数,也可以达到同样的目的,但避免了上面的副作用。
例14程序可改为:
例15用内置函数实现求平方值。
#inclde<
useingnamespacestd;
inlineintpower(intx)//改用内置函数
{
returnx*x;
intmain()
{cout<
power
(2)<
endl;
cout<
returnO;
运行结果是
4(输出power
(2)的值)
4(输出power(1+1)的值)
可以看到:
1、用带参宏定义和内置函数都可以实行置换,但具体的做法不同,用内置函数可以达到用#define宏置换的门的,但不会出现带参宏定义的副作用。
2、使用内置函数可以节省运行时间,但却增加了目标程序的长度。
九、作用域运算符
每一个变量都有其确有效的作用域,只能在变量的作用域内使用该变量,不能直接使用其他作用域中的变量。
见例6。
例16局部变量和全局变量同名。
floata=13.5;
//全局变量a
intmain()
{
inta=5;
//主函数内变量a
//输出5
:
//输出13.5
“:
”a表示全局作用域中的变量a。
请注意:
不能用“:
”访问函数中的局部变量。
十、字符串变量
除了可以使用字符数组处理字符串外,C++还提供了一种更方便的方法—用字符串类型(string类型)定义字符串变量。
实际上,string并不是C++语言本身具有的基本类型(而char,int,float,double等是C++本身提供的基本类型),它是在c++标准库中声明的一个字符串类,用这种类可以定义对象。
1.定义字符串变量
和其他类型变量一样,字符串变量必须先定义后使用,定义字符串变量要用类名strmg。
如:
stringstringl;
//定义stringl为字符串变量
stringstring2="
China"
//定义string2同时对其初始化
可以看出,这和定义char,int,float,double等类型变量的方法是类似的。
应当注意:
要使用string类的功能时,必须在本文件的开头将c++标准库中的“string”头文件包含进来,即应加上#include<
string>
//注意头文件名不是"
string.h这一点是与定义基本数据类型变量所不同的。
2.对字符串变量的赋值
在定义了字符串变量后,可以用赋值语句对它赋以一个字符串常量,
string1="
Canada"
而用字符数组时是不能像下面这样做的
charstr[10];
str="
Hello!
既可以用字符串常量给字符串变量赋值,也可以用一个字符串变量给另一个字符串变量赋值。
string2=stringl;
//假设string2.和stringl均已定义为字符串变量
可以对字符串变量中某一字符进行操作,如
stringword="
Then"
;
//定义并初始化字符串变量word
word[2]='
a'
//修改序号为2的字符,修改后word的值为"
Than"
前面已说明,字符串常量以“\o”作为结束符,但将字符串常量存放到字符串变量中时,只存放字符串本身而不包括“\o”。
因此字符串变量word中的字符为"
Than”(共4个字符)而不是"
再加“\0”。
3.字符串变量的输入输出
可以在输入输出语句中用字符串变量名输入输出字符串,如
cin>
>
string1;
//从键盘输入一个字符串给字符串变量stfingl
stHnS2;
//将字符串stnng2输出
4.字符串变量的运算
在用字符数组存放字符串时,字符串的运算要用字符串函数,如strcat(连接),strcmp(比较),strcpy(复制),而对stung类对象,可以不用这些函数,而直接用简单的运算符。
(1)用赋值运算符实现字符串复制
stringl=string2;
其作用与“strcpy(string1,string2);
”相同。
(2)用加法运算符实现字符串连接
stringstring1="
C++"
//定义string[并赋初值
Language"
//定义string2并赋初值
stnngl=string1十sane2;
//连接string1和string2
连接后string1为"
C++Language"
(3)用关系运算符实现字符串比较
可以直接用==(等于)、,(大于)、<
(小于)、!
=(不等于)、>
=(大于或等于)、<
=(小于或等于)等关系运算符来进行字符串的比较。
5.字符串数组
不仅可以用string定义字符串变量,也可以用string定义字符串数组。
stringname[5];
//定义一个字符串数组,它包含5个字符串元素
stringname[5]={"
Zhang"
,"
Li"
Fun"
Wang"
Tan"
};
//定义一个字符中数组并初始化此时name数组的状况如图5所示。
图5
可以看到:
(1)在一个字符串数组中包含若干个(今为5个)元素,每个元素相当于—个字符串变量。
(2)并不要求每个字符串元素具有相同的K度,即使对同一个元素而言,它的长度也是可以变化的,当向某一个元素重新赋值时,其长度就可能发生变化,,
(3)在字符串数组的每一个元素中存放一个字符串,而不是一个字符,这是字符串数组与字符数组的区别。
如果用字符数组存放字符串,一个元素只能存放一个字符,用一个一维字符数组存放一个字符申。
(4)每一个字符中元素中只包含字符串本身的字符而不包括"
\0"
可见用字符串数组存放字符串以及对字符串进行处理是很方便的,使用户感到更加直观,简化了操作,提高了效率。
例17输入3个字符串,要求按字母由小到大顺序输出。
对于将3个整数按由小到大顺序输出,是很容易处理的。
可以按照同样的算法将3个字符串按由小到大顺序输出。
程序如下:
stringstring1,string2,string3,temp;
pleaseinputthreestrings:
//这是对用户输入的提示
cin>
string1>
string2>
string3;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第三 C+ 扩充