《c++ primer》3.5 array 小结

array的长度是静态的,即在编译阶段就已经确定。没有 vector 灵活,但性能一般更强。

1. 声明

维数必须是一个 constant expression,另外数组中每个单元必须指明类型(不能用auto),必须是对象,不能是别名(reference)。

1 int arr[10];
2 int *parr[sz]; // 42 个整数指针
3 string str[ get_size() ]; // 如果 get_size() 返还常数表达式就ok,否则错误

 

2. 初始化

int ia1[3] = {0,1,2};
int ia1[] = {0,1,2}; // 自动确定维数为3
int ia1[5] = {0,1,2}; // 自动将后2个元素初始化为0
string a4[3] = {"hi", "bye"}; //自动将最后一个元素初始化为""

 

3. 字符数组

字符数组多一个隐含的元素 \0 在末尾,作为结束的标志。

char a1[] = {'C', '+', '+'};//长度实际为4,自动增加 '\0'
char a4[6] = "Daniel"; //错误,没有空间给隐含的 '\0'

 

4. 指向数组的指针

int * ptrs[10]; // ptrs 是10个整数指针构成的数组
int (*Parray) [10] = & arr; // Parray 是指向数组arr 的指针,arr由10个整型构成
int (&arrRef) [10] = arr; // arrRef 是数组 arr 的别名,arr 由10个整型构成
int * (&arry) [10] = ptrs; // ptrs 是 10 个指向整型的指针构成的数组,arry 是它的别名

 

5. 引用数组的单元

可以用下标,也可以用 range for。下标范围是 0, 1, n-1,其中n为维数。下标应为 size_t 类型,size_t 无符号,可以足够大,在 cstddef 头文件中。

如果要遍历所有单元,用 range for 是更好的选择,

unsigned scores[11] = {};
for( auto i: scores)
    cout<< i << " ";
cout<<endl;

 

6. 指针与数组

实际上,数组就是用指针实现的。

string num[] = {"one", "two", "three"};// num 也是一个指针,指向第一个元素

 

7. begin, end 函数

指针是一种迭代器,但数组不是类,所以没有成员函数 begin(), end(),于是 library 提供了 begin(arr), end(arr) 函数

int *pbeg = begin(arr), *pend = end(arr); 
while( pbeg != pend && *pbeg >=0) // 寻找整数数组中第一个负整数
    ++pbeg;

不可以dereference 或者增加 end(arr)指针,因为 end(arr) 指向的是数组外的地址。

因为指针是迭代器,所以其他迭代器的操作也适用,比如加上一个整数(若指向数组外,除了end(arr)以外的值是错误的),两个指针相减,比大小。

下标符号[] 可以用在任何指针上,只要得到的元素再数组内。

int ia[] = {0,2,4,6,8};
int *p = & ia[2]; // p 指向元素4
int k = p[-2]; // k  = ia[0] = 0

所以下标可以是负整数,只要得到的元素仍在数组内就行。

 

 8. C风格的字符串

 我记得谭浩强老师的C++教程就是沿用的C风格的字符串,它是如下表示的:

char a[80] = "hahaha"; // 自动用'\0'结束,即 a[6]='\0'

默认用 '\0' 表示字符串内容的结束,数组长度必须大于等于字符串长度+1。

library提供了一些函数对这种风格的字符串进行操作

strlen(p)            字符串p的长度,不包括'\0'即null字符
strcmp(p1,p2)    比较两个字符串,①比较长度,②按字典顺序比较字符
strcat(p1,p2)        将 p2 的内容追加到 p1,然后返回 p1
strcpy(p1, p2)        将 p2 的内容赋值给 p1,返回 p1

上面这些函数都不能保证字符数组长度够用,字符数组长度够用必须由程序员来手动保证。

所以很容易发生错误。c++提倡使用 vector 和 string类型,而不是 数组 和 C风格的字符串。但有些代码是用后者写的,需要跟那些代码打交道,所以c++的 library 提供了办法处理这些过时的对象。

const char * str = s.c_str(); //  string 类 s 的内容变成一个C风格的字符数组并返还首字符的指针

可以调用 string 的成员函数 c_str,返还一个C风格字符数组的指针,但如果此后改变了 string s,这个指针可能会出现错误,所以改变之前先 copy str[] 里面的内容。

 

9. 用数组来初始化vector

int int_arr[] = {0, 1, 2, 3, 4, 5};
vector<int> ivec( begin(int_arr), end(int_arr) ); // ivec 的内容为 arr 中的所有成员
vector<int> subVec( int_arr+1, int_arr+4 ); // subVec 的内容为 1,2,3,4

 

10. 多维数组

没有多维数组,多维数组实则是基本单元是数组的数组。

int ia[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11}; //编译器自动分行
int ia[3][4] = {0,3,6,9}; //第一行元素为 0,3,6,9,其他元素赋0 (value-initialized)

可用 range for 来遍历多维数组

size_t cnt = 0;
for( auto &row : ia)
    for( auto &col : row){
        col = cnt;
        cnt++;
    }

这里 row, col 必须用别名,否则,ia 的成员是指向 4元素数组 的指针,row  会是一个这样的指针,但没有下一步单元,所以内层循环会错误。

所以,用 range for 来遍历多维数组时,除了内层以外,其他各层的循环变量都必须是别名。所以全用别名就完事了。

posted on 2020-04-13 13:49  luyi07  阅读(167)  评论(0编辑  收藏  举报

导航