数组
数组是一种类似于标准库类型vector的数据结构,但是在性能和灵活性的权衡上又与vector有所不同。与vector相似的地方是,数组也是存放类型相同的对象的容器,这些对象本身没有名字,需要通过其所在位置访问。与vector不同的地方是,数组的大小确定不变,不能随意向数组中增加元素。因为数组的大小固定,因此对某些特殊的应用来说程序的运行时性能较好,但是相应地也损失了一些灵活性。
数组初始化
初始化数组要指定大小,如果不指定维度系统会根据初始化列表自动设置数组大小,但是不要将数组数组的大小小于列表长度,否则编译器会报错。
1 | void arrary_init() |
错误操作
不允许拷贝和赋值不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值:
1 | //含有3个整数的数组 |
复杂声明
和vector一样,数组能存放大多数类型的对象。例如,可以定义一个存放指针的数组。又因为数组本身就是对象,所以允许定义数组的指针及数组的引用。在这几种情况中,定义存放指针的数组比较简单和直接,但是定义数组的指针或数组的引用就稍微复杂一点了:
1 | void dif_array() |
数组访问
和vector一样,数组也支持下标访问和遍历访问
1 | void visit_array() |
指针和数组
在C++语言中,指针和数组有非常紧密的联系。使用数组的时候编译器一般会把它转换成指针。
通常情况下,使用取地址符来获取指向某个对象的指针,取地址符可以用于任何对象。
数组的元素也是对象,对数组使用下标运算符得到该数组指定位置的元素。
因此像其他对象一样,对数组的元素使用取地址符就能得到指向该元素的指针:
1 | //数组的元素是string元素 |
在一些情况下数组的操作实际上是指针的操作,这一结论有很多隐含的意思。其中一层意思是当使用数组作为一个auto变量的初始值时,推断得到的类型是指针而非数组:
1 | // ia是一个含有10个整数的数组 |
尽管ia是由10个整数构成的数组,但当使用ia作为初始值时,编译器实际执行的初始化过程类似于下面的形式:
1 | ia2是int*类型 |
必须指出的是,当使用decltype关键字时上述转换不会发生,decltype(ia)返回的类型是由10个整数构成的数组:
1 | // ia3是一个含有10个整数的数组 |
指针也是迭代器
就像使用迭代器遍历vector对象中的元素一样,使用指针也能遍历数组中的元素。当然,这样做的前提是先得获取到指向数组第一个元素的指针和指向数组尾元素的下一位置的指针。之前已经介绍过,通过数组名字或者数组中首元素的地址都能得到指向首元素的指针;不过获取尾后指针就要用到数组的另外一个特殊性质了。
1 | int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
我们可以设法获取数组尾元素之后的那个并不存在的元素的地址:
1 | int *e = &arr[10]; //指向arr尾元素的下一个位置的指针 |
这里显然使用下标运算符索引了一个不存在的元素,arr有10个元素,尾元素所在位置的索引是9,接下来那个不存在的元素唯一的用处就是提供其地址用于初始化e。就像尾后迭代器一样,尾后指针也不指向具体的元素。因此,不能对尾后指针执行解引用或递增的操作。
所以我们利用指针的末尾元素可以实现另一种方式的遍历
1 | for (int *b = arr; b != e; ++b) |
数组也支持sizeof操作sizeof计算的是数组所占用的空间,除以sizeof(int),得到的就是数组的长度,所以数组的遍历可以这样
1 | for (int i = 0; i < sizeof(arr) / sizeof(int); i++) |
标准库函数begin
尽管能计算得到尾后指针,但这种用法极易出错。为了让指针的使用更简单、更安全,C++11新标准引入了两个名为begin和end的函数。这两个函数与容器中的两个同名成员功能类似,不过数组毕竟不是类类型,因此这两个函数不是成员函数。正确的使用形式是将数组作为它们的参数:
1 | // beg指向arr第一个元素 |
通过begin和end函数获取数组第一个元素地址和最后一个元素的下一个位置,然后实现遍历,非常安全
指针运算
指向数组元素的指针包括解引用、递增、比较、与整数相加、两个指针相减等,用在指针和用在迭代器上意义完全一致。给(从)一个指针加上(减去)某整数值,结果仍是指针。新指针指向的元素与原来的指针相比前进了(后退了)该整数值个位置:
1 | int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
另外一种计算数组元素个数的方式
1 | int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
C风格字符串
C风格字符串被C++包含在cstring头文件里,包括strcmp字符串比较,strcpy字符串copy,strcat字符串连接
比较字符串
1 | const char cal1[] = "A string example"; |
字符串连接
字符串的连接用到了memset清空操作,以及strcpy, strcat等操作,大家看看就好不用深入理解,这是C语言的方式
1 | void c_string() |
习惯使用C语言的同学可以通过c_str()函数将string转化为const char*类型的字符串
1 | string strcpp = "CPP"; |
使用数组初始化vector对象
vector除了可以通过初始化列表,指定初始值和大小等方式外,还可以通过数组和vector初始化
通过vector初始化
1 | vector<int> v1 = {1, 3, 5, 7, 9}; |
通过数组初始化
1 | void vector_init2() |