[英]why does derefrencing a pointer to an array of integers(in 2d array) return(or decay to) pointer to first element?
我已经阅读了许多指针和二维数组关系的帖子,但我似乎无法理解概念。 假设有一个2d数组int a[3][2]
和数组int b[2]
。
现在a
返回一个指向大小为3的整数数组的指针。它的类型为int (*)[2]
。
正如我对这个概念的理解所做的那样( *a
)会给我数组本身, 这会衰减到指向1d数组的第一个元素并且类型为(int *)的指针 。 现在大胆的部分是怀疑。
为什么以及如何在数组本身(这是完整的1d数组a [0])衰减到1d数组的第一个元素时发生这种衰变?
(似乎无法得到原因和部分)并且似乎无法在其他链接上找到它。
作为a[0]
, *a
, &a[0][0]
表示相同的指针。 这里作为[0]是第一个1d数组。 那么这是真的, b
(在上面声明)和a[0]
代表相同的东西(都是1d数组然后衰减到指向类型(int *)数组中第一个元素的指针?
为什么以及如何在数组本身衰减到1d数组的第一个元素时发生这种衰变?
除非它是
sizeof
运算符的操作数,_Alignof
运算符1 ,一元&
运算符,或者是用于初始化数组的字符串文字,具有类型''数组类型''的表达式将转换为表达式输入''指向类型'的指针,指向数组对象的初始元素,而不是左值。
简单; 数组名称可以转换为指向其第一个元素的指针。
由于a
是一个数组名称,它衰减到指向其第一个元素的指针,该元素是一维数组。 它的类型是int(*)[2]
。 由于a
(后衰减)是指向的数组2
int
, *a
是阵列2
int
秒。 由于这是一个数组类型,即*a
是第一个1D数组的数组名称 ,它衰减到指向数组对象的第一个元素( a[0][0]
)的指针。 所以,它的类型是int *
。
这是真的,
b
(在上面声明)和a[0]
代表相同的东西(都是1d数组,然后衰减到指向类型(int*
)数组中第一个元素的指针?
是b
和a[0]
都是int *
类型(衰变后)。
1.阅读Keith Thompson的commat。 还要阅读这个答案 ,其中指出: C11标准的草案说数组有另一个例外,即当数组是新_Alignof
运算符的操作数时。 这是草案中的错误,在最终公布的C11标准中得到纠正; _Alignof
只能应用于带括号的类型名称,而不能应用于表达式。
你的“为什么”问题的答案是:因为语言规范是这样说的。 数组总是衰减到指向它们的第一个元素(除了许多特定的上下文)。 所以,正如你正确指出的那样*a
有类型int [2]
。 这是一个数组。 并且因为它是一个数组,所以语言需要衰减到指向(*a)[0]
的类型int *
指针(同样,除少数特定的上下文之外)。 你的原始a
是一个int [3][2]
类型的数组,衰减到int (*)[2]
指针。 同时*a
是一个int [2]
类型的数组,衰减到int *
指针。 这就是为什么。
至于“如何”,目前尚不清楚你究竟在问什么。 在这种情况下,“衰减”意味着在表达式中,数组类型的值被指针类型的值隐式替换。 这里的所有都是它的。
是的,你的例子中a[0]
和b
都是int [2]
类型的数组,它们与int *
类型的指针相同地衰减。 即它们在衰变行为方面是“同样的事情”。
指定此转换的规则隐藏在C11第6.3.2节中:
...具有类型“数组类型”的表达式将转换为类型为“指向类型的指针”的表达式,该表达式指向数组对象的初始元素,而不是左值。
这意味着如果你有一个表达式,其中使用int b[3]
的数组名称b
,它将被转换为指向int的指针,即int*
。
此规则是通用的。 如果你有一个数组int a[3][2]
,那么正式你有一个“大小为3的大小为2的int数组”。 这将转换为指向type的指针,它是“指向int类型为2的数组的指针”, int(*)[2]
。
请注意,“衰减”仅“向下”一个级别,因此通过使用二维数组名称a
,您将始终获得数组指针而不是指向第一个元素的指针。 数组指针和普通int指针之间的区别主要是风格,以保持语言的一致性。 如果将指针的实际地址打印为整数,则无论指针类型如何都是相同的。
所以我对这个概念的理解就是解除它
(*a)
会给我数组本身,并且这会衰减到指向1d数组的第一个元素并且类型为(int*)
的指针
它将为您提供数组本身,它将衰减为数组指针。 它不会再从那里腐烂,只有一个层次。 所以*a
不会给你一个指向第一个元素的指针。
为什么以及如何在数组本身衰减到1d数组的第一个元素时发生这种衰变?
无论何时在表达式中使用数组名称,它都会衰减,从“数组到类型”到“指向类型的指针”。 如果“type”恰好是一个数组,则会得到一个指向数组的指针。
还有一个疑问。 作为
a[0]
,*a
,&a[0][0]
表示相同的指针。 这里作为[0]是第一个1d数组。
a[0]
和*a
是等价的,两者都给出一个数组指针。 &a[0][0]
是指向int的指针。 它们有不同的类型,但在实践中指向相同的记忆。
请尝试以下代码:
int x[3][10];
printf("%d\n", x[0]);
printf("%d\n", x[1]);
printf("%d\n", x[2]);
看下面的表达式
if(&x[0][9] + 1 == &x[1][0])
printf("I've entered here");
这个值为true ...当你向指针添加1时,它的地址增加4(或者你的机器具有的任何int大小),显示在内存中,元素x [1] [0]正好在元素x之后[ 0] [9]
一个整数大小为4,你会看到这些版画之间的差异是40(4 * 10)个元素......
这个数组是在编译时分配的,因此它已经知道它需要多少空间,它为3 * 10个整数分配连续的空间,就像它被声明为
int x[30];
当你单独使用名称x时,你得到的是它指向的第一个元素的地址......
第二个维度只适合我们的程序员...但是编译器的成本很低......当你访问时
x[1][8];
它必须计算添加到起始地址以访问该元素的程度,
这将是(1 * 10 + 8)* SIZE_OF_ARRAY_TYPE(这里是int)...
在上面的表达式中,1 =第一个维度上的数字,乘以10(第二个维度中第一行中的元素数量)加到第二个[]中的元素个数中
如果你有一个1维数组:
x[23]
唯一的帐户是23 * SIZE_OF_ARRAY_TYPE(这里是int)
你也可以在这里尝试这个IF语句:
if(&x[0][10] == &x[1][0])
printf("I've entered here");
甚至是作业等
x[1][4] = 20;
printf("%d\n", x[0][14]);
指针为你提供了很大的力量,但是拥有巨大的力量带来了巨大的责任;)
数组int a[3][2]
以行主要顺序存储在内存中作为1d数组,因此该数组:
int a[3][2] = {
{1, 2},
{3, 4},
{5, 6}
};
将存储为:
int a[] = {1, 2, 3, 4, 5, 6};
例如:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
size_t i;
int a[3][2] = {
{1, 2},
{3, 4},
{5, 6}
};
for(i = 0 ; i < sizeof(a) / sizeof(int) ; i++)
{
printf("%d\n", ((int *) a)[i]);
}
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.