复合类型
- 数组
- 字符串
- string类
- 结构
- 共用体
- 枚举
- 指针(new delete管理动态内存)
- 动态数组,动态结构
- vector和array类
1.数组
数组声明格式:
typeName arrayName[arraySize];
这样声明时注意arraySize不可以是变量。数组的索引从0开始到arraySize-1.
数组初始化:
int initArray[3] = {1, 2, 3};
如果只对数组的一部分进行初始化,那么编译器将把其它元素设置为0。因此一般初始化所有元素时只写第一个元素的初始化即可。
C++11在初始化数组是可以省略=号,大括号里不包含任何东西时默认初始化为0。
2.字符串
这里指的时C-风格的字符串,也就是使用char型数组存储字符串。这里不再多提。
3.string类
string类可以直接将字符串作为一种数据类型去声明:
#include <string>
int main()
{
using namespace std;
string str1;
string str2 = "xuan";
str1 = str2;
cout << str1 << endl; //xuan
cout << "Please input a string: ";
cin >> str2; //xiao
str1 = str1 + str2; //xuanxiao
cout << "This is all string: " << str1 << endl;
return 0;
}
string类型的变量可以直接赋值和+拼接,可以使用str1[0]来对字符串的元素进行操作,可以使用str1.size()取得字符串的长度。str1.find()可以查找字符串的内容。str1.subtr()可以找到某一元素第一次出现的位置。
结构
结构可以将不同类型的数据放在一个结构中。其定义如下:
struct inflatable
{
char name[20];
float volume;
double price;
};
//使用结构
inflatable hat =
{
"xuan",
1.88,
29.99
}; //C++可以省略struct关键字
//如果使用inflatable hat {};则每个成员都被初始化为0。(可以不加等号)
hat.name = "xuan";
hat.volume = 0;
hat.price = 0;
可以将结构作为参数传递给函数,也可以让函数返回一个结构。另外,还可以使用赋值运算符(=)将结构付给另一个同类型的结构,这样结构中的每个成员都将被设置为另一个结构中相应成员的置,即使成员是数组。这种赋值叫做成员赋值。
另外,C++结构出了成员变量之外,还可以有成员函数,但这些高级特性通常被用于类中,而不是结构中。
结构体可以和一般数据类型一样成为数组成员,具体定义方式及初始化方式如下:
#include <iostream>
struct inflatable
{
char name[20];
float volume;
double price;
}
int main()
{
using namespace std;
//这里数组中的每个元素都是一个结构
inflatable guests[2] =
{
{"Bambi", 0.5, 21.99},
{"Godzilla", 2000, 565.99}
};
return 0;
}
共用体
共用体是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中一种类型。也就是说,结构可以同时存储int,long,double,而公用体只能存储int或long或double。共用体定义如下:
union one4all
{
int int_val;
long long_val;
double double_val;
};
//使用
one4all pail;
pail.int_val=15; //store an int
cout << pail.int_val;
pail.double_val = 1.38; // store a double, int value is lost
cout << pail.double_val;
因此pail有时可以是int变量,有时可以是double变量。成员名称标识了变量的容量。由于共用体没次只能存储一个值,因此它必须有足够的空间来存储最大的成员,所以他的长度为最大成员的长度。
公用体的用途之一是,但数据项使用两种或者更多的格式(但不同时使用)时,可节省空间。
枚举
enum定义:
enum spectrum {red, orange, yellow, green, blue, violet, indigo, ultraviolet};
//使用
spectrum band;
band = red;
//band赋值只能是上面定义的那些
//显式的设置枚举量的值
enum bits{one = 1, two = 2, four = 4, eight = 8};
//指定的值必须是整数,也可以只显式的定义其中一些枚举量的值
enum bigstep{first, second = 100, third};
//first默认为0,后面没有被初始化的将比前面的枚举量大1
可以用枚举来定义switch语句中使用的符号常量。
指针和自由存储空间
C++指针基本和C的指针差不多,这里不多说,直接看c++的一些特性:
使用new来分配内存
C语言中使用malloc分配内存,而在C++中使用new运算符来分配内存。
为一个数据对象(可以是结构,也可以是基本类型)获得并指定分配内存的通用格式如下:
typeName * pointer_name = new typeName;
程序实例:
#include <iostream>
int main()
{
using namespace std;
int nights = 1001;
int * pt = new int;
*pt = 1001;
double * pd = new double;
*pd = 10000001.0;
return 0;
}
new与malloc最大的不同是new是在程序运行过程中进行内存分配的,这样更加灵活。还有一点不同是常规内存分配是在栈(stack)中存储,而new从堆(heap)或自由存储区的内存区域分配内存。
使用delete释放内存
当需要内存时,可以使用new来请求,使用完内存之后,可以用delete将内存归还给内存池。使用方法如下:
int * ps = new int;
.....
delete ps;
delete只会释放ps指向的内存,而不会删除指针ps本身,可以将ps重新指向一个新分配的内存块。一定要配对的使用new和delete,否则将会发生内存泄漏(memory leak)。也不可以尝试释放已经释放的内存块,这样做的结果是不确定的。而且不能使用delete来释放声明变量所获得的内存:
int * ps = new int;
delete ps;
int jugs = 5;
int * pi = &jugs;
delete pi; //(这是不对的)
**警告:**只能用delete来释放new分配的内存,然而对空指针使用delete是安全的。
使用new来创建动态数组
可以使用new来在程序运行时根据用户信息决定是否创建数组以及创建数组的大小。这种数组叫做动态数组。
使用new创建动态数组
在C++中,创建动态数组很容易,只要将数组的元素类型和元素数目告诉new即可。必须在类型名后加上方括号,其中包含元素数目。
type_name * pointer_name = new type_name [nem_elements];
int * psome = new int [10]; // get a block of 10 ints
new运算符返回第一个元素的地址。对于new创建的数组要用另一种格式的delete进行释放:
delete [] psome;
方括号表示释放整个数组,而不仅仅是指针指向的元素。
总之,使用new和delete时,应遵守以下规则:
- 不要使用delete来释放不是new分配的内存
- 不要使用delete使用同一个内存块两次
- 如果使用new [] 为数组分配内存,则应使用delete []来释放
- 如果使用new[] 为一个实体分配内存,则应使用delete来释放
- 对空指针应用delete是安全的
使用动态数组
两种使用方式,和C语言指针一样,一种是将指针当作数组名,另一种是对指针进行加减运算然后访问元素。
#include <iostream>
int main()
{
using namespace std;
double * p3 = new double [3];
p3[0] = 0.2;
p3[1] = 0.5;
p3[2] = 0.8;
//另一种
p3 = p3 + 1;
cout << *p3 << endl;
p3 = p3 - 1;
cout << *p3 << endl;
return 0;
}
使用new创建动态结构
结构也可以用new在运行时创建并分配内存。
#include <iostream>
struct inflatable
{
char name[20];
float volume;
double price;
}
int mian()
{
using namespace std;
inflatable * ps = new inflatable;
cout << "Enter name of inflatable item: ";
cin.get(ps->name, 20);
cout << "Enter volume in cubic feet: ";
cin >> ps->volume;
cout << "Enter price: $";
cin >> ps->price;
cout << "Name: " << (*ps).name << endl;
cout << "Volume: " << ps->volume << endl;
cout << "Price: $" << ps->price << endl;
delete ps;
return 0;
}
数组替代品(vector和array)
vector和array类可以代替数组,可以有更多的好处。
模板类vector
模板类vector类似于string类,也是一种动态数组。可以在运行阶段设置vector对象的长度,可在末尾附加新数据,还可以在中间插入新数据。基本上它是使用new创建动态数组的替代品。实际上,vector类确实使用new和delete来管理内存,但这种工作是自动完成的。
要使用vector对象,必须包含头文件vector。其次,vector包含在名称空间std中,因此可以使用using编译指令,using声明或std::vector。第三,模板使用不同的语法来指出它存储的数据类型。第四,vector类使用不同的语法来指定元素数。
#include <vector>
...
using namespace std;
vector<int> vi; // creat a zero-size array of int
int n;
cin >> n;
vector<double> vd(n); // creat an array of n doubles
其中,vi是一个vector<int>对象,vd是一个vector<double>对象。由于vector对象在插入或添加值时自动调整长度,因此可以将vi的初始长度设置为0。但要调整长度,需要使用vector包中的各种方法。
一般格式:
vector<typeName> vt (n_elem);
其中参数n_elem可以是整型常量,也可以是整型变量。
模板类array
vector类的功能比数组强大,但付出的代价是效率稍低。如果需要的是长度固定的数组,使用数组是更佳的选择,但代价是不那么方便和安全。array模板类解决了这个问题。与数组一样,array对象的长度也是固定的,也使用栈(静态内存分配),而不是自由存储区,因此其效率与数组相同,但更方便,更安全。要创建array对象,需要包含头文件array。array对象的创建语法与vector稍有不同:
#include <array>
...
using namespace std;
array<int, 5> ai; // creat array object of 5 ints
array<double, 4> ad = {1.2, 2.1, 3.43, 4.3};
所以array的创建格式为:
array<typeName, n_elem> arr;
与创建vector对象不同的是,n_elem不能是变量。
比较数组,vector对象和array对象
无论是数组,vector对象还是array对象,都可以使用标准数组表示法来访问各个元素。其次,从地址来看,array对象和数组存储在相同的内存区域中(栈),而vector对象存储在另一个区域中(自由存储区或堆)。第三,可以将一个array对象赋给另一个array对象;而对于数组,必须逐元素复制数据。
使用标准数组表示法来访问元素时不会检查非法超界错误,可以用vector和array的成员函数at()来对其成员进行操作:a.at(1) = 2.3;这种表示会在运行期间捕获非法索引,程序会中断,但是这种额外检查的代价是运行时间更长,所以C++允许使用两种表示法。