一、一维数组

和vector对比,不可改变大小。C++尽量用vector代替数组。编译器一般把数组看成指针。

初始化

字符数组可以用字符串字面值初始化,注意别漏了结尾空字符。
数组不支持拷贝、赋值。

  1. /**************数组定义声明*****************/
  2. unsigned cnt = 42; // 不是常量表达式
  3. constexpr unsigned sz = 42; // 常量表达式
  4. int arr[10]; // 元素执行默认初始化
  5. int* parr[sz]; // 含有42个整型指针的数组
  6. string bad[cnt]; // 错误:定义数组时,维度必须是常量表达式,即编译时能确定值
  7. string strs[getsize()]; // 当getsize是constexpr时正确;否则错误
  8. int* ptrs[10]; // 整形指针数组,从右往坐看,显示数组,再是int *元素
  9. int &refs[10] = /* ?*/; // 错误:数组元素不能是引用
  10. int( *Parray )[10] = &arr; // 指针指向数组,有()从里往外看,先是指针,再看到数组。
  11. int( &arrRef )[10] = arr; // 数组的引用,同上方法看
  12. int* ( &arry )[10] = ptrs; // 数组的引用,数组是int*数组。先从里往外,再从右往左。
  13. /**************数组初始化*****************/
  14. const unsigned sz = 3;
  15. int ial[sz] = { 0, 1, 2 }; // 含有 3 个元素 的数组,元素值分别是 0, 1 , 2
  16. int a2[] = { 0, 1, 2 }; // 维度是 3 的数组
  17. int a3[5] = { 0, 1, 2 }; // 等价于{0, 1, 2, 0, 0},后面两个执行默认初始化
  18. string a4[3] = { "hi ", "bye" }; // 等价于{"hi","bye",""},最后一个执行默认初始化
  19. int a5[2] = { 0, 1, 2 }; // 错误:初始值过多
  20. /***************字符数组初始化**********************/
  21. char al[] = { 'C', '+', '+' }; // 列表初始化
  22. char a3[] = "C++"; // 维度是4,有空字符
  23. const char a4[6] = "Daniel"; // 错误:没有空间可存放空字符!
  24. /************数组间不支持拷贝赋值********************/
  25. int a[] = {0, 1, 2};
  26. int a2[] = a; // 错误:不允许使用一个数组初始化另一个数组
  27. a2 = a; // 错误:不能把一个数组直接赋值给另一个数组

元素访问

[]下标运算符访问。
数组下标类型size_t,机器相关的无符号类型,足以表示任意对象的大小,在C++的C标准库头文件cstddef中定义。

指针和数组

数组类型对象,就是在指向数组的首元素的指针。
指针也是迭代器。

  1. string nums[] = { "one", "two" , "three" }; // 数组的元素是string对象
  2. string *p = &nums[0]; // p指向nums[0]
  3. string *p2 = nums; // 等价
  4. auto ia2( nums ); // ia2是指针,指向首元素
  5. decltype(nums) ia3 = { "one", "two" , "three" };
  6. ia3 = p; // 错误:ia3是数组,不是指针
  7. int arr[] = {0,1,2,3,4,5,6,7,8,9};
  8. int *p = arr; //p指向arr的第一个元素
  9. ++p; //p指向arr[1]
  10. int *p1 = &arr[3], *p2 = &arr[5];
  11. ptrdiff_t distance = p1 - p2; // 有符号类型,类似size_t机器相关,cstddef头文件定义
  12. count << *p1 + 4 << endl; // 等价于(*p1)+4
  13. // 运算符顺序:一元 > 二元 > 三元
  14. // 运算符顺序:算术 > 关系 > 逻辑运算符。
  15. char *str = string("asdfasd"); //错误

数组迭代器

标准库函数begin、end,和标准容器迭代器一样,但是前者同样适用于数组,所以可以统一用前者。

  1. int i[] = {0 , 1 , 2 , 3} ;
  2. int *beg = begin(ia) ; // 指向ia首元素的指针
  3. int *last = end(ia) ; // 指向arr尾元素下一位置的指针
  4. int int_arr[] = {0, 1, 2, 3, 4, 5} ;
  5. vector<int> ivec(begin(int_arr), end(int_arr)); // 数组来初始化容器vector

C风格字符串

C规定,字符串必须以\0空字符结束。
C++为了兼容C,保留了C风格字符串(字符串字面值)。

