目录
一.开始学习c++
1 .1.1注意c++是c语言的升级版,可以兼容绝大部分的c语言程序
c++注重面向对象编程,而c语言注重的是面相过程
c++对大小写敏感 编译器对拼写也是敏感的故文件拓展名一般用cpp
2.1.0新的开始
2.1.1输入和输出与main函数
输入用cin 输出用cout
控制符endl以及换行符/n的应用
endl表示重起一行 endl在头文件iostream中定义,位于名称空间std中
c语言的\n也可以使用
使用cin cout进行输入输出的程度必须包含文件<iostream>
2.1.2名称空间
如果使用iostream而不是iostream.h 则应使用名称空间编译指令 using namespace std;
来使iostream中的定义对程序可用 这叫做using编译指令 (名称空间那一节会详细解答)
二.数据处理
1变量和常量
1.1.0变量
变量定义和空间申请在同一时刻 而赋值不是
1.1.1变量类型
1.1.2常变量
eg const double pi = 3.14159;
必须在定义的时候赋值,并且在程序运算过程中不可变,编译器可以对长常变量进行类型检查。
1.1.3变量名
如果想用两个或者更多的单词组成一个名称,通常的做法是用下划线将单词分开或者从第二个单词或者两个单词第一个字母大写
1.1.3无符号类型变量
不能储存负值,优点是可以增大变量能够储存的最大值
eg 如果int表示范围是-32768到32767 那么无符号版本可以储存0到65535 只需要在前面加上unsigned 即可
1.2.0常量
1.2.1符号常量
eg #define PI 3.1415926
好处便于程序修改和维护 程序中遇到PI的地方会自动提高精度
1.2.2文字常量
程序运行中,值不能被改变的量称为常量。
文字常量是指可直接使用的常量。如代码中的数字。
文字常量存储在代码区,对它的访问不是通过地址进行的。
文字常量分为:整形、实型、字符型和字符串型常量。
1.2.3整型常量
1.2.4实型常量
实行说白了就是带小数点的,例如1.就是1.0 .123就是0.123 1e3就是1.0*10^3
注意 使用e的时候数字里面不能有空格
1.2.4字符型常量
与int不同char一般情况下既不是有符号型signed也不是无符号型unsigned
1.2.5转义字符
‘\12’=‘10‘根据ascii码表’10‘为/n
这两张图思考一下为什么会合并
1.2.6字符串常量
2.1.0数据的处理
2.1.1算数运算
取余运算符两边必须是整数
N是常量不可以被改变
2.2.1自增自减运算
2.2.2逻辑运算
2.2.3其它
&运算符可以检索变量的内存地址
2.2.4类型转换
对不同类型进行计算时,c++会自动进行类型转换,如以下情况
1將一种算术类型的值赋给另一种算术类型的变量时,C++将对值进行转换;
2表达式中包含不同的类型时,C++将对值进行转换;
3将参数传递给函数时,C++将对值进行转换;
然而也存在一些潜在的类型转换的问题 如图
传递参数时也会进行类型转换
还有强制类型转换
强制类型转换有两种表达方式 如果想要将储存在变量thorn中的int值转换为long类型 则有
(long)thorn 或者 long(thorn)
3.1.1补充:auto声明 可以让编译器根据初始值的类型推断变量的类型,那么编译器将把变量的类型设置为和初始值相同
auto n=100;//n is int
auto x=1.5;//x is double
auto y=1.3e12L;//y is long double
三.复合类型(数组 字符串 指针)
1.1.0数组
与c语言相通,数组array是一种数据格式,能够储存多个同类型的值
要创建数组 要声明以下三点:
1储存在每个元素种值的类型;2数组名;3数组的元素数;
声明数组的通常格式如下
typeName arrayName[arraySize];
表达式arraySize指定元素数目,它必须是整型常数,例如10或者是const,也可以是常量表达式例如8*szieof(int),即所有的值在编译时都是已经确定的,具体地说arraySize不能是变量,变量的值实在程序运行中设置的。 随后会有new来避开这种限制
1.2.1作为复合类型的数组
为什么说是复合类型 例如 float loans[20]; loans的类型并不是数组而是float数组,这强调了loans数组是使用float类型创建的;
c++数组从0开始编号(必须) int month[12];的第一个元素是month[0] 最后一个元素是month[11] 最后一个元素的索引比元素长度小1
sizeof运算符返回类型或数据对象的长度(单位为字节)。注意,如果将sizeof运算符用于数组名,得到的将是整个数组中的字节数。但如果将 sizeof 用于数组元素,则得到的将是元素的长层(单位为字节)。这表明 yams 是一个数组,而 yams[1]只是一个 int变量
1.3.1数组的初始化
只有在定义数组的时候才可以使用初始化,此后就不能使用了,也不能将一个数组赋值给另一个数组,如下
int cards[4]={1,2,3,4};\\okay
int hand[4];\\okay
hand[4]={5,6,7,8};\\not allowed
hand=cards;\\not allowed
初始化数组时 提供的值可以少于数组的元素数目;如果只有一部分初始化,那么编译器会将剩余元素设置为0;如果初始化时方括号为空[],那么编译器会自动计算元素个数;
2.1.0字符串
c++处理字符串的方式有两种,一种来自c语言 被称为c-风格字符串
c-风格字符串有一种特殊的性质 以空字符结尾,空字符被写作\n 其ASCII码为0 用来标记字符串的结尾
将数组初始化为字符串的工作看上去冗长乏味--使用大量单引号,且必须记住加上空字符。不必担心,有一种更好的、将字符数 组初始化为字符串的方法--只需使用一个用引号括起的字符串即可,这种字符串被称为字符串常量(stri ing constant)或字符串字面值(string literal),
char bird[11] = "Mr. Cheeps"; // the \0 is understood
char fish[] ="Bubbles"; // let the c compiler count
c++对字符串长度没有限制
在确定储存字符串的最短数组时 别忘了讲结尾的空字符计算在内
字符串常量(使用双引号) 不能与字符常量(使用单引号)互换
2.1.1拼接字符串常量
strlen()只计算可见的字符,不把空字符计算在内
2.1.2对行而不是对单词
仔细看下面这个例子
两种可以读取行而不是单词的方法——getline()和get() 区别 getline将丢弃换行符 而get保留
getline()
getlin()函数读取整行,它使用通过回车键输人的换行符来确定输人结尾。要调用这种方法,可以使用cin.getine()该函数有两个参数。第一个参数是用来存储输人行的数组的名称,第二个参数是要读取的字符数。如果这个参数为 20,则函数最多读取 19 个字符,余下的空间用于存储自动在结尾处添加的空字符getline()成员函数在读取指定数目的字符或遇到换行符时停止读取。
cin.getline(name,20);//对20个原色的name数组输入
get()
与getline的使用方法一样 不同点 get有一种变体可以不带任何参数读取下一行字符以此来应对换行符
2.1.3string类型
string类型隐藏了字符串的数组性质 ,让我们能够像处理变量一样处理字符串
string str1;
cin >> str1 ;
cout << str1;
程序可以自动处理string的大小,调节长度
string类函数 使用方法和C语言相同
3.1.0指针和自由存储空间
指针是一个变量,其储存的是值的地址,而不是值本身
如果想获取值的地址只需要使用地址运算符&就可以获取它的位置
使用常规变量时 值是指定的量 而地址为派生量
c++使用关键字new请求正确数量的内存以及使用指针来跟踪新分配的内存的位置
处理存储数据的新策略刚好相反,将地址视为指定的量,而将值视为派生量。一种特殊类型的变量指针用于储值的地址。因此,指针名表示的是地址。*运算符被称为间接值 (indirect value )或解除引用(dereferencing) 运算符,将其应用于指针,可以得到该地址处存储的值(这和乘法使用的符号相同;C++根据上下文来确定所指的是乘法还是解除引用)。例如,假设manly是一个指针,则&manly 表示的是个地址,而*manly 表示存储在该地址处的值。*manly 与常规 int 变量等效
指针声明必须指定指针指向的数据的类型
int* ptr;
对于每个指针变量名,都需要使用一个*
3.1.1指针的危险
危险更易发生在那些使用指针不仔细的人身上。极其重要的一点是:在C++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。为数据提供空间是一个独立的步骤,忽略这一步 无疑是自找麻烦,如下所示:
long * fellow; // create a pointer-to-1ong
*fellow=223323; // place a value in never-never land
fellow确实是一个指针,但它指向哪里呢?上述代码没有将地址赋给 fellow。那么223323 將被放在哪里呢?我们不知道。由于fellow 没有被初始化,它可能有任何值。不管值是什么,程序都将它解释为存储223323 的地址。如果fellow的值碰巧为 1200,计算机将把数据放在地址 1200 上,即使这恰巧是程序代码的地址。fellow指向的地方很可能并不是所要存储223323 的地方。这种错误可能会导致一些最隐匿、最难以跟踪的 bug
警告:一定要在对指针应用解除引用运算符(*),之前,将指针初始化为一个确定的、适当的地址。这是关于使用指针的金科玉律,
3.1.2指针和数字
要将数字值作为地址来使用,应该通过强制类型转换将数字转换为适当的地址类型
int* pt;
pt = (int*)0xB8000000;
3.2.1***使用new分配内存***
对于指针,需要指出的另一点是,new 分配的内存块通常与常规交量声明分配的内存块不同。变量 nighis和pd 的值都存储在被称为栈(staek)的内存区域中,而 new 从被称为堆(hesp)或自由存储区 (fee store)的内存区域分配内存
3.2.2使用delete释放内存
另一个方面是delete运算符 它使得在使用完内存后能将其还给内存池
int* ps = new int;
.........//use the memory
delete ps;
在编译时给数组分配内存被称为静态联编(static binding),意味着数组是在编译时加人到程序中的。但使用new时,如果在运行阶段需要数组,则创建它:如果不需要,则不创建。还可以在程序运行时选择数组的长度。这被称为动态联编(dynamie binding)。意味着数组是在程序运行时创建的。这种数组叫作动态数组 (dynamicarTay)。使用静态联编时,必须在编写程序时指定数组的长度 使用动态联编时 程序在运行时确定数组的长度
使用new创建动态数组
int * psome = new int [10];// get a block of 10 ints
new运算符返回第一个元素的地址。在这个例子中,该地址被赋给指针 psome。
当程序使用完 new 分配的内存块时,应使用 delete 释放它们。然而,对于使用new 创建的数组,应使用另一种格式的 delete 来释放:
delete [] psome; // free a dynamic array
方括号告诉程序,应释放整个数组,而不仅仅是指针指向的元素。请注意 delete 和指针之间的方括号。如果使用 new 时,不带方括号,则使用delete 时,也不应带方括号。如果使用new 时带方括号,则使用 delete时也应带方括号
编写程序时必须让程序跟踪元素的数目,实际上 程序确实跟踪了分配的内存量 以便于以后使用delete[]运算符能够正确的释放这些内存,但这种信息不是公用的 ***例如不能使用sizeof运算符来确定动态分配的数组包含的字节数***
使用动态数组时如何访问其中的元素 只需要把指针当作数组名使用即可 也就是说对于第一个元素可以用psome[0]而不是*psome 对于第二个元素可以使用psome[1]…以此类推
不能修改数组名的值。但指针是变量,因此可以修改它的值。请注意将 p3加1的效果。表达式p3[1]原本指的是数组的第1个值。因此,将p3加1导致它指向第2个元素而不是第1个。将它减1后,指针将指向原来的值,这样程序便可以给 delete[]提供正确的地址。相邻的 int 地址通常相差2个字节或4个字节,而将p3加1后,它將指向下一个元素的地址,这表明指针算术有一些特别的地方。情况确实如此。
3.3.1指针算数
c++将数组名解释为地址
注意 将指针变量加一后 其增加的值等于指向的类型占用的字节数
在很多情况下 可以相同的方式使用指针名和数组名 区别之一是可以修改指针的值而数组名是常量另一个区别是对数组使用sizeof得到的是数组的长度 而对指针使用sizeof得到的是指针的长度 即使指针指向的是一个数组
数组名被解释为第一个元素的地址 而对数组名应用地址运算符时得到的是整个数组的地址
3.4.1指针和字符串
char flower[10]="rose";
cout << flower << "s are red\n";
为了与cout对字符串输出的处理保持一致,这个用 引号括起的字符串也应当是一个地址。
在C++中,用引号括起的字符串像数组名一样,也是第1个元素的地址。上述代码不会将整个字符串发送给cout,而只是发送该字符串的地址。这意味着对于数组中的字符串、用引号括起的字符串常量以及指针所描述的字符串,处理的方式是一样的,都將传递它们的地址。与逐个传递字符串中的所有字符相比,这样做的工作量确实要少。
注意:在cout 和多数C++表达式中,char数组名、char 指针以及用引号括起的字符串常量都被解释为字符串第一个字符的地址。
看这段代码
const char * bird="wren";
字符串字面值是常量 这就是为什么代码在声明中使用关键字const的原因
一般来说,编译器在内存留出一些空间来储存程序源代码中的所有用引号括起来的字符串 并将每个被储存的字符串与其地址关联起来 这意味着可以像使用字符串“wren”那样使用指针bird
cout << "a concerned" << bird << "speaks";
警告 在将字符串读入程序时应使用已分配的内存地址,该地址可以是数组名 也可以是new初始过的指针
一般来说如果给cout提供一个指针,他将打印地址,如果指针的类型为*char则将显示其指向的字符串 如果要显示字符串的地址则必须将这种指针强制转化为另一种指针例如int*
应该使用strcpy()或者strncpy()而不是赋值运算符来将字符串赋给数组
strcpy()接受三个参数 目标地址 要复制的字符串的地址 要复制的最大字符数
3.5.1使用new创建动态结构
#inclue<iostream>
struct inflatable
{
char name[20];
double price;
};
int main()
{using namespace std;
inflatable * ps= new inflatble;
********
********
delete ps;
return 0;
}
比较棘手的一步是访问成员。创建动态结构时不能将成员运算符句点用于结构名,因为这种结构没有名称,只是知道它的地址。C++专门为这种情况提供了一个运算符:箭头成员运算符 (->)。该运算符由连字符和大于号组成,可用于指向结构的指针,就像点运算符可用于结构名一样。例如,如果ps 指向一个 inflatable 结构,则 ps->price 是被指向的结构的 price 成员
如果结构标识符是结构名,则使用句点运算符;如果是指向结构的指针就用箭头运算符
如果ps是指向结构的指针,则*ps就是被指向的值----结构本身 *ps是一个结构 (*ps). price是该结构的price成员 (根据c++运算符优先规则要求使用括号)
4.1.0枚举
枚举是一种创见符号常量的方式,这种方式可以代替const,它还允许定义新类型但必须严格按照限制进行 使用enmu的句法与结构类似
enmu spectrum[red , orange , yellow , green , blue , violet , indigo , ultraviolet};
red orange yellow 作为符号常量对应整数0~7 这些常数叫枚举量 默认情况下 将整数值赋给枚举量,第一个是0第二个是1 以此类推
对于枚举只定义了赋值运算符 没有其它算数定义
枚举量是整型,可以被提升为int类型,但int不能自动转换为枚举类型
band = orange + red;
非法的原因有些复杂。确实没有为枚举定义运算符+,但用于算术表达式中时,枚举将被转换为整数因此表达式 orange + red 将被转换为 1+0。这是一个合法的表达式,但其类型为int不能将其赋给类型为spectrum 的变量 band 如果 int值是有效的,则可以通过强制类型转换,将它赋给枚举变量
可以用枚举来定义switch语句中的符号常量 如果只打算使用常量 则可以省略枚举类型的名称
4.1.2设置枚举的量
4.1.3枚举的取值范围
5.1.0结构体
结构是一种灵活的数据格式,同一个结构可以储存多种类型的数据
结构是用户定义的类型,而结构声明定义了这种类型的数据属性。定义了类型后,便可以创建这种类型的变量。因此创建结构包括两步。首先,定义结构描述——它描述并标记了能够存储在结构中的各种数据类型。然后按描述创建结构变量(结构数据对象)
struct inflatable
{
char name[20];
float volume;
double prince;
};
可以利用成员运算符 . 来访问结构成员
inflatable.name;
结构声明的位置很重要,外部声明可以被其后面的任何函数使用,内部声明只能被该声明所属的函数使用
如果初始化的大括号里未包含任何东西,各个成员都被设置为0
最后 不允许缩窄变换
结构可以将string类作为成员
结构体可以作为参数传递给函数 也可以被函数返回
也可以使用赋值运算符对相同类型的结构进行赋值
5.1.2结构数组
5.1.3结构中的位字段
5.2.1共用体union
共用体是一种数据格式 它能够储存不同的数据类型,但是只能同时存储其中的一种类型,结构体可以同时储存 int long double;而共用体只能储存int或double或long,句法相似
one4all pail;
pail.int_val=15;
cout << pail.int_val;
pail.double_val=1.38;
cout << pail.double_val;
因此,pail 有时可以是int变量,而有时又可以是 double 变量。成员名称标识了变量的容量。由于共用体每次只能存储一个值,因此它必须有足够的空间来存储最大的成员,所以,共用体的长度为其最大成员的长度。
共用体的用途之一是,当数据项使用两种或更多种格式 (但不会同时使用)时,可节省空间
匿名共用体 没有名称其成员成为位于相同地址的变量 然而 每次只有一个成员是当前的成员
5.2.2使用new创建动态结构
如果结构标识符是结构名 则使用句点运算符 如果标识符是指向结构体的指针则使用箭头运算符
注意:如果ps是指向结构的指针,则*ps就是结构本身,由于它是一个结构 因此(*ps).price 是该结构的price成员 <c++的运算有限规则要求使用括号>
#include <iostream>
struct inflatable
{
char name[20];
float volume;
double price;
};
int main()
{
using namespace std;
inflatable * ps =new inflatable;
.......
}
6.1.1自动 静态 动态存储
c++管理内存的方式有自动存储 静态存储 动态存储(还有线性存储)
1自动存储 在函数内部定义的常规变量使用自动存储 叫做自动变量 这意味着它们在被所属函数调用的时候自动产生,在该函数结束的时候消亡
自动变量通常存储在栈中 执行代码时 其中地代码依次加入到栈中 在离开代码块时 按相反的顺序释放这些变量 这被称为后进先出 执行过程中 栈将不断增大缩小
2静态储存
静态存储是整个程序执行期间都存在的存储方式 使变量成为静态的方式有两种:一种是在函数外面定义它;另一种是在声明变量时使用关键字 static
static double fee =56.50;
自动存储和静态存储的关键在于:这些方法严格地限制了变量的寿命。变量可能存在于程序的整个生命周期(静态变量),也可能只是在特定函数被执行时存在(自动变量)
3.动态存储 new 和delete 运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内存池,这在C+中被称为自由存储空间(free store)或堆(heap)。该内存池同用于静态变量和自动变量的内存是分开的。 new和delete让您能够在一个函数中分配内存,而在另一个函数中释放它。因此,数据的生命周期不完全受程序或函数的生存时间控制。 在栈中,自动添加和删除机制使得占用的内存总是连续的,但new和delete的相互影响可能导致占用的自由存储区不连续,这使得跟踪新分配内存的位置更困难
7.1.1数组的替代品
1模板类vector
它是使用new创建动态数组的替代品 实际上 vector类确实使用new 和delete来管理内存
使用时必须包含头文件 #include<vector> 包含在名称空间std中
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int>vi;
int n;
cin >> n;
vector<double>vd(n);
}
其中,vi是一个 vector<in>对象,vd 是一个vector<double>对象。由于vector 对象在您插入或添加值时自动调整长度,因此可以将 vi的初始长度设置为零。但要调整长度,需要使用 vector 包中的各种方法 一般而言,下面的声明创建一个名为vt的 vector 对象,它可存储n_elem 个类型为typeName 的元素vector<typeName> vt(n_elem);其中参数 n_elem 可以是整型常量,也可以是整型变量
2模板类array
与数组一样,array对象的长度也是固定的,也是用栈而不是自由储存区,因此效率与数组相同但比数组更安全 需要头文件 #include<array>
#include<iostream>
#include<array>
using namespace std;
int main()
{
array<int,5> ai;
array<double,4>ad={1.1,1.2,1.3,1.4};
}
注意 array<typeName,n_elem>arr; 这里的n_elem不能是变量
首先,注意到无论是数组、vector对象还是 array对象,都可使用标准数组表示法来访问各个元素。其次,从地址可知,aray 对象和数组存储在相同的内存区域(即栈)中,而 vector 对象存储在另一个区域(自由存储区或堆)中。第三,注意到可以将一个array 对象赋给另一个 array 对象;而对于数组,必须逐元素复制数据
四.循环和关系表达式
4.1.1for循环
4.1.2while循环
4.1.3do while 循环
4.1.4typedef 工具
4.2.1嵌套循环和二维数组
五.分支语句和逻辑运算符
5.1.1if语句
5.1.2 if else语句
5.1.3逻辑运算符
5.1.4cctype字符函数库
5.1.5switch语句
//四五章与c语言大差不差 所以先跳过 最后在补充细化
六.函数----c++的编程模块
6.1.1复习函数相关知识
要使用c++函数 必须完成的工作:
提供函数定义 提供函数原型 调用函数
6.1.2定义函数
函数分为两类 有无返回值 没有返回值的函数被称为void函数 通常格式如下
void functionName(parameterList)
{
statement(s)
return;
}
//parameterList指的是传递给函数的参数类型和数量
有返回值的函数会生成一个值 其通用格式如下
typeName functionName(parameterList)
{
statements
return value;
}
返回的值可以是常量 变量 表达式
c++对于返回值有一定的限制 不能是数组(但是可以作为结构或者对象组成部分来返回) 可以返回指针 结构 对象
如果函数有返回值 那么main()就可以将它用在赋值语句中
6.1.3函数的原型和调用
函数原型是一条语句,因此必须用分号结尾(即复制函数定义中的函数头并添加分号)
double cube(doublex);
原型的功能 1正确处理函数返回值 2检查使用参数数目和类型是否正确
如果没有原型 那么下面这段代码将被编译器通过
double z =cube();
6.1.4函数参数和按值传递
double volume = cube (side);//side=5
double cube (double x)
当cube被调用时 该函数将创建一个新的名为x的double变量,并将其初始化为5 这样的操作不会影响main中的数据 cube使用的是side的副本 不是原来的数据
用于接受传递值的变量被称为形参(x)传递给参数的值成为实参(side)
函数可以有多个参数 用逗号分开即可
6.1.5函数和数组
int sum_arr(int arr[],int n)
上述代码函数参数表种 arr被指出是一个数组 方括号是空的又表明可以将任意长度的数组传递给他 事实并非如此 arr实际上是一个指针 ,但好消息是在编写代码的其余部分可以将它看作数组
数组名实际上是指针 所以在使用函数时传递一个指向数组的指针(数组名)即可
int sum_arr(int *arr,int n)
int sun_arr(int arr[],int n)
这两个函数头都是正确的 c++中当且仅当在函数头及原型中int*arr 和int arr[ ]含义相同 而int arr[]不止指向数组 还指向第一个元素 指向独立的一个值的时候还是使用指针
6.1.6使用数组区间的函数
6.2.1函数和二维数组
6.3.1函数和c-风格字符串
6.4.1函数和结构
6.5.1函数和array对象
6.6.1递归
6.7.1函数指针
七.函数探幽
7.1.1内联函数
常规函数与内联函数的区别不在于编写方式而在于c++编译器如何将他们组合到程序中
c++内联函数提供了另一种选择,内联函数的编译代码与其他程序代码“内联”起来了。也就是说,编译器将使用相应的函数代码替换函数调用。对手内联代码,程序无需跳到另一个位置处执行代码,再跳回来。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。如果程序在 10个不同的地方调用同一个内联函数,则该程序将包含该函数代码的 10个副本
要使用内联函数必须在函数声明或者是定义前加上关键字inline
(内联函数不能递归)
7.2.1引用变量
c++新增了一种复合类型 引用变量
引用变量通俗来讲就是已经定义的了变量的别名 相当于直接使用了原来的变量并且对其做出改变
主要用途是作为函数的形参,通过引用变量作为参数函数将使用原始数据 而不是其副本
7.2.2创建引用变量
使用运算符&(另一个含义是取地址符)
学到这里我们不免联想到指针
int rats=101;
int & rodents=rats;
int * prats=rats;
实际上两者还是有一些差别 其中之一就是声明引用时必须将其初始化,不能像指针那样先声明再赋值
int rat;
int & rodent;
rodent=rat;//不可以这样做
引用更接近const指针 必须在创建时就初始化 一旦与某个变量关联起来就一直效忠于他
int &rodents=rats;
int *const pr=&rats;
上面代码其实是下面代码的伪装表示 rodents扮演的角色与表达式*pr相同
{按值传递不改变在main中x的值
按引用传递会改变******}
7.2.3临时变量 引用参数和const
如果实参与引用参数不匹配 那么c++就会生成临时变量 当前 仅当参数为const时c++才允许这样做
什么时候创建临时变量 1