首先需明确,现代C++程序应尽量使用vector和迭代器类型,而避免使用低级的数组和指针。设计良好的程序只有在强调速度时才在类实现的内部使用数组和指针。
一、数组
1、数组的定义和初始化
(1)数组的维数必须用值大于等于1的常量表达式定义。此常量表达式只能为:整型字面值常量、枚举常量或者用常量表达式初始化的整型const对象(此处的“数组”不包括“动态数组”)。
(2)若没有显式的提供元素初值,则数组元素会像普通变量一样初始化(函数体外定义,内置类型数组,均初始化为0;函数体内定义,内置类型数组,均无初始化)。
(3)字符数组有两种方式初始化:
a、用一组由花括号括起来、逗号隔开的字符字面值初始化;
b、用一个字符串字面值进行初始化。
注意,C++中所有的字符串字面值都由编译器自动在末尾添加一个空字符'\0'。若使用a方法初始化,记得显式添加'\0'。最好使用b方法初始化。
但是,用字符串字面值初始化一个string对象时,空字符'\0'并不加入string对象中。
(4)数组不允许直接复制和赋值。此外,只有字符数组或char型指针可由cout直接输出,其他类型数组,必须显式的循环输出每个元素。
2、数组操作
(1)数组下标的正确类型为size_t(定义在cstddef头文件中,机器相关的无符号整型),vector的下标类型为vector<T>::size_type,string的下标类型为string::size_type。
(2)必须保证数组下标值在正确范围之内。
二、指针
1、指针的定义和初始化
(1)指针的数据类型是指针所指向的对象的类型。
(2)两种声明指针的风格:
string *pstring;
string* pstring;
建议使用第一种。
(3)指针可能的取值有三种:保存一个特定对象的地址;指向某个对象后面的另一对象;0值(Null)。若指针保存0值,表明它不指向任何对象。
(4)避免使用未初始化的指针。
C++语言无法检测指针是否未被初始化。
如果可能的话,除非所指向的对象已经存在,否则不要先定义指针。
如果必须分开定义指针和其所指向的对象,则将指针初始化为0(Null)。
(5)C++中的void * 指针。
void * 指针可以保存任何类型对象的地址,它表明该指针与一地址值相关,但不清楚存储在此地址上的对象的类型。
void * 指针仅支持几种操作:与另一个指针进行比较;向函数传递void * 指针或从函数返回void * 指针;给另一个void * 指针赋值。不允许使用void * 指针操作它所指向的对象。
2、指针操作
(1)指针与引用的比较。
区别一,引用总是指向某个对象,且定义引用时必须同时初始化;
区别二,给引用赋值修改的是该引用所关联的对象的值。
(2)指针是数组的迭代器。内置数组类型具有标准库容器的许多性质。
3、指针与const限定符
(1)指向const对象的指针
a、可以把指向const对象的指针理解为“自以为指向const对象的指针”。因为这种指针既可以指向const对象,也可以指向非const对象。但是由于系统没法分辨所指向的对象是否为const,因此系统会把它所指的对象都视为const。如此一来,不允许利用这种指针修改所指向的对象(对于非const对象来说,当然可以通过其他方法修改对象值)。
b、
const double *cptr;
const void *cpv;
const限定了cptr指针所指向的对象类型,而非cptr本身。因此,cptr本身并不是const,在定义时无需初始化,且允许给cptr重新赋值,使其指向另一个const(或非const)对象。
c、实际程序中,指向const对象的指针常用作函数的形参。有两个好处,一是此形参既可以接受const对象,也可以接受非const对象;二是确保传递给函数的实际对象在函数中不因为形参而被修改。
(2)const指针
a、const指针——指针本身的值不能修改。在定义时必须同时初始化,且初始化之后,不能使这个指针再指向其他对象。
int errNumb = 0;
int *const curErr = &errNumb;
b、const指针所指对象的值能否修改完全取决于该对象的类型。
(3)指向const对象的const指针
首先是个const指针,其指向一个const对象。兼具(1)(2)所述两种性质。
const double pi = 3.14159;
const double *const pi_ptr = π
(4)const限定符既可以放在类型前面,也可以放在类型后:
string const s1;
const string s2;
放在类型前面更常见,但是放在类型后面更有助于理解。
三、C风格字符串
1、C风格字符串
(1)C风格字符串是以空字符null结束的字符数组。字符串字面值是该类型的实例。
(2)处理C风格字符串的库函数的头文件为:cstring。这是string.h头文件的C++版本。
(3)在使用cstring中的库函数处理C风格字符串时,牢记字符串必须以结束符null('\0')结束。strlen(s),返回s的长度,不包括字符串结束符null。
2、动态数组
(1)动态分配的数组不必在编译时知道其长度(动态数组的维度可以为普通变量),通常在运行时才确定数组长度。
(2)动态分配数组时,如果数组元素具有类类型,将使用该类的默认构造函数实现初始化;若数组元素是内置类型,则无初始化。也可使用跟在数组长度后的一对空圆括号做初始化(但也只能初始化为元素类型的默认值,无法初始化为指定值)。
int *pia = new int[20]();
(3)必须显式的释放动态空间,对于二维动态数组,先释放内层,再释放外层。
for(size_t i = 0; i != arr_size; ++i)
delete [] p[i];
delete [] p;
3、新旧代码兼容
(1)c_str函数返回C风格字符串,返回指向字符数组首地址的指针(此指针指向const char类型的数组),该数组存放了与string对象相同的内容,并且以结束符null结束。
string st("Hello world!");
const char *str = st.c_str();
(2)使用数组初始化vector对象
使用数组初始化vector对象,需指出用于初始化式的第一个元素及数组最后一个元素的下一位置的地址:
const size_t arr_size = 3;
int int_arr[arr_size] = {1, 2, 3};
vector<int> ivec(int_arr, int_arr + arr_size);
4、指向数组的指针与指针数组
int *ip[4]; //array of pointers to int
int (*ip)[4]; //pointer to an array of 4 ints
第一个为指针数组,第二个为指向含有4个元素的数组的指针。