C字符串操作函数
string = C字符串 + 字符串操作函数。(数据结构的基本定义:结构+操作)

  1. strlen(p) // 返回 p 的长度,空字符不计算在内
  2. strcmp(p1, p2) // 如果 p1 == p2, 返回0
  3. // 如果 p1 > p2,返回一个正值
  4. // 如果 p1 < p2,返回一个负值
  5. strcat(p1, p2) // 将p2附加到p1之后,返回p1
  6. strcpy(p1, p2 ) // 将p2拷贝给p1,返回p1

二、多维数组

  1. // 注意区分多维数组和指针数组
  2. int arr[3][4]; // 多维数组,内存空间连续
  3. int* arr[3]; // 指针数组,元素是指针。

如何理解多维数组?可以认为是数组的数组,即数组的元素是数组。
当一个数组的元素仍然是数组,我们可以用两个维度来定义:第一个维度是数组的大小,第二个维度是元素的大小

  1. int arr[2][3];
  2. // 第一个维度:[2],是arr数组的大小,有2个元素
  3. // 第二个维度:[3],是arr数组元素大小,是int[3]数组。
  4. int arr[10][20][30];
  5. // 1、arr[10][20],arr是一个长度为10的数组,元素是大小为20的数组
  6. // 2、[20][30],是一个长度为20的数组,元素是int[30]数组。

定义、初始化

  1. int ia[3][4] = {
  2. {0, 1, 2, 3}, //花括号不是必需的。
  3. {4, 5, 6, 7},
  4. {8, 9, 10, 11}
  5. );
  6. int ia[3][4] = { { 0 }, { 4 }, { 8 }}; // 显式地初始化每行的首元素
  7. int ix[3][4] = {0, 3, 6, 9}; // 显式地初始化第 1 行,其他元素执行值初始化
  8. ia[2][3] = arr[0][0][0]; // 用arr的首元素为ia最后一行的最后一个元素赋值
  9. int (&row)[4] = ia[1]; // 数组的引用:把row绑定到ia的第二个4元素数组上
  10. int ia[3][4]; // 大小为3的数组,每个元素是含有4个整数的数组
  11. int (*p)[4] = ia; // 数组的指针:p指向含有4个整数的数组,从内往外解析。
  12. int *ip[4]; // 注意和上面的区别,这是int*元素的数组。
  13. p = &ia[2]; // p指向ia的尾元素

遍历

多数数组遍历方法很多,尽量使用C++写法,避免使用C的东西(下标索引、指针)。

1、范围for遍历(C++)

除了最内层循环,其他层循环都必须是引用。

  1. int ia[3][4] ; //12个未初始化的元素
  2. for(auto &row : ia); // row的类型是4元素数组引用
  3. for(auto row : ia); // row是int*,编译器将其转成了指向首元素指针。
  4. size_t cnt = O;
  5. for(auto &row : ia ) // 注意!!除了最内层循环,都应该使用引用类型
  6. //for(auto row : ia ) // 编译错误:编译器将row转成了int*指针,显然它是无法进行循环的。
  7. for(auto &col : row) { // 最内层循环,col不做要求。
  8. col = cnt ;
  9. ++cnt ;
  10. }

2、迭代器遍历(C++)

  1. int ia[rowCnt][colCnt] ; //12个未初始化的元素
  2. for (auto p = begin(ia); p != end(ia); ++p) { // p指向ia的第一个数组
  3. for (auto q = begin(*p) ; q != end(*p); ++q) // q指向内层数组的首元素
  4. cout << *q << ''; // 输出q所指的整数值

3、数组下标遍历(C)

  1. int ia[rowCnt][colCnt] ; //12个未初始化的元素
  2. for (size_t i = 0 ; i != rowCnt ; ++i) // 注意数组下标索引是size_t类型
  3. for (size_t j = O; j != colCnt; ++j)
  4. ia[i][j] = i * colCnt + j;

4、指针遍历(C)

  1. int ia[3][4] ; //12个未初始化的元素
  2. for(auto p = ia; p != ia + 3; ++p) { // p指向含有4个整数的数组,元素是数组。
  3. for (auto q = *p ; q != *p + 4; ++q)// q指向4个整数数组的首元素,也就是说,q指向一个整数
  4. cout << *q << ' ';
  5. cout << endl ;
  6. }

类型别名,简化遍历。

  1. int ia[rowCnt][colCnt] ; //12个未初始化的元素
  2. using int_array = int[4]; // 新标准下类型别名的声明
  3. // typedef int int_array[4); // 等价的 typedef 声明
  4. for (int_array *p = ia ; p != ia + 3; ++p) {
  5. for (int *q = *p; q != *p + 4; ++q)
  6. cout << *q <<' ';