简体   繁体   English

为什么解除指向一个整数数组(在2d数组中)的指针返回(或衰减到)指向第一个元素的指针?

[英]why does derefrencing a pointer to an array of integers(in 2d array) return(or decay to) pointer to first element?

I have read many posts of pointers and 2d array relation, but I cant seem to understand concept. 我已经阅读了许多指针和二维数组关系的帖子,但我似乎无法理解概念。 Lets say there is a 2d array int a[3][2] and an array int b[2] . 假设有一个2d数组int a[3][2]和数组int b[2]
now a is returning a pointer to array of integers of size 3. It would be of type int (*)[2] . 现在a返回一个指向大小为3的整数数组的指针。它的类型为int (*)[2]

As my understanding of the concept goes derefrencing it( *a ) would give me the array itself and this decays to a pointer pointing to first element of the 1d array and is of type (int*) . 正如我对这个概念的理解所做的那样( *a )会给我数组本身, 这会衰减到指向1d数组的第一个元素并且类型为(int *)的指针 now the bold part is the doubt. 现在大胆的部分是怀疑。

why and how does this decay happen where the array itself(which is the complete 1d array a[0]) decays to first element of the 1d array? 为什么以及如何在数组本身(这是完整的1d数组a [0])衰减到1d数组的第一个元素时发生这种衰变?
(cant seem to get the why and how part) and cant seem to find it on other links also. (似乎无法得到原因和部分)并且似乎无法在其他链接上找到它。

