数组
声明格式
typeName arrayName [arraySize]; //arraySize不能是变量,可以是整型常数、const、常量表达式
下标:months[0]是数组months的第一个元素;sizeof months
表示计算整个数组中的字节数
初始化规则
只有在定义数组时才能使用初始化;可通过下标分别给元素赋值。若只对数组一部分初始化,则编译器把其它元素设置为0。若初始化数组时[ ]内为0,则自动计算元素个数。
C++11数组初始化方法
可省略等号;可不在{ }内包含任何东西,即所有元素设置为0;列表初始化禁止缩窄转换。
字符串
比较strlen()
与sizeof
标准头文件cstring中库函数strlen()返回存储在数组中字符串的长度,只计算可见字符,不计算空字符;而sizeof指出整个数组长度。
每次读取一行字符串输入
istream中的类(cin)提供了一些面向行的类成员函数:getline()
和get()
。它们都读取一行输入,直到换行符,而getline()
将丢弃换行符,get()
将换行符保留在输入序列中。
getline()
函数读取整行,通过回车键输入的换行符确定输入结尾,但不保存换行符。
cin.getline(name,20);
//将姓名读入到包含20个元素的数组name中
get()
函数将换行符保留在输入队列中;使用不带任何参数的cin.get()调用可读取下一个字符(即使是换行符)。
拼接
cin.get (name,ArSize).get( );
cin.getline(name1,ArSize).getline(name2,ArSize); //把输入中连续的两行分别读入数组name1、name2中,其效果与两次调用cin.getline()相同。
cin.clear()
当get()
读取空行后将设置失效位(failbit),意味着接下来的输入将被阻断,恢复输入需要使用cin.clear()
String类简介
头文件string要包含,string类位于名称空间std中,需提供一条using编译指令,或使用std::string
来引用它。
String对象和字符数组间主要区别:可将string对象声明为简单变量 ,而不是数组,C++11允许将列表初始化为用于C-风格字符串和string对象。
- 可将一个string对象赋给另一个string对象;可使用运算符
+
将两个string对象合并,也可用运算符+=
将运算符附加到string对象的末尾。 - 头文件
cstring
提供函数strcpy()
将字符串复制到字符数组中,strcat()
将字符串附加到字符数组末尾。
strcpy(char1,char2); //copy char2 to char1
strcat(char1,char2); //append contents of char2 to char1
两种确定字符串中字符数的方法:
int len1=strl.size( ); //obtain length of str1
int len2=strlen(char1); //obtain length of char1
- 未被初始化的string对象的长度被自动设置为0.
cin.getline(charr,20); //charr—目标数组、20—数组长度
getline(cin,str); //cin作为参数查找输入位置,string自动调整大小
- 类型
wchar_t/char16_t/char32_t
分别由前缀L/u/U
表示。 - 原始字符串(raw):将
”(
和)”
用作定界符,并用前缀R
来标识原始字符串。在其中,字符表示的就是自己。它允许在字符串开头的”
和(
之间添加其它字符,且在结尾也须包含。 如R “+*(……)+*”
eg:cout<<R”+*(“(who wouldn’t ?)”, she whispered.)+*”<<endl;
显示:”(who wouldn’t ?)”, she whispered.
结构简介
结构是用户定义的类型,而结构声明定义了这种类型的数据属性。结构定义描述:
struct inflatable
{
char name[20];
float volume; //结构成员(每个列表项都是声明语句)
double price;
};
//初始化:
inflatable guest =
{
“Awst Lee”, //name value
1.88, //volume value
29.99 //price value
};
- 与数组一样,由逗号分隔值列表。使用guest.name、guest.volume来访问结构成员,
guest.name[0]
是字符A;通常使用外部结构声明,使得所有函数都能使用这种类型的结构。 - 结构初始化(支持列表初始化,且符号=是可选的)
inflatable guest { “Awst Lee”, 1.88 , 29.99 } ;
若大括号内未包含任何东西,则各成员设置为0,不允许缩窄转换。 - 结构可将string类作为成员,但要让结构定义能访问名称空间std。编译指令using移到结构定义之前,或类型声明为std::string.
- 成员赋值有效。可同时完成定义结构和创建结构变量,只需要将变量名放在结束括号的后面。
- 结构数组
inflatable guest[2] =
{
{“Bambi”, 0.5 , 21.99},
{“Awst”, 200 , 34.88}
};
//创建一个包含100个inflatable结构的数组:
inflatable gifts[100];
cin>>gifts[0].volume ;
cout<<gifts[99].price;
共用体(union)
一种数据格式,能够存储不同数据类型,但只能同时存储其中的一种类型。
union one4all
{
int int_val;
long long_val;
double double_val;
};
one4all pail;
pail.int_val = 15;
pail.double_val = 1.38; //pail有时是int变量,有时是double变量
共用体每次只存储一个值,即union的长度为其最大成员的长度。用途:当数据项使用两种或多种格式(不同时使用)时,可节省内存空间。常用于操作系统数据结构或硬件数据结构。
枚举(enum)–可代替const创建符号常量
如:
enum spectrum {red, orange, yellow, green, blue, violet } ; //让spectrum成为新类型的名称;spectrum被称为枚举(enumeration);
将red、orange、yellow等作为符号常量,对应整数值0~5,这些常量叫枚举量。
设置枚举量的值
enum {zero, null = 0, one, numero = 1};
//后面未被初始化的枚举量将比其前面的大1,即one的值为1.
枚举的取值范围
取值上限:比枚举量中最大值大的最小2的幂并减1.
取值下限:若枚举量中最小值>=0,则下限为0;否则和取上限方法一样,前面加负号。
enum bits { one=-6, two = 2, eight = 8 }; //取值范围[-7, 15]
在不进行强制类型转换情况下,只能将定义枚举时使用的枚举量赋给这种枚举的变量,且其只定义了赋值运算符。枚举量是整型,可被提升为int类型,但int不能自动转为枚举型。用于算术表达式中时,枚举将被转换为整数。
指针和自由存储空间
int updates = 6;
int *p_updates = & updates;
指针名p_updates
表示地址(&updates),*
运算符被称为间接值或解除引用运算符。*p_updates = updates = 6
.
声明和初始化指针(在声明语句中初始化)
指针声明必须指定指针指向数据的类型;*
运算符两边空格可选(p_updates
是指针/地址,而*p_updates
是int而不是指针)
下面的声明创建一个指针(p1)和一个int型变量(p2):
int *p1, p2;
指针的危险
C++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向数据的内存。
一定要在对指针应用解除运算符(*
)之前,将指针初始化为一个确定的、适当的地址。
要将数字值作为地址来使用,应通过强制类型转换将数字转换为适当的地址类型
int *pt ;
pt = (int*) 0xB8000000;
使用new来分配内存
为一个数据对象(可以是结构、基本类型)获得并指定分配内存的格式:
typeName * pointer_name = new typeName;
new运算符根据类型来确定需要多少字节的内存,然后找到这样的内存并返回其地址,接下来将地址赋给pointer_name,也就是被声明为指向typeName的指针。
常规变量的值被存储在栈的内存区域中,而new从堆(或自由存储区)分配内存。在C++中,值为0的指针为空指针(不指向有效数据),常用来表示运算符或函数失败(若成功则返回一个有用指针)。
使用delete
释放内存
使用delete时,后面要加上指向内存块的指针。
int *ps = new int;
……
delete ps; //释放ps指向的内存,但不会删除指针ps本身
只能用delete来释放使用new分配的内存;不能释放已经释放的内存块,不能使用delete来释放声明变量所获得的内存。
使用new
创建动态数组
静态联编:在编译时给数组分配内存。必须在编写程序时指定数组长度
动态联编:程序运行时创建数组。程序运行时确定数组长度
使用new
创建动态数组(告诉new元素类型、数目)
int *psome = new int[10]; //new 运算符返回第一个元素地址
……
delete [ ] psome; //程序使用完new分配的内存块后应释放
若new带方括号,则delete也带方括号;new不带[ ] ,delete也不带[ ].
注意:
- 不要使用delete来释放不是new分配的内存。
- 不要使用delete释放同一个内存两次。
- 若使用new [ ] 为数组分配内存,则应用delete [ ] 来释放。
- 若用new为一个实体分配内存,则应用delete(无方括号)来释放。
- 为数组分配内存格式:
type_name* pointer_name = new type_name[num_elements];
- 使用new运算符可以确保内存块足以存储num_elements个类型为type_name的元素,而pointer_name将指向第一个元素。
使用动态数组(把指针当做数组名使用)
第一個元素和地址
C++内部都使用指针来处理数组,数组和指针基本等价。对于第一个元素可用psome[0]
,而不是*psome;第二个元素psome[1]. 数组名不能修改,但指针时变量可修改其值(加1后指向下一个元素地址)
指针、数组、指针算术
指针、数组基本等价的原因在于指针算术和C++内部处理数组的方式;将指针变量加1后,增加的量等于它指向的类型的字节数;C++将数组名解释为地址(数组第一个元素的地址)
使用数组表示法时
arrayname[i] => *(arrayname+i)
使用指针时,C++执行同样的转换:
pointername[i] => *(pointername+i)
数组名被解释为其第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址。
short tell[10];
cout<<tell<<endl; //display &tell[0]
cout<<&tell<<endl; //display address of whole array
数字上这两地址相同,表达式tell+1
将地址值+2, &tell+1
将地址加20.
数组指针:[*p](n)
—指针p指向一个长度为n的一维数组。
指针数组:*p[n]
—数组p有n个指针类型的元素
对指针解除引用意味着获得指针指向的值
绝不要对未被初始化为适当地址的指针解除引用
字符与地址
在cout和多数表达式中,char数组名、char指针以及用引号括起的字符串常量都被解释为字符串中第一个字符的地址。若给cout提供一个字符的地址,则它将从该字符开始打印,直到遇到空字符为止。
一般的,若给cout提供一个指针,它将打印地址。但若指针类型为char*
,则cout将显示它指向的字符串;若要显示字符串地址,则需将这种指针强制转换为另一种类型的指针类型,如int* (char *)ps; cout<<(int*)ps;)
初始化数组
使用“=”运算符;否则应使用strcpy( )
或strncpy( )
.
strcpy(array, string_s) ;//若string_s长度大于array, 则使用strncpy( ).
strncpy(path ,src ,sizeof(path)-1); //将src的前sizeof(path)位字符复制到path,留path[sizeof(path)-1] = ‘\0’ ; //一位给空字符(字符串结尾)
将字符串赋给数组时应使用strcpy()
或strncpy()
.
通过使用new
可以创建动态结构
创建结构:inflatable *ps = new inflatable ;
//把存储inflatable结构的一块可用内存的地址赋给指针ps。
访问成员:箭头运算符(->),可用于指向结构的指针,就像点运算符可用于结构名一样。
指定结构成员:结构标识符是结构名—句点运算符/(*ps).price
标识符是指向结构的指针—箭头运算符/ps->price
三种管理数据内存的方法
自动存储
自动变量:在函数内部定义的常规变量使用自动存储空间,是局部变量,作用域为包含它的代码块。通常存储在栈中(后进先出)。
静态存储
整个程序执行期间都存在的存储方式。(函数外定义或在声明时使用static)。
new
和delete
管理的内存池(自由存储空间或堆)
数据的生命周期不完全受程序或函数的生存时间控制,但也使得跟踪新分配内存的位置更困难。
应同时使用new和delete运算符,在自由存储空间上动态分配内存、随后释放它。
数组的替代品
模板类vector:使用new创建动态数组的替代品
要使用vector对象,须包含头文件vector,且包含在名称空间std中。一般而言,下面的声明创建一个名为vt的vector对象,它可存储n_elem个类型为typeName的元素: vector<typeName> vt(n_elem);
其中参数n_elem可以是整型常量,也可是整型变量。
模板类array
要创建array对象,须包含头文件array,且包含在名称空间std中。下面的声明创建一个名为arr的array对象,它包含n_elem个类型为typeName的元素:
array <typeName, n_elem> arr ;
其中n_elem不能是变量。
vector类—功能比数组强,效率低
对于长度固定的数组—不方便也不安全。
array—效率与数组相同,更方便也更安全。
array对象和数组存储在相同的内存区域(栈)中,而vector对象存储在另一个区域(自由存储区或堆)中。可将一个array对象赋给另一个array对象,而对于数组必须逐元素复制数据。
三者都可用标准数组表示法来访问各个元素。
可用vector和array对象的成员函数at()
:
vector <double> a2(4) ; //create vector with 4 elements
a2.at(1) = 2.3; //assign 2.3 to a2[1]
中括号表示法和成员函数at()的差别在于,使用at()时,将在运行期间捕获非法索引,而程序默认将中断。这种额外检查的代价是运行时间更长。