当我将[指向可变大小数组的指针]转换为[指向指针的指针]时会发生什么?
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**
变量时会导致运行时错误?
答案 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
。
答案 1 :(得分:1)
问题是ptr[0]
或*ptr
应该是一个指针,但事实并非如此。也就是说,ptr[0]
或*ptr
不包含有效指针。在这个地址有阵列ar的第一个元素。因此,当使用表达式ptr[0][0]
时,您将收到运行时错误。通常情况下,程序行为未定义。
答案 2 :(得分:0)
声明int **ptr
时,它引用一个int指针数组。但是你声明了一个int数组数组。
这就是为什么语言没有为此提供任何隐式演员,因为这两种类型实际上并不相关。
像你一样操纵演员的结果有未定义的行为。