As a[0] , *a , &a[0][0] represent the same pointer. 作为a[0]*a&a[0][0]表示相同的指针。 here as a[0] is the first 1d array. 这里作为[0]是第一个1d数组。 then is this true that b (declared above) and a[0] represent the same thing (both being 1d array and then decay to the pointer to first element in array of type (int*)? 那么这是真的, b (在上面声明)和a[0]代表相同的东西(都是1d数组然后衰减到指向类型(int *)数组中第一个元素的指针?

why and how does this decay happen where the array itself decays to first element of the 1d array? 为什么以及如何在数组本身衰减到1d数组的第一个元素时发生这种衰变?

C11: 6.3.2.1 p(3): C11:6.3.2.1 p(3):

Except when it is the operand of the sizeof operator, the _Alignof operator 1 ,the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue. 除非它是sizeof运算符的操作数, _Alignof运算符1 ,一元&运算符,或者是用于初始化数组的字符串文字,具有类型''数组类型''的表达式将转换为表达式输入''指向类型'的指针,指向数组对象的初始元素,而不是左值。

In simple; 简单; the array names can be converted to pointer to its first element. 数组名称可以转换为指向其第一个元素的指针。

Since a is an array name, it decays to the pointer to its first element which is a 1D array. 由于a是一个数组名称,它衰减到指向其第一个元素的指针,该元素是一维数组。 Its type is int(*)[2] . 它的类型是int(*)[2] Since a (after decay) is a pointer to an array of 2 int , *a is an array of 2 int s. 由于a (后衰减)是指向的数组2 int*a是阵列2 int秒。 Since that's an array type, ie *a is an array name for the first 1D array, it decays to a pointer to the first element ( a[0][0] ) of the array object. 由于这是一个数组类型,即*a是第一个1D数组的数组名称 ,它衰减到指向数组对象的第一个元素( a[0][0] )的指针。 So, its type is int * . 所以,它的类型是int *

is this true that b (declared above) and a[0] represent the same thing (both being 1d array and then decay to the pointer to first element in array of type ( int* )? 这是真的, b (在上面声明)和a[0]代表相同的东西(都是1d数组,然后衰减到指向类型( int* )数组中第一个元素的指针?

Yes b and a[0] are both of type int * (after decay). ba[0]都是int *类型(衰变后)。


1. Read the commat by Keith Thompson . 1.阅读Keith Thompson的commat。 Also read this answer which states that: A draft of the C11 standard says that there's another exception for arrays, namely when the array is the operand of the new _Alignof operator. 还要阅读这个答案 ,其中指出: C11标准的草案说数组有另一个例外,即当数组是新_Alignof运算符的操作数时。 This is an error in the draft, corrected in the final published C11 standard; 这是草案中的错误,在最终公布的C11标准中得到纠正; _Alignof can only be applied to a parenthesized type name, not to an expression. _Alignof只能应用于带括号的类型名称,而不能应用于表达式。

The answer to your "why " question is: because the language specification says so. 你的“为什么”问题的答案是:因为语言规范是这样说的。 Arrays always decay to pointers to their first elements (aside from a number of specific contexts). 数组总是衰减到指向它们的第一个元素(除了许多特定的上下文)。 So, as you correctly noted *a has type int [2] . 所以,正如你正确指出的那样*a有类型int [2] This is an array. 这是一个数组。 And since it is an array, it is required by the language to decay to pointer of type int * that points to (*a)[0] (again, with the exception of a few specific contexts). 并且因为它是一个数组,所以语言需要衰减到指向(*a)[0]的类型int *指针(同样,除少数特定的上下文之外)。 Your original a is an array of type int [3][2] that decays to int (*)[2] pointer. 你的原始a是一个int [3][2]类型的数组,衰减到int (*)[2]指针。 Meanwhile *a is an array of type int [2] that decays to int * pointer. 同时*a是一个int [2]类型的数组,衰减到int *指针。 That's why. 这就是为什么。

As for "how", it is not clear what exactly you are asking about. 至于“如何”,目前尚不清楚你究竟在问什么。 "Decay" in this case means that in expressions values of array type are implicitly replaced by values of pointer type. 在这种情况下,“衰减”意味着在表达式中,数组类型的值被指针类型的值隐式替换。 That's all there is to it. 这里的所有都是它的。

And yes, both a[0] and b in your example are arrays of type int [2] , which decay identically to pointers of type int * . 是的,你的例子中a[0]b都是int [2]类型的数组,它们与int *类型的指针相同地衰减。 Ie they are "the same thing" with regard to decaying behavior. 即它们在衰变行为方面是“同样的事情”。

The rule specifying this conversion is hidden in the C11 chapter 6.3.2: 指定此转换的规则隐藏在C11第6.3.2节中:

...an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. ...具有类型“数组类型”的表达式将转换为类型为“指向类型的指针”的表达式,该表达式指向数组对象的初始元素,而不是左值。

Meaning if you have an expression where the array name b of int b[3] is used, it will get converted to a pointer to int, an int* . 这意味着如果你有一个表达式,其中使用int b[3]的数组名称b ,它将被转换为指向int的指针,即int*

This rule is generic. 此规则是通用的。 If you have an array int a[3][2] , then formally you have a "size 3 array of size 2 arrays of type int". 如果你有一个数组int a[3][2] ,那么正式你有一个“大小为3的大小为2的int数组”。 This will get converted to aa pointer to type, which is a "pointer to array of size 2 of type int", int(*)[2] . 这将转换为指向type的指针,它是“指向int类型为2的数组的指针”, int(*)[2]

Note that the "decay" only goes "down" one level, so by using the two-dimensional array name a , you will always get an array pointer and not a pointer to the first element. 请注意,“衰减”仅“向下”一个级别,因此通过使用二维数组名称a ,您将始终获得数组指针而不是指向第一个元素的指针。 The difference between an array pointer and a plain int pointer is mainly stylistic, to keep the language consistent. 数组指针和普通int指针之间的区别主要是风格,以保持语言的一致性。 If you print the actual address of the pointer as an integer, it will be the same no matter pointer type. 如果将指针的实际地址打印为整数,则无论指针类型如何都是相同的。

so as my understanding of the concept goes derefrencing it (*a) would give me the array itself and this decays to a pointer pointing to first element of the 1d array and is of type (int*) 所以我对这个概念的理解就是解除它(*a)会给我数组本身,并且这会衰减到指向1d数组的第一个元素并且类型为(int*)的指针

It will give you the array itself, which will decay into an array pointer. 它将为您提供数组本身,它将衰减为数组指针。 It will not decay any further from there, just one level. 它不会再从那里腐烂,只有一个层次。 So *a will not give you a pointer to the first element. 所以*a不会给你一个指向第一个元素的指针。

why and how does this decay happen where the array itself decays to first element of the 1d array? 为什么以及如何在数组本身衰减到1d数组的第一个元素时发生这种衰变?

Whenever you use the array name inside an expression it will decay, from "array to type" to "pointer to type". 无论何时在表达式中使用数组名称,它都会衰减,从“数组到类型”到“指向类型的指针”。 If "type" happens to be an array, you get a pointer to an array. 如果“type”恰好是一个数组,则会得到一个指向数组的指针。

and one more doubt i had. 还有一个疑问。 As a[0] , *a , &a[0][0] represent the same pointer. 作为a[0]*a&a[0][0]表示相同的指针。 here as a[0] is the first 1d array. 这里作为[0]是第一个1d数组。

a[0] and *a are equivalent, both gives an array pointer. a[0]*a是等价的,两者都给出一个数组指针。 &a[0][0] is a pointer to int. &a[0][0]是指向int的指针。 They have different types but in practice points at the same memory. 它们有不同的类型,但在实践中指向相同的记忆。

Try the following code: 请尝试以下代码:

int x[3][10];
printf("%d\n", x[0]);
printf("%d\n", x[1]);
printf("%d\n", x[2]);

Look at the following expression 看下面的表达式

if(&x[0][9] + 1 == &x[1][0])
    printf("I've entered here");

This evaluates to true... When you add 1 to the pointer it is increasing its address by 4 (or whatever int size your machine has), showing that in memory, element x[1][0] comes right after element x[0][9] 这个值为true ...当你向指针添加1时,它的地址增加4(或者你的机器具有的任何int大小),显示在内存中,元素x [1] [0]正好在元素x之后[ 0] [9]

an integer has size 4, you will see that the difference between the prints is 40 (4 * 10) elements... 一个整数大小为4,你会看到这些版画之间的差异是40(4 * 10)个元素......

This array was allocated at compilation time so it already knows how much space it needs and it allocates space for 3*10 integers contiguous, the same way as it would be if it was declared as 这个数组是在编译时分配的,因此它已经知道它需要多少空间,它为3 * 10个整数分配连续的空间,就像它被声明为

 int x[30];

when you use the name x alone what you get is the address of the first element it points to... 当你单独使用名称x时,你得到的是它指向的第一个元素的地址......

The second dimension is just for us programmers... But it comes at a small cost for the compiler... when you access like 第二个维度只适合我们的程序员...但是编译器的成本很低......当你访问时

 x[1][8];

it has to calculate how much it has to add to the start address to access that element, 它必须计算添加到起始地址以访问该元素的程度,

which would be (1 * 10 + 8) * SIZE_OF_ARRAY_TYPE (which is int here) ... 这将是(1 * 10 + 8)* SIZE_OF_ARRAY_TYPE(这里是int)...

In the above expression 1 = the number on the first dimension, multiplied by 10 (number of elements in the second dimension that would be on first row) added to the number of elements in the second [] 在上面的表达式中,1 =第一个维度上的数字,乘以10(第二个维度中第一行中的元素数量)加到第二个[]中的元素个数中

and if you had a 1 dimension array: 如果你有一个1维数组:

 x[23]

the only account is 23 * SIZE_OF_ARRAY_TYPE (which is int here) 唯一的帐户是23 * SIZE_OF_ARRAY_TYPE(这里是int)

you can also try this IF statement here: 你也可以在这里尝试这个IF语句:

 if(&x[0][10] == &x[1][0])
    printf("I've entered here");

or even assignments such as 甚至是作业等

x[1][4] = 20;

printf("%d\n", x[0][14]);

Pointers give you a lot of power, but with a great power comes a great responsibility ;) 指针为你提供了很大的力量,但是拥有巨大的力量带来了巨大的责任;)

The array int a[3][2] is stored in memory as 1d array in row major order , so this array: 数组int a[3][2]行主要顺序存储在内存中作为1d数组,因此该数组:

int a[3][2] = {
  {1, 2},
  {3, 4},
  {5, 6}
};

will be stored as: 将存储为:

int a[] = {1, 2, 3, 4, 5, 6};

for instance: 例如:

#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.

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