C++ Primer Plus学习笔记(第四章)续
目录
1)共用体
2)枚举
3)指针
4)使用new来分配内存
5)指针、数组和指针算术
6)C++有3中管理数据内存的方式:自动存储、静态存储和动态存储。
7)数组的替代品:vector和array
1)共用体
a)是一种数据格式,能够存储不同的数据类型,但只能同时存储其中的一种类型。由于每次只能存储一个值,因此它必须有足够的空间来存储最大的成员,所以,共用体的长度为其最大成员的长度。
b)共用体的用途之一是,当数据项使用两种或更多种格式时,可以节省空间。
c)匿名共用体没有名称,其成员将成为位于相同地址处的变量。显然,每次只有一个成员是当前的成员。
union
{
long id_num;
char id_char[20];
}
2)枚举
a)将整数值赋给枚举量,第一个枚举量的值为0,第二个枚举量的值为1,依次类推。
enum spectrum{red,orange,yellow,green,violet,blue};
b)可以用枚举名来声明这种类型的变量。
spectrum band;
c)对于枚举,只定义了赋值运算,没有为枚举定义算术运算。
band=orange;//赋值
band=orange+red;//这是错误的
d)枚举量是整形,可被提升为int类型,但int类型不能自动转换为枚举类型。
int color=blue;
color=3+red;//可以,因为red转换为int类型了
e)可以用赋值运算符来显式地设置枚举量的值。指定的值必须是整数。
enum bits{one=1,two=2,eight=8}
默认情况下第一个是0,后面没有被初始化的枚举量将比前面的枚举量大1。也可以创建多个相同值的枚举量。
enum bigstep{first,second=10,third,third_1=11};
3)指针
a)显示地址时,cout使用十六进制表示法,因为这是常用于描述内存的表示法。在有些系统中,可能不会将两个变量存储在相邻的内存单元中。
b)*运算符被称为间接值或解除引用运算符,将其应用于指针,可以得到该地址处存储的值。mainly是一个指针,mainly表示一个地址,而*mainly表示存储在该地址处的值。*mainly与常规int变量等效。
c)在创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。为数据提供空间是一个独立的步骤。所以注意:一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。
d)指针不是整型,虽然计算机通常把地址当作整数来处理。指针和整数是截然不同的类型。整数可以执行加、减、乘除等运算,而指针描述的是地址,将两个地址相乘没有任何意义。
int *pt;
pt=(int *)0xB8000000;//这样的赋值是有效的
4)使用new来分配内存
a)如果已经声明了相应类型的指针,则可以使用该指针,而不用再声明一个新的指针。为一个数据对象(可以是结构,也可以是基本类型)获得并分配指定内存的通用格式:
typeName *pointer_name = new typeName;
int *pt= new int;
*pt=1001;
b)new分配的内存块通常与常规变量声明分配的内存块不同。new从被称为堆(heap)或自由存储区的内存区域分配内存。
c)释放指针ps指向的内存,但不会删除指针ps本身。可以将ps重新指向另一个新分配的内存块,一定要配对使用new和delete,否则将发生内存泄露(memory leak)。也就是说,被分配的内存再也无法使用了。如果内存泄露严重,则程序将由于不断寻找更多内存而终止。
int *ps= new int ;
delete ps;
d)不要尝试释放已经释放的内存,这样的结果是不确定的。也不要使用delete来释放声明变量所获得的内存。
int *ps =new int;
delete ps;
delete ps;//释放两次是不正确的
int *pi=&jugs;
delete pi;//不允许这样释放内存
e)不要创建两个指向同一个内存块的指针,因为这将增加错误地删除同一个内存块两次的可能性。另外,只能用delete来释放使用new分配的内存,对空指针使用delete是安全的。
f)静态联编:在编译时给数组分配内存。意味着数组是在编译时加入到程序中。必须在编译程序时指定数组的长度。
动态联编:使用new时,如果在运行阶段需要数组,则创建它,如果不需要,则不创建。还可以在程序运行时选择数组的长度。
g)使用new创建动态数组:只要将数组的元素类型和元素数目告诉new即可。必须在类型名后加上方括号,其中包含元素数目。new运算符返回的是第一个元素的地址。通用格式:
type_name *pointer_name =new type_name [num_elements];
int *psome =new int [10];
delete [ ] psome;
h)总之,使用new和delete应该遵守规则如下:
不要使用delete来释放不是new分配的内存。
不要使用delete释放同一个内存块两次。
如果使用new[ ]为数组分配内存,则应使用delete[ ]来释放。
如果使用new为一个实体分配内存,则应使用delete来释放。
对空指针使用delete是安全的。
5)指针、数组和指针算术
a)将指针变量加1后,增加的量等于它指向的类型的字节数。将指向double的指针加1后,如果系统对double使用8字节存储,则数值将增加8,指向short的指针加1,指针值则加2。
b)对数组应用sizeof运算符得到的是数组的长度,对指针应用sizeof运算符得到的是指针的长度,即使指针指向一个数组。
c)数组的地址:数组名被解析为第一个元素的地址,而对数组名取地址运算得到的是整个数组的地址。
short tell[10];
cout<<tell<<endl; //&tell[0]数组名-->第一个元素的地址
cout<<&tell<<endl; //the whole of array数组名取地址运算-->整个数组的地址
&tell[0](即tell)是一个2字节内存块的地址。而&tell是一个20字节内存块的地址。对表达式tell+1是将地址值加2,而表达式&tell+2是将地址加20。
d)应将内存地址赋给指针。可以对变量名应用&运算符,来获得被命名的内存的地址,new运算符返回未命名的内存的地址。
e)使用方括号数组表示法等同于对指针解除引用。所以,另一种对指针解除引用的方法就是使用数组表示法,如pn[0]与*pn是一样的。绝不要对未被初始化为适当地址的指针解除引用。
6)C++有3中管理数据内存的方式:自动存储、静态存储和动态存储。
a)自动存储:在函数内部定义的常规变量使用自动存储空间,被称为自动变量。意味着他们在所属的函数被调用时自动产生,在该函数结束时消亡。自动变量是一个局部变量,通常存储在栈中。
b)静态存储:是整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种:一种是在函数外面定义它,另一种是在声明变量时使用关键字static。
c)动态存储:new和delete管理了一个内存池,在C++中被称为自由存储空间或堆。该内存池同用于静态变量和自动变量的内存是分开的。
7)数组的替代品:vector和array
a)vector模板类:类似于string类,也是一种动态数组。可以在运行阶段设置vector对象的长度,可以在末尾附加新数据,也可以在中间插入新数据。
b)vector类确实使用new和delete来管理内存,但是是自动完成的。要使用vector对象,必须包含头文件<vector>,还包含在名称空间std中。
c)标准格式:vector<typeName> vt(n_elem);
如:vector<int> ai(4);
d)模板类array:包含头文件<array>,包含在名称空间std中。array对象的长度是固定的,使用栈来创建。格式:
array<typeName, n_elem> arr;
如:array<double, 4> ai={1.2, 1.3, 2.2, 3.3};
e)可以使用vector和array对象的成员函数at()。
如:a2.at(1)=2.3; //a2[1]=2.3
第四章(完)