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

时间:2014-06-02 15:07:39

标签: c++ pointers semantics

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

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**变量时会导致运行时错误?

3 个答案:

答案 0 :(得分:2)

数组不是指针。

数组是所有相同类型的数据的连续内存块,全部打包在一起。碰巧的是,如果你有一个指向第一个元素的指针,并且你知道数据的类型,你可以使用你的指针对你的数组执行许多相同的操作。

数组上的

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

live example

答案 1 :(得分:1)

问题是ptr[0]*ptr应该是一个指针,但事实并非如此。也就是说,ptr[0]*ptr不包含有效指针。在这个地址有阵列ar的第一个元素。因此,当使用表达式ptr[0][0]时,您将收到运行时错误。通常情况下,程序行为未定义。

答案 2 :(得分:0)

声明int **ptr时,它引用一个int指针数组。但是你声明了一个int数组数组。

这就是为什么语言没有为此提供任何隐式演员,因为这两种类型实际上并不相关。

像你一样操纵演员的结果有未定义的行为。