简体   繁体   English

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

[英]Casting a (pointer to a variable sized array) to (pointer to pointer)

What exactly happens when I cast a [pointer to a variable sized array] to a [pointer to pointer] ? 当我将[指向可变大小数组的指针]转换为[指针指针]时会发生什么?

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

The above code gives a runtime error. 上面的代码给出了运行时错误。

Casting a variable sized array to a pointer works as expected: 将可变大小的数组转换为指针按预期方式工作:

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

Here ar decays into a pointer to the first element. 这里ar衰减成指向第一个元素的指针。

But what happens internally when casting an int(*)[c] to int** ? 但是在将int(*)[c]int**时内部会发生什么? Why does it result in a runtime error when reading/writing to the int** variable? 为什么在读取/写入int**变量时会导致运行时错误?

An array is not a pointer. 数组不是指针。

An array is a block of contiguous memory of data all of the same type, all packed together. 数组是所有相同类型的数据的连续内存块,全部打包在一起。 As it happens, if you have a pointer to the first element, and you know the type of the data, you can do many of the same things with your pointer that you could do with your array. 碰巧的是,如果你有一个指向第一个元素的指针,并且你知道数据的类型,那么你可以使用你的指针对数组执行许多相同的操作。

foo[5] on an array gets the 5th element, and on a pointer to the first element also gets the 5th element. 数组上的foo[5]获取第5个元素,而指向第一个元素的指针也获得第5个元素。

In fact, you can convert an array to a type foo to a pointer to the first element implicitly. 实际上,您可以将数组转换为类型foo ,隐式转换为指向第一个元素的指针。

Now, what you are doing is something completely different. 现在,你正在做的事情是完全不同的。 The pointer to the first element is a pointer to int[5] -- an entire array. 指向第一个元素的指针是指向int[5]的指针 - 整个数组。

Suppose you had an array of pointers to int* of length 5. Each one of them could point to a different int[5] , and you could use the int*[6] as a two-dimensional array. 假设你有一个指向int*的长度为5的指针。它们中的每一个都可以指向不同的int[5] ,你可以使用int*[6]作为二维数组。 But you'll note here we have an array of pointers to int* , not an array of int[5] . 但是你会注意到我们有一个指向int*的数组,而不是int[5]的数组。 And as arrays are not pointers, these are different things. 由于数组不是指针,因此这些是不同的东西。

Now, we can fix this. 现在,我们可以解决这个问题。

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 );
}

The above is a fancy C++11 way to write: 以上是一种花哨的C ++ 11写法:

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

Now you can take your ar and turn it into an array-of-pointers. 现在你可以把你的ar变成一个指针数组。 If you have a function taking int** you can call as_array_of_pointers and take an explicit pointer to the first element, and rely on temporary lifetime to do the work: 如果你有一个函数接受int**你可以调用as_array_of_pointers并获取一个指向第一个元素的显式指针,并依赖临时生命周期来完成工作:

void foo( int** x ) {}

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

this requires C++11. 这需要C ++ 11。 You can instead do it manually in C++03. 您可以在C ++ 03中手动执行此操作。

The crash you are seeing (via undefined behavior) is probably the result of reinterpreting the first element of your array as a pointer-to- int , instead of one or more int (depending on the relative size of pointers and int on your system). 您看到的崩溃(通过未定义的行为)可能是将数组的第一个元素重新解释为指向int的指针而不是一个或多个int (取决于系统上指针和int的相对大小)的结果。

live example 实例

The problem is that ptr[0] or *ptr is supposed to be a pointer, but it is not. 问题是ptr[0]*ptr应该是一个指针,但事实并非如此。 That is, ptr[0] or *ptr does not contain a valid pointer. 也就是说, ptr[0]*ptr不包含有效指针。 At this address there is the first element of array ar. 在这个地址有阵列ar的第一个元素。 So you will get a run-time error when will use expression ptr[0][0] That is in general case the program behaviour is undefined. 因此,当使用表达式ptr[0][0]时,您将得到运行时错误。在一般情况下,程序行为是未定义的。

When you declare int **ptr , it refers to an array of int pointers. 声明int **ptr ,它引用一个int指针数组。 But you declared an array of arrays of int. 但是你声明了一个int数组数组。

This is why the language does not provide any implicit cast for this, since the two types really don't relate. 这就是为什么语言不为此提供任何隐式转换,因为这两种类型实际上没有关联。

Manipulating the result of the cast as you did has undefined behavior. 像你一样操纵强制转换的结果有未定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM