数组
其他操作
与数组相关的还有一些其他的操作
-
求数组中元素的个数
sizeof
int a [3]; sizeof(a)/sizeof(int); // 使用sizeof数组没有退化成指针,获取到的是数组所占用的内存大小
std::size
int a[3]; std::size(a); // 直接获取数组内元素的个数
(c)end
-(c)begin
int a[3]; std::cend(a) - std::cbegin(a); // 直接获取数组内元素的个数
以上所有的求数组元素个数的操作都只能针对数组操作,不能针对指针或者不完整类型的数组
前两种方法数组尺寸是编译期获取的,而最后一个方法是在运行期获取的,所以不推荐使用最后一种方法。而前两种方法中
sizeof
方法需要针对特定类型做除法,不易于修改,所以三种方法中最推荐使用std::size
-
遍历数组中的元素
- 基于元素个数
int a[4] = {2,3,5,7}; size_t index = 0; while(index < std::size(a)){ std::cout << a[index] << std::endl; index = index + 1; }
- 基于
(c)begin
和(c)end
int a[4] = {2,3,5,7}; auto ptr = std::cbegin(a); while(ptr != std::cend(a)){ std::cout << *ptr << std::endl; ptr = ptr + 1; }
- 基于范围的
for
循环int a[4] = {2,3,5,7}; for(int x:a){ std::cout << x << std::endl; }
- 基于元素个数
C字符串
C风格的字符串本质上也是一个数组,比如
char str[] = "Hello"; // 类型为char[6]
末尾加
\0
主要是为了在运行期使用指针形式对字符串操作时获取字符串的长度
C语言额外提供了一些函数来支持C风格字符串的相关操作
- strlen:求字符串长度
char str[] = "Hello"; strlen(str); // 定义在cstring头文件中
- strcmp:判断字符串是否相等
- 其他操作
以上所有的操作都需要末尾的
\0
的支持,所以在声明C风格字符串的时候建议使用字符串来初始化而不是使用字符列表
多维数组
多维数组的本质是数组的数组,比如
int a[3][4]; // 数组中包含3个元素,每个元素的类型是一个int[4]的数组
多维数组的初始化方式有以下几种
- 缺省初始化
- 单层大括号初始化
int x[3][4] = {1,2,3,4,5}; // 按照行主序,按顺序填充,省下的为0
- 多层大括号初始化
int x[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; // 对每一行单独进行一个大括号初始化,方式与单维数组相同
- 自动推导初始化
int x[][3] = {1,2,3,4}; //类型为int[2][3]
注意必须给定后面维的大小,只能省略第一维的大小
我们可以对多维数组进行索引和遍历
- 使用多个中括号进行索引
- 使用多重循环来遍历
int x[3][4] = {1,2,3,4,5}; for(auto &p:x){ for(auto q:p){ std::cout << q << std::endl; } }
第一个循环必须带
&
符号,因为如果不带的话p的类型就不是int[4]
而是int*
了,我们就没有办法对他使用基于范围的for
循环了
数组可以隐式转换为指针,多维数组同样可以隐式转换为指针,但是只有最高维会进行转换,其他维度的信息会被保留,比如
int x[3][4];
auto ptr = x; // 类型为int (*) [4]
我们可以使用类型别名来简化多维数组指针的声明,比如
using A = int[4];
int x[3][4];
A * ptr = x;
A x1[3]; // 类型为int[3][4]而不是int[4][3]
同样,指针也可以被用来遍历多维数组,比如
int x[3][4];
auto ptr = std::begin(x);
while(ptr != std::end(x)){
auto ptr2 = std::begin(*ptr);
while(ptr2 != std::end(*ptr)){
std::cout << *ptr2 << std::endl;
ptr2 = ptr2 + 1;
}
ptr = ptr + 1;
}