简体   繁体   English

为什么 int*[] 衰减为 int** 而不是 int[][]?

[英]Why does int*[] decay into int** but not int[][]?

I'm trying to understand the nature of type-decay.我试图了解类型衰减的本质。 For example, we all know arrays decay into pointers in a certain context.例如,我们都知道数组在特定上下文中会衰减为指针。 My attempt is to understand how int[] equates to int* but how two-dimensional arrays don't correspond to the expected pointer type.我试图了解int[]如何等同于int*但二维数组如何与预期的指针类型不对应。 Here is a test case:这是一个测试用例:

std::is_same<int*, std::decay<int[]>::type>::value; // true

This returns true as expected, but this doesn't:这按预期返回 true,但这不会:

std::is_same<int**, std::decay<int[][1]>::type>::value; // false

Why is this not true?为什么这不是真的? I finally found a way to make it return true, and that was by making the first dimension a pointer:我终于找到了一种让它返回 true 的方法,那就是将第一个维度设为指针:

std::is_same<int**, std::decay<int*[]>::type>::value; // true

And the assertion holds true for any type with pointers but with the last being the array.该断言适用于任何带有指针但最后一个是数组的类型。 For example ( int***[] == int****; // true ).例如( int***[] == int****; // true )。

Can I have an explanation as to why this is happening?我能解释一下为什么会这样吗? Why doesn't the array types correspond to the pointer types as would be expected?为什么数组类型不像预期的那样对应于指针类型?

Why does int*[] decay into int** but not int[][] ?为什么int*[]衰减为int**而不是int[][]

Because it would be impossible to do pointer arithmetic with it.因为用它做指针运算是不可能的。

For example, int p[5][4] means an array of (length-4 array of int ).例如, int p[5][4]表示一个数组(长度为 4 的int数组)。 There are no pointers involved, it's simply a contiguous block of memory of size 5*4*sizeof(int) .不涉及指针,它只是一个大小为5*4*sizeof(int)的连续内存块。 When you ask for a particular element, eg int a = p[i][j] , the compiler is really doing this:当您请求特定元素时,例如int a = p[i][j] ,编译器实际上是这样做的:

char *tmp = (char *)p           // Work in units of bytes (char)
          + i * sizeof(int[4])  // Offset for outer dimension (int[4] is a type)
          + j * sizeof(int);    // Offset for inner dimension
int a = *(int *)tmp;            // Back to the contained type, and dereference

Obviously, it can only do this because it knows the size of the "inner" dimension(s).显然,它只能这样做,因为它知道“内部”维度的大小。 Casting to an int (*)[4] retains this information;转换为int (*)[4]保留此信息; it's a pointer to (length-4 array of int ).它是一个指向(长度为 4 的int数组)的指针。 However, an int ** doesn't ;但是, int **不会 it's merely a pointer to (pointer to int ).它只是一个指向(指向int指针)。

For another take on this, see the following sections of the C FAQ:有关此问题的另一种看法,请参阅 C 常见问题解答的以下部分:

(This is all for C, but this behaviour is essentially unchanged in C++.) (这都是针对 C 的,但这种行为在 C++ 中基本上没有变化。)

C was not really "designed" as a language; C 并不是真正“设计”为一种语言; instead, features were added as needs arose, with an effort not to break earlier code.取而代之的是,根据需要添加功能,努力不破坏早期的代码。 Such an evolutionary approach was a good thing in the days when C was being developed, since it meant that for the most part developers could reap the benefits of the earlier improvements in the language before everything the language might need to do was worked out.在 C 被开发的时代,这种进化方法是一件好事,因为这意味着在大多数情况下,开发人员可以在语言可能需要做的所有事情都得到解决之前,从早期的语言改进中获益。 Unfortunately, the way in which array- and pointer handling have evolved has led to a variety of rules which are, in retrospect, unfortunate.不幸的是,数组和指针处理的演变方式导致了多种规则,回想起来,这些规则令人遗憾。

In the C language of today, there is a fairly substantial type system, and variables have clearly defined types, but things were not always thus.在今天的C语言中,有一个相当充实的类型系统,变量也有明确的类型定义,但事情并非总是如此。 A declaration char arr[8] ;声明char arr[8] ; would allocate 8 bytes in the present scope, and make arr point to the first of them.将在当前范围内分配 8 个字节,并使arr指向其中的第一个。 The compiler wouldn't know that arr represented an array--it would represent a char pointer just like any other char* .编译器不会知道arr表示一个数组——它会像任何其他char*一样表示一个 char 指针。 From what I understand, if one had declared char arr1[8], arr2[8];据我了解,如果已经声明char arr1[8], arr2[8]; , the statement arr1 = arr2; , 语句arr1 = arr2; would have been perfectly legal, being somewhat equivalent conceptually to char *st1 = "foo, *st2 = "bar"; st1 = st2; , but would have almost always represented a bug.本来是完全合法的,在概念上有点等同于char *st1 = "foo, *st2 = "bar"; st1 = st2; ,但几乎总是代表一个错误。

The rule that arrays decompose into pointers stemmed from a time when arrays and pointers really were the same thing.数组分解为指针的规则起源于数组和指针实际上是一回事的时代。 Since then, arrays have come to be recognized as a distinct type, but the language needed to remain essentially compatible with the days when they weren't.从那时起,数组开始被认为是一种独特的类型,但该语言需要与它们不兼容的时代保持基本兼容。 When the rules were being formulated, the question of how two-dimensional arrays should be handled wasn't an issue because there was no such thing.在制定规则时,二维数组应该如何处理的问题不是问题,因为没有这样的事情。 One could do something like char foo[20]; char *bar[4]; int i; for (i=0; i<4; i++) bar[i] = foo + (i*5);可以做一些类似char foo[20]; char *bar[4]; int i; for (i=0; i<4; i++) bar[i] = foo + (i*5);事情char foo[20]; char *bar[4]; int i; for (i=0; i<4; i++) bar[i] = foo + (i*5); char foo[20]; char *bar[4]; int i; for (i=0; i<4; i++) bar[i] = foo + (i*5); and then use bar[x][y] in the same way as one would now use a two-dimensional array, but a compiler wouldn't view things that way--it just saw bar as a pointer to a pointer.然后以与现在使用二维数组相同的方式使用bar[x][y] ,但编译器不会以这种方式查看事物——它只是将bar视为指向指针的指针。 If one wanted to make foo[1] point somewhere completely different from foo[2], one could perfectly legally do so.如果你想让 foo[1] 指向与 foo[2] 完全不同的某个地方,你完全可以合法地这样做。

When two two-dimensional arrays were added to C, it was not necessary to maintain compatibility with earlier code that declared two-dimensional arrays, because there wasn't any.当两个二维数组被添加到 C 中时,没有必要保持与声明二维数组的早期代码的兼容性,因为没有任何代码。 While it would have been possible to specify that char bar[4][5];虽然可以指定char bar[4][5]; would generate code equivalent to what was shown using the foo[20] , in which case a char[][] would have been usable as a char** , it was thought that just as assigning array variables would have been a mistake 99% of the time, so too would have been re-assignment of array rows, had that been legal.将生成与使用foo[20]显示的代码等效的代码,在这种情况下, char[][]将可用作char** ,人们认为就像分配数组变量一样会出错 99%当时,如果这是合法的,那么也会重新分配数组行。 Thus, arrays in C are recognized as distinct types, with their own rules which are a bit odd, but which are what they are.因此,C 中的数组被认为是不同的类型,它们有自己的规则,这有点奇怪,但它们就是这样。

Because int[M][N] and int** are incompatible types.因为int[M][N]int**是不兼容的类型。

However, int[M][N] can decay into int (*)[N] type.但是, int[M][N]可以衰减为int (*)[N]类型。 So the following :所以以下:

std::is_same<int(*)[1], std::decay<int[1][1]>::type>::value;

should give you true .应该给你true

Two dimensional arrays are not stored as pointer to pointers, but as a contiguous block of memory.二维数组不是存储为指向指针的指针,而是存储为连续的内存块。

An object declared as type int[y][x] is a block of size sizeof(int) * x * y whereas, an object of type int ** is a pointer to an int*声明为int[y][x]类型的对象是大小为sizeof(int) * x * y的块,而int **类型的对象是指向int*的指针

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

相关问题 为什么while(int)在int = 0时结束? - Why does while(int) end when int = 0? 为什么 std::is_invocable <std::decay_t<void(int&)> , 标准::decay_t<int> &gt;::值是假的? </int></std::decay_t<void(int&)> - Why std::is_invocable<std::decay_t<void(int&)>, std::decay_t<int>>::value is false? 为什么“ unsigned int” +“ unsigned int”返回“ unsigned int”? - Why does “unsigned int” + “unsigned int” return an “unsigned int”? 重载分辨率和数组到指针衰减 - 为什么 int (&amp;a)[2] 和 int* a 被认为在重载分辨率方面同样准确 - Overload resolution and array-to-pointer decay - why is int (&a)[2] and int* a considered equally exact regarding overload resolution 从“ int []的数组”到“ int的指针”的显式衰减令人困惑吗? - Confusing explicit decay from “array of int[]” to “pointer to int”? 为什么int main(){}编译? - Why does int main() {} compile? 为什么要编译:string = int - Why does this compile: string = int 如果int不是类,为什么int x = int(5)合法? - Why is int x = int(5) legal if int is not a class? int(abc)(int,int)是什么意思? - What does int (abc)(int,int) mean? 为什么int和float的总和是int? - Why is the sum of an int and a float an int?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM