数组(三)

90 阅读1分钟

数组到指针的隐式转换

  • 使用数组对象时,通常情况下会产生数组到指针的隐式转换
#include <iostream>
#include <type_traits>

int main()
{
    int a[3] = {1, 2, 3};
    std::cout << a[0] << std::endl;
    
    auto b = a;  // decay 退化
}

像 decltype(a), sizeof(a) 等情况下,不会发生退化。

  • 隐式转换会丢失一部分类型信息

int[3] 类型会包含 3 这个信息,但是 a[4] 会隐式转换为 *(a + 4),造成 3 这个信息丢失。

int main()
{
    int a[3] = {1, 2, 3};  // int[3]
    std::cout << a[4] << std::endl;
    
    auto b = a;  // int*
}
  • 可以通过声明引用来避免隐式转换
auto& b = a;  // int(&)[3]
  • 注意:不要使用 extern 指针来声明数组

合法情况:

source.cpp

int array[4] = {1, 2, 3, 4};

main.cpp

#include <iostream>

extern int array[4];
int main()
{
    std::cout << array[1] << std::endl;
}

不合法情况:

source.cpp

#include <iostream>

extern int* array;
int main()
{
    std::cout << array[1] << std::endl;
}

运行期错误。

原因:编译期是针对翻译单元来说,因此对于单个文件来说,都是没有问题的。同时,也不是链接错误,因为链接期已经不包含类型信息,只包含符号相关。

运行期 source.cpp 会将 array 的内容当做 地址,即 0x01 00 00 00 02 00 00 00

第二种正确做法:

source.cpp

extern int array[];  // Unknown Bounded Array
  • 获得指向数组开头与结尾的指针: std::(c)begin, std::(c)end

  • 指针算数:

增加、减少

比较

求距离

解引用

指针索引

int a[3] = {1, 2, 3};
std::cout << a << ' ' << &(a[0]) << ' ' << std::begin(a) << std::endl;
std::cout << a + 3 << ' ' << &(a[3]) << ' ' << std::end(a) << std::endl;

std::cbegin(a) // const int*