简体   繁体   English

在C中,为什么(int *)&x [k]和2-D数组x的(int *)x [k]一样工作?

[英]In C, why does (int*)&x[k] work as well as (int*)x[k] for a 2-D array x?

In the following code 在以下代码中

 int x[2][3] = {{1,2,3},{4,5,6}};
 int* y1 = (int*)x[1];
 int* y2 = (int*)&x[1];

 int i;
 for(i=0; i < 3 ; i++)
 {
  printf("%i %i\n",y1[i],y2[i]);
}

why do y1 and y2 point to the same data? 为什么y1和y2指向相同的数据?

I would think that x[1] is a pointer to the second row of data, so y1 should be the correct way to access it. 我认为x [1]是指向第二行数据的指针,因此y1应该是访问它的正确方法。 The expression &x[1] is getting the address of the pointer to the second row of data, so why does y2 even work? 表达式&x [1]得到指向第二行数据的指针的地址,为什么y2甚至可以工作呢?

Given the declaration 鉴于声明

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

the type of the expression x[1] is "3-element array of int ". 表达式x[1]的类型是“ int 3元素数组”。 Unless an array expression is an operand of the sizeof or & address-of operator, or is a string literal being used to initialize another array in a declaration, the type of the expression is converted to "pointer to T" and the value of the expression is the address of the first element of the array. 除非数组表达式是sizeof& address-of运算符的操作数,或者是用于初始化声明中的另一个数组的字符串文字,否则表达式的类型将转换为“指向T的指针”以及expression是数组的第一个元素的地址。

Therefore, in the declaration 因此,在声明中

int *y1 = (int *) x[1];

the cast is unnecessary; 演员是不必要的; x[1] will automatically be converted to type int * , and y1 will point to x[1][0] . x[1]将自动转换为int *类型, y1将指向x[1][0]

In the declaration 在宣言中

int *y2 = (int *) &x[1];

the array expression x[1] is an operand of the address-of & operator, so it isn't automatically converted to type int * . 数组表达式x[1]是取址的操作数&操作者,所以它不会自动转换为类型int * The type of the expression &x[1] is "pointer to 3-element array of int ", or int (*)[3] . 表达式&x[1]是“指向int 3元素数组的指针”或int (*)[3] The cast is necessary in this case, since you can't implicitly convert a pointer to an array of T to pointer to T. However, it's probably not what you want to do; 在这种情况下,强制转换是必要的,因为你不能隐式地将指向T数组的指针转换为指向T的指针。但是,它可能不是你想要做的; converting a pointer to an array to a pointer to a scalar will probably lead to confusion on somebody's part. 将指向数组的指针转换为指向标量的指针可能会导致某人混淆。

Note that x[1] and &x[1] yield the same value (the address of the first element in the array is the same as the address of the array itself), but the types are different, which will matter for things like the ++ and -- operators. 请注意, x[1]&x[1]产生相同的 (数组中第一个元素的地址与数组本身的地址相同),但类型不同,这对于像++--运算符。

If you want to avoid the casts, rewrite those declaration as 如果你想避免强制转换,请将这些声明重写为

int *y1      =  x[1];
int (*y2)[3] = &x[1];

Well, x[1] is an array , not a pointer. 嗯, x[1]是一个数组 ,而不是一个指针。 The funky detail here is that address of the array is the array itself :), so to say, as in: 这里的时髦细节是数组的地址是数组本身:),所以说,如:

int a[10] = {0};
assert(( int* )a == ( int* )&a);

Edit 0: 编辑0:

To answer your question in the comment: A line like int a[XXX]; 在评论中回答你的问题:像int a[XXX]; reserves a chunk of memory of size sizeof( int ) * XXX . 保留一小块sizeof( int ) * XXX的内存。 Every time you use a to access that memory, a is replaced with the address of the first element. 每次使用a访问该内存时, a都会替换为第一个元素的地址。 The compiler knows that address (or at least the offset of the first element from the data segment or from the stack frame). 编译器知道该地址(或至少是数据段或堆栈帧中第一个元素的偏移量)。 This eliminates the need for storing that address in a temporary, and then dereferencing that temporary to get to the memory itself. 这消除了将该地址存储在临时中,然后将其临时解除引用以获取内存本身的需要。 Compiler forms the expression with (almost) direct value of the address. 编译器用(几乎)地址的直接值形成表达式。 Thus a here in a sense has no location to take address of, so to preserve the semantics the &a is short-circuited to just a . 因此, a在这里的感觉已经没有位置拿的地址,所以保留语义&a短路只是a

On the other hand, if you pass a as a function argument it's decayed to a pointer. 在另一方面,如果你传递a作为函数参数它腐烂的指针。

All fun stuff. 所有有趣的东西。 Get yourself this book to see more: "Expert C Programming Deep C Secrets" 获取本书以了解更多信息: “专家C编程Deep C Secrets”

Because a 2D array does not store the actual pointer of each rows. 因为2D数组不存储每行的实际指针。 On the stack, only the address of the first element is stored. 在堆栈上,仅存储第一个元素的地址。 Since the x array has a fixed known size the offsets are calculated on compile time. 由于x数组具有固定的已知大小,因此在编译时计算偏移量。

The expression (int*)&x[1] downgrades the array to a pointer, returning the same value. 表达式(int*)&x[1]将数组降级为指针,返回相同的值。

The expression x[1] returns the address of the value 4 in memory. 表达式x[1]返回内存中值4的地址。 Using the & operator you are asking for the address of the address of the value 4 , which does not make much sense in this case. 使用&运算符,您要求输入值4的地址,这在这种情况下没有多大意义。

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

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