将(指向可变大小数组的指针)强制转换为(指针指向指针)

Casting a (pointer to a variable sized array) to (pointer to pointer)

本文关键字:指针 转换 小数 数组      更新时间:2023-10-16

当我将[指向可变大小数组的指针]转换为[指针指向指针]时,究竟会发生什么?

int ar[r][c];
int **ptr = (int**)ar;  // implicit casting not allowed
ptr[0][0] = 100;

以上代码给出一个运行时错误。

将可变大小的数组转换为指针的工作方式与预期一致:

int ar[c];
int *ptr = ar;
ptr[0] = 100;

这里ar衰变为指向第一个元素的指针。

但是当将int(*)[c]转换为int**时内部会发生什么?为什么在读/写int**变量时导致运行时错误?

数组不是指针。

数组是同一类型数据的连续内存块,所有数据都打包在一起。事实上,如果你有一个指向第一个元素的指针,并且你知道数据的类型,那么你可以用指针做很多可以用数组做的事情。

foo[5]在数组上得到第5个元素,在指向第一个元素的指针上也得到第5个元素。

实际上,可以将数组转换为foo类型,隐式地转换为指向第一个元素的指针。

现在,你正在做的是完全不同的事情。指向第一个元素的指针是指向int[5](整个数组)的指针。

假设有一个指向int*的指针数组,长度为5。它们中的每一个都可以指向不同的int[5],并且可以将int*[6]用作二维数组。但是你会注意到这里我们有一个指向int*的指针数组,而不是指向int[5]的指针数组。因为数组不是指针,所以它们是不同的东西。

现在,我们可以解决这个问题了

template<unsigned...>struct indexes{typedef indexes type;};
template<unsigned Max, unsigned...Is> struct make_indexes:make_indexes<Max-1, Max-1, Is...>{};
template<unsigned...Is> struct make_indexes<0, Is...>:indexes<Is...>{};
template<unsigned Max> using make_indexes_t = typename make_indexes<Max>::type;
template<typename T, unsigned N, unsigned M, unsigned... Is>
std::array<T*, M> as_array_of_pointers( indexes<Is...>, T(&arr)[M][N] ) {
  return { arr[Is]... };
};
template<typename T, unsigned N, unsigned M>
std::array<T*, M> as_array_of_pointers( T(&arr)[M][N] ) {
  return as_array_of_pointers( make_indexes_t<M>{}, arr );
}

以上是c++ 11的一种奇特的编写方式:

std::array<int*, 5> arr = { ar[0], ar[1], ar[2] };

现在您可以将ar转换为指针数组。如果你有一个接受int**的函数,你可以调用as_array_of_pointers并接受指向第一个元素的显式指针,并依靠临时生存期来完成工作:

void foo( int** x ) {}
int main() {
  int a[5][3] = {0};
  foo( &(as_array_of_pointers(a)[0]) );
}

需要c++ 11。您可以在c++ 03中手动执行。

您看到的崩溃(通过未定义的行为)可能是将数组的第一个元素重新解释为指向int的指针,而不是一个或多个int(取决于指针和int在您的系统上的相对大小)的结果。

生活例子

问题是ptr[0]*ptr应该是一个指针,但它不是。也就是说,ptr[0]*ptr不包含有效指针。在这个地址有数组ar的第一个元素。所以当你使用表达式ptr[0][0]时,你会得到一个运行时错误,这是在一般情况下,程序的行为是未定义的。

声明int **ptr时,它指向一个int指针数组。但是你声明了一个int型数组的数组。

这就是为什么语言没有为This提供任何隐式强制转换的原因,因为这两种类型实际上并不相关。

像您那样操作强制转换的结果是未定义的行为。