一、一维数组
和vector对比,不可改变大小。C++尽量用vector代替数组。编译器一般把数组看成指针。
初始化
字符数组可以用字符串字面值初始化,注意别漏了结尾空字符。
数组不支持拷贝、赋值。
/**************数组定义声明*****************/
unsigned cnt = 42; // 不是常量表达式
constexpr unsigned sz = 42; // 常量表达式
int arr[10]; // 元素执行默认初始化
int* parr[sz]; // 含有42个整型指针的数组
string bad[cnt]; // 错误:定义数组时,维度必须是常量表达式,即编译时能确定值
string strs[getsize()]; // 当getsize是constexpr时正确;否则错误
int* ptrs[10]; // 整形指针数组,从右往坐看,显示数组,再是int *元素
int &refs[10] = /* ?*/; // 错误:数组元素不能是引用
int( *Parray )[10] = &arr; // 指针指向数组,有()从里往外看,先是指针,再看到数组。
int( &arrRef )[10] = arr; // 数组的引用,同上方法看
int* ( &arry )[10] = ptrs; // 数组的引用,数组是int*数组。先从里往外,再从右往左。
/**************数组初始化*****************/
const unsigned sz = 3;
int ial[sz] = { 0, 1, 2 }; // 含有 3 个元素 的数组,元素值分别是 0, 1 , 2
int a2[] = { 0, 1, 2 }; // 维度是 3 的数组
int a3[5] = { 0, 1, 2 }; // 等价于{0, 1, 2, 0, 0},后面两个执行默认初始化
string a4[3] = { "hi ", "bye" }; // 等价于{"hi","bye",""},最后一个执行默认初始化
int a5[2] = { 0, 1, 2 }; // 错误:初始值过多
/***************字符数组初始化**********************/
char al[] = { 'C', '+', '+' }; // 列表初始化
char a3[] = "C++"; // 维度是4,有空字符
const char a4[6] = "Daniel"; // 错误:没有空间可存放空字符!
/************数组间不支持拷贝赋值********************/
int a[] = {0, 1, 2};
int a2[] = a; // 错误:不允许使用一个数组初始化另一个数组
a2 = a; // 错误:不能把一个数组直接赋值给另一个数组
元素访问
[]下标运算符访问。
数组下标类型size_t,机器相关的无符号类型,足以表示任意对象的大小,在C++的C标准库头文件cstddef中定义。
指针和数组
数组类型对象,就是在指向数组的首元素的指针。
指针也是迭代器。
string nums[] = { "one", "two" , "three" }; // 数组的元素是string对象
string *p = &nums[0]; // p指向nums[0]
string *p2 = nums; // 等价
auto ia2( nums ); // ia2是指针,指向首元素
decltype(nums) ia3 = { "one", "two" , "three" };
ia3 = p; // 错误:ia3是数组,不是指针
int arr[] = {0,1,2,3,4,5,6,7,8,9};
int *p = arr; //p指向arr的第一个元素
++p; //p指向arr[1]
int *p1 = &arr[3], *p2 = &arr[5];
ptrdiff_t distance = p1 - p2; // 有符号类型,类似size_t机器相关,cstddef头文件定义
count << *p1 + 4 << endl; // 等价于(*p1)+4
// 运算符顺序:一元 > 二元 > 三元
// 运算符顺序:算术 > 关系 > 逻辑运算符。
char *str = string("asdfasd"); //错误
数组迭代器
标准库函数begin、end,和标准容器迭代器一样,但是前者同样适用于数组,所以可以统一用前者。
int i[] = {0 , 1 , 2 , 3} ;
int *beg = begin(ia) ; // 指向ia首元素的指针
int *last = end(ia) ; // 指向arr尾元素下一位置的指针
int int_arr[] = {0, 1, 2, 3, 4, 5} ;
vector<int> ivec(begin(int_arr), end(int_arr)); // 数组来初始化容器vector
C风格字符串
C规定,字符串必须以\0空字符结束。
C++为了兼容C,保留了C风格字符串(字符串字面值)。
C字符串操作函数
string = C字符串 + 字符串操作函数。(数据结构的基本定义:结构+操作)
strlen(p) // 返回 p 的长度,空字符不计算在内
strcmp(p1, p2) // 如果 p1 == p2, 返回0
// 如果 p1 > p2,返回一个正值
// 如果 p1 < p2,返回一个负值
strcat(p1, p2) // 将p2附加到p1之后,返回p1
strcpy(p1, p2 ) // 将p2拷贝给p1,返回p1
二、多维数组
// 注意区分多维数组和指针数组
int arr[3][4]; // 多维数组,内存空间连续
int* arr[3]; // 指针数组,元素是指针。
如何理解多维数组?可以认为是数组的数组,即数组的元素是数组。
当一个数组的元素仍然是数组,我们可以用两个维度来定义:第一个维度是数组的大小,第二个维度是元素的大小。
int arr[2][3];
// 第一个维度:[2],是arr数组的大小,有2个元素
// 第二个维度:[3],是arr数组元素大小,是int[3]数组。
int arr[10][20][30];
// 1、arr[10][20],arr是一个长度为10的数组,元素是大小为20的数组
// 2、[20][30],是一个长度为20的数组,元素是int[30]数组。
定义、初始化
int ia[3][4] = {
{0, 1, 2, 3}, //花括号不是必需的。
{4, 5, 6, 7},
{8, 9, 10, 11}
);
int ia[3][4] = { { 0 }, { 4 }, { 8 }}; // 显式地初始化每行的首元素
int ix[3][4] = {0, 3, 6, 9}; // 显式地初始化第 1 行,其他元素执行值初始化
ia[2][3] = arr[0][0][0]; // 用arr的首元素为ia最后一行的最后一个元素赋值
int (&row)[4] = ia[1]; // 数组的引用:把row绑定到ia的第二个4元素数组上
int ia[3][4]; // 大小为3的数组,每个元素是含有4个整数的数组
int (*p)[4] = ia; // 数组的指针:p指向含有4个整数的数组,从内往外解析。
int *ip[4]; // 注意和上面的区别,这是int*元素的数组。
p = &ia[2]; // p指向ia的尾元素
遍历
多数数组遍历方法很多,尽量使用C++写法,避免使用C的东西(下标索引、指针)。
1、范围for遍历(C++)
除了最内层循环,其他层循环都必须是引用。
int ia[3][4] ; //12个未初始化的元素
for(auto &row : ia); // row的类型是4元素数组引用
for(auto row : ia); // row是int*,编译器将其转成了指向首元素指针。
size_t cnt = O;
for(auto &row : ia ) // 注意!!除了最内层循环,都应该使用引用类型
//for(auto row : ia ) // 编译错误:编译器将row转成了int*指针,显然它是无法进行循环的。
for(auto &col : row) { // 最内层循环,col不做要求。
col = cnt ;
++cnt ;
}
2、迭代器遍历(C++)
int ia[rowCnt][colCnt] ; //12个未初始化的元素
for (auto p = begin(ia); p != end(ia); ++p) { // p指向ia的第一个数组
for (auto q = begin(*p) ; q != end(*p); ++q) // q指向内层数组的首元素
cout << *q << ''; // 输出q所指的整数值
3、数组下标遍历(C)
int ia[rowCnt][colCnt] ; //12个未初始化的元素
for (size_t i = 0 ; i != rowCnt ; ++i) // 注意数组下标索引是size_t类型
for (size_t j = O; j != colCnt; ++j)
ia[i][j] = i * colCnt + j;
4、指针遍历(C)
int ia[3][4] ; //12个未初始化的元素
for(auto p = ia; p != ia + 3; ++p) { // p指向含有4个整数的数组,元素是数组。
for (auto q = *p ; q != *p + 4; ++q)// q指向4个整数数组的首元素,也就是说,q指向一个整数
cout << *q << ' ';
cout << endl ;
}
类型别名,简化遍历。
int ia[rowCnt][colCnt] ; //12个未初始化的元素
using int_array = int[4]; // 新标准下类型别名的声明
// typedef int int_array[4); // 等价的 typedef 声明
for (int_array *p = ia ; p != ia + 3; ++p) {
for (int *q = *p; q != *p + 4; ++q)
cout << *q <<' ';