Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么int*[]衰减为int**而不是int[][]?_C++ - Fatal编程技术网

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

C++ 为什么int*[]衰减为int**而不是int[][]?,c++,C++,我试图理解类型衰变的本质。例如,我们都知道数组在特定上下文中会衰减为指针。我试图理解int[]如何等同于int*,但二维数组如何与预期的指针类型不对应。下面是一个测试用例: std::is_same<int*, std::decay<int[]>::type>::value; // true std::值是否相同;//真的 这会按预期返回true,但不会: std::is_same<int**, std::decay<int[][1]>::type&

我试图理解类型衰变的本质。例如,我们都知道数组在特定上下文中会衰减为指针。我试图理解
int[]
如何等同于
int*
,但二维数组如何与预期的指针类型不对应。下面是一个测试用例:

std::is_same<int*, std::decay<int[]>::type>::value; // true
std::值是否相同;//真的
这会按预期返回true,但不会:

std::is_same<int**, std::decay<int[][1]>::type>::value; // false
std::值是否相同;//假的
为什么不是这样?我终于找到了一种方法使其返回真值,那就是将第一个维度设为指针:

std::is_same<int**, std::decay<int*[]>::type>::value; // true
std::值是否相同;//真的
该断言适用于具有指针的任何类型,但最后一个类型是数组。例如(
int***[]==int****;//true

我能解释一下为什么会发生这种情况吗?为什么数组类型不符合预期的指针类型

为什么
int*[]
衰退为
int**
而不是
int[][]

因为用它做指针运算是不可能的

例如,
int p[5][4]
表示一个数组(长度为4的
int
数组)。没有指针,它只是一个大小为
5*4*sizeof(int)
的连续内存块。当您请求特定元素时,例如
inta=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
显然,它只能这样做,因为它知道“内部”维度的大小。对
int(*)[4]
的强制转换保留此信息;它是指向(长度为4的
int
数组)的指针。但是,
int**
不会;它只是一个指向(指向
int
)的指针

有关这方面的其他信息,请参阅C常见问题解答的以下部分:


(这是所有的C,但是这个行为在C++中基本不变)

,因为<代码> int [M] [n] < /Cord>和<代码> int *>代码>是不兼容类型。p> 但是,
int[M][N]
可以退化为
int(*)[N]
类型。因此,以下是:

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

应该为您提供
true

二维数组不是作为指向指针的指针存储的,而是作为连续的内存块存储的

声明为类型为
int[y][x]
的对象是大小为
sizeof(int)*x*y
的块,而类型为
int**
的对象是指向
int*

的指针,而
C并不是真正“设计”为语言的;取而代之的是,在需要时添加了一些特性,以避免破坏早期的代码。在开发C语言的时代,这种进化的方法是一件好事,因为这意味着在开发语言可能需要做的所有事情之前,开发人员可以从语言早期的改进中获益。不幸的是,数组和指针处理的发展方式导致了各种各样的规则,回想起来,这些规则是不幸的

在今天的C语言中,有一个相当重要的类型系统,变量有明确定义的类型,但事情并不总是这样。声明
字符arr[8]
;将在当前范围内分配8个字节,并使
arr
指向其中的第一个字节。编译器不知道
arr
表示一个数组——它将像任何其他
char*
一样表示一个char指针。据我所知,如果一个人声明了
char arr1[8],arr2[8],语句
arr1=arr2
在概念上与char*st1=“foo,*st2=“bar”;st1=st2;
完全合法,但几乎总是代表一个bug


数组分解为指针的规则源于数组和指针实际上是同一事物的时代。从那时起,数组已经被认为是一种独特的类型,但这种语言需要与它们不存在的时代保持本质上的兼容。在制定规则时,二维如何nal数组应该被处理并不是一个问题,因为没有这样的事情。我们可以做一些事情,比如
char foo[20];char*bar[4];int i;for(i=0;我要精确地说,“一个声明为type
int[y][x]
的对象是一个大小为
sizeof(int)*x*y
”的块。另一种方法是:
int[M][N]
int**
需要两次转换(不允许),而不是一次转换(允许)。第一次转换需要从
int[M][N]
转换为指向数组第一个元素的指针。[first]元素的类型是
int[N]
,因此
int[M][N]
首先转换为
int(*)[N]
,然后需要转换为
int**
,要求内部数组的第一个元素
int[N]
转换为
int*
。这很有趣,但是您知道其中任何一个的参考吗?(这是一个真实的问题,我真的很有兴趣了解这段历史。)我没有任何参考资料,不幸的是,尽管在其他SO问题中已经讨论了历史的各个方面。至少有两条SO线索支持这一说法?很好的帖子。非常简单很好的回答Nawaz!