复合类型是指在其他类型的基础上定义的类型。C++中内置的复合类型包括指针、引用、数组、结构体、共用体和枚举。也可以用户自己定义。
一.指针
指针类型指向一个对象的地址,可以间接操作它指向的对象。
I.定义指针变量的语法:
类型 * 指针变量;
1 .需要取对象的地址进行存储,用到取地址符&,例如:int *pi=&a;//指针pi存放整型变量a的地址。
2.指针本身也可以是对象,即可以用指针指向指针。
3.用指针间接访问对象时需解引用,用到解引用符“ * ”。例如:int *pi=&x;*pi=10;//间接操作pi指向的x,使x=10;。
4.指针不能指向不同类型的对象,不同指针的表示方法和保存的地址值没有分别,又分别的使指针指向对象的类型不同。
5.指针不能保存非地址值,也不能被赋值或初始化为不同类型的地址值。
6.void类型指针,他只能表明相关的值是个地址,但是该地址保存的对象类型不知道。不能操纵void指针指向的对象,只能传送地址或者和其他地址值进行比较,也不允许到其他类型指针直接赋值。
II 空指针与空悬指针
一.空指针:不指向任何对象的指针。所以不能对空指针解引用
生成空指针3种方法
指针值为0表示空指针,即 int *pi=0;
C++11引入字面值nullptr,int *pi=nullptr;
头文件 < cstdlib >中定义的预处理常量NULL值,它的值为0;即 int *pi=NULL;
空悬指针:指向不确定的单元。执行delete(下面会有介绍)后的指针。
III. new和delete
静态和动态内存分配在预防上的主要区别:
(1)静态对象是有名字的变量,可以直接操作;而动态对象没有名字,要通过指针间接的操作。
(2)静态对象的空间分配与释放由编译器自动处理,动态对象必须由程序员显式地操作。
程序使用动态内存三种原因:
(1)程序不知道自己需要使用多少对象。
(2)程序不知道所需对象的准确类型。
(3)程序需要在多个对象间共享数据。
C++语言则通过new和delete来进行动态存储空间的管理。
new
new运算符在堆上动态分配空间,创建对象,并返回对象的地址。
new有三种表达形式。
1.用于分配特定类型的单个对象,并返回其地址
形式为: new 类型
或者 new 类型(初始值)
2.分配指定类型和大小的数组,并返回数组首地址。
new 类型[数组大小]
用new分配的数组大小不一定要是常数。
3.允许程序员将对象创建在已经分配好的内存中。称为定位new表达式。
new (指针)类型
必须要包含标准库头文件< new>,例如:
#include< iostream>
#include< new>
using namespace std;
char *buf=new char[100]; //预分配一段空间,首地址在buf中保存;
int main()
{ int *pi=new (buf) int;//在buf中创建一个int对象,此时不再重新从堆上分配空。}
delete
堆上的空间使用后必须释放,否则内存泄漏,new分配的空间用delete运算符释放。
1.释放new分配的单个对象
delete 指针;
2.释放new分配的数组的delete形式为
delete [ ] 指针;
3.定位new并不实际在堆上分配空间,因此没有对应的delete表达式。
二.引用
引用可以作为对象的另一个名字。表示同一个变量,通过引用可以间接地操纵对象
I.左值引用
类型 &引用变量=初始量;
1.引用必须被初始化,初始值是一个又内存地址的对象。
2.引用一旦初始化,就不能再绑定到其他对象。
3.不能双重引用,引用的引用是错误的。
II.右值引用
(可取地址的、有名字的是左值;反之是右值。或者说赋值号左边的是左值,右边是右值)
类型 &&右值引用变量=右值表达式;
1.右值引用必须初始化,初始值是右值表达式
2.不能将右值引用直接绑定在一个左值上。
3.左值成倍,即 i*5 就可作为右值绑定。
.const限定指针和引用
const限定词将一个对象限定为常量。const也可以限定指针和引用。
1.指针的类型必须与其所指向的对象类型一致,C++允许将非const地址赋给const指针。
2.引用也是,const引用可以绑定到非const对象,也可以用任意表达式初始化const引用,只要表达式的结果能转化为引用的类型即可。
volatile与const一起被成为CV限定词,二者使用语法相同;
当一个对象的值可能在编译器的控制或检测之外被改变时,应该将对象声明为volatile。
三.结构体、联合和枚举
I.结构体
结构体吧一组来自不同类型的数据组合在一起构成了复合类型,其中的每个数据都是成员。结构体由关键字struct定义,语法形式为
struct 结构体类型名
{成员声明;
};
例如:struct X{
char c;
int i;
float f;
double d;};//定义结构体类型X;
X s1,s2;
X *pi=&s1;
s1.i=1;//必须通过X变量s1引用成员;
s2.c=pi>c;//通过指针pi引用成员c;
…
1.结构体成员不能独立使用,必须由结构体类型的变量通过成员选择运算符“ .”来选择,或者由指针通过“->”运算符选择。
2.结构体变量在内存中的大小是所有成员的大小之和。
II联合
联合union,与struct语法类似
1.但每次只能使用一个成员,下面的成员会覆盖上一个的内容。
2.联合变量大小是最后一个成员的大小。
III.枚举
枚举类型定义了一组命名的整数常量,以提高代码的可读性, 例如
enum Light{ red, green, yellow};
1.可以使用未命名的枚举类型定义常量。例如:
enum {False,True};。
2.enum定义的枚举在C++11标准中被称为不限定作用域的枚举类型。C++11引入了限定作用域的枚举类型,用关键字enum class或enum struct定义。
3.在不限定作用域的枚举类型中,枚举成员的作用域与枚举类型本身的作用域相同。
4.不能使用枚举成员进行迭代,C++不支持枚举成员之间的前后移动。
四.标准库类型string
string表示可变长度的字符序列。使用需要包含头文件< string>。
简单使用:
#include< iostream>
#include< string>
using namespace std;
int main()
{sting s1,s2;
string s3=“hello,world”;
string s4(“I am”);
s2=“Today”;//两种赋值
s1=s3+" "+s4;//字符串连接
s1+=“5”;}//末尾追加
1.s.empty() s为空返回1,否则返回; s.size() 返回s中的字符个数; s[n] 返回s中第n个字符的引用,n从0开始计。
2.cin输入字符串时,到空格结束;getline(cin,s)可以输入空格,到换行结束;
五.标准库类型vector
vector表示对象的集合,所有对象类型相同。vector这样容纳这其他对象的对象被称为容器。vector是长度可变的向量,比数组用起来更方便更快捷。使用需要包含头文件< vector>。
语法形式:
vector <元素类型> 变量名;
几种初始化类型:
1.vector< T>v2(v1) v2中包含v1所有元素的副本。
2.vector< T>v2=v1 等价于v2(v1)。
3.vector< T>v3(n,val) v3包含n个重复的元素,每个元素的值都是val。
4.vector< T>v4(n) v4包含着n个重复执行值初始化的元素。
5.vector< T>v5{a,b,c…} 对每一个进行赋值。大括号前有无赋值号效果相同。
vector支持的几种操作:
v.empty() 是否为空。
v.size() 返回元素个数。
v.push_back(t) 末尾添加一个元素t。 v.pop_back() 末尾删除一个元素。
v1=v2 整体赋值。
六.迭代器
类似于指针类型,间接访问对象。迭代器在容器或string对象上使用,所以迭代器指向的对象时容器中的元素或string中的字符。使用迭代器可以访问容器中的某个元素,也可以在容器上移动。迭代器只有在指向某个元素或指向最后一个元素的下一个位置是才是有效的。
1.标准库容器用iterator和const_iterator表示迭代器类型,例如:
vector< int >::iterator a1; //a1能读写vector< int >的元素。
string::iterator a2; //a2能读写string对象中的字符。
加了const_就变成了只读不写。
2.迭代器支持的运算符
*iter 解引用,返回所指元素的引用
iter->mem 解引用iter并获取该元素的成员mem,等价于(*iter).mem.
++iter 指向下一个元素 --iter指向上一个元素。
iter1==iter2 判断两者是否相同,
iter1-iter2 指向同一容器的迭代器之间的距离
七.文件读写
I.标准库文件流
ifstream类:istream的派生类,用来输入(读文件)的文件流。
ofstream类:ostream的派生类,用来输出(写文件)的文件流
fstream类:iostream的派生类,把文家连接到流对象用来输入和输出。
使用文件流需要包含头文件< fstream>
II.字符串流
istringstream:istream的派生类,用来从string对象中读取数据。
ostringstream:ostream的派生类,用来向string对象写入格式化的内容。
stringstream:iostream的派生类,既可以读数据也可以写数据。