为什么x[0] != x[0][0] != x[0][0][0]?

时间:2022-09-06 16:32:34

I'm studying a little of C++ and I'm fighting with pointers. I understand that I can have 3 level of pointers by declaring:

我正在学习一些c++的知识,我在与指针做斗争。我知道我可以通过声明:

int *(*x)[5];

so that *x is a pointer to an array of 5 elements that are pointers to int. Also I know that x[0] = *(x+0);, x[1] = *(x+1)and so on....

因此* x 5的指针指向数组元素的指针int。我也知道x[0]= *(x + 0);x[1]= *(x + 1)等等....

So, given the above declaration, why is x[0] != x[0][0] != x[0][0][0] ?

那么,基于上述声明,为什么x[0] != x[0][0] != x[0][0][0] ?

11 个解决方案

#1


256  

x is a pointer to an array of 5 pointers to int.
x[0] is an array of 5 pointers to int.
x[0][0] is a pointer to an int.
x[0][0][0] is an int.

x是指向5个指针的数组,x[0]是指向int的5个指针,x[0][0]是指向int的指针,x[0][0][0]是int。

                       x[0]
   Pointer to array  +------+                                 x[0][0][0]         
x -----------------> |      |         Pointer to int           +-------+
               0x500 | 0x100| x[0][0]---------------->   0x100 |  10   |
x is a pointer to    |      |                                  +-------+
an array of 5        +------+                        
pointers to int      |      |         Pointer to int                             
               0x504 | 0x222| x[0][1]---------------->   0x222                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x508 | 0x001| x[0][2]---------------->   0x001                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x50C | 0x123| x[0][3]---------------->   0x123                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x510 | 0x000| x[0][4]---------------->   0x000                    
                     |      |                                             
                     +------+                                             

You can see that

你可以看到,

  • x[0] is an array and will converted to pointer to its first element when used in an expression (with some exceptions). Therefore x[0] will give the address of its first element x[0][0] which is 0x500.
  • x[0]是一个数组,在表达式中使用时将转换为指向第一个元素的指针(有些例外)。所以x[0]会给出第一个元素x[0][0]的地址也就是0x500。
  • x[0][0] contains address of an int which is 0x100.
  • [0][0]包含int的地址,即0x100。
  • x[0][0][0] contains an int value of 10.
  • x[0][0][0]包含10的int值。

So, x[0] is equal to &x[0][0]and therefore, &x[0][0] != x[0][0].
Hence, x[0] != x[0][0] != x[0][0][0].

所以,x[0]= x[0][0]因此,x[0][0]! = x[0][0]。因此,x[0] != x[0][0] != x[0][0][0]。

#2


131  

x[0] != x[0][0] != x[0][0][0]

is, according to your own post,

是,根据你自己的帖子,

*(x+0) != *(*(x+0)+0) != *(*(*(x+0)+0)+0)`  

which is simplified

这是简化

*x != **x != ***x

Why should it be equal?
The first one is the address of some pointer.
The second one is the address of another pointer.
And the third one is some int value.

为什么它应该是相等的?第一个是某个指针的地址。第二个是另一个指针的地址。第三个是某个int值。

#3


47  

Here is the memory layout of your pointer:

这里是你的指针的内存布局:

   +------------------+
x: | address of array |
   +------------------+
            |
            V
            +-----------+-----------+-----------+-----------+-----------+
            | pointer 0 | pointer 1 | pointer 2 | pointer 3 | pointer 4 |
            +-----------+-----------+-----------+-----------+-----------+
                  |
                  V
                  +--------------+
                  | some integer |
                  +--------------+

x[0] yields "address of array",
x[0][0] yields "pointer 0",
x[0][0][0] yields "some integer".

x[0]产生“数组地址”,x[0][0]产生“指针0”,x[0][0][0]产生“某个整数”。

I believe, it should be obvious now, why they are all different.

我相信,现在应该很明显了,为什么它们都不一样。


The above is close enough for basic understanding, which is why I wrote it the way I wrote it. However, as haccks rightly points out, the first line is not 100% precise. So here come all the fine details:

上面的内容非常接近于基本的理解,这就是为什么我写它的方式。然而,正如haccks正确指出的那样,第一行并非100%准确。这里是所有的细节:

From the definition of the C language, the value of x[0] is the whole array of integer pointers. However, arrays are something you can't really do anything with in C. You always manipulate either their address or their elements, never the entire array as a whole:

根据C语言的定义,x[0]的值是整型指针的数组。但是,数组在c中是你做不到的,你总是操作它们的地址或元素,而不是整个数组:

  1. You can pass x[0] to the sizeof operator. But that's not really a use of the value, its result depends of the type only.

    您可以将x[0]传递给sizeof运算符。但这并不是值的使用,它的结果只取决于类型。

  2. You can take its address which yields the value of x, i. e. "address of array" with the type int*(*)[5]. In other words: &x[0] <=> &*(x + 0) <=> (x + 0) <=> x

    你可以取它的地址,得到x的值,即。“数组地址”,类型为int*(*)[5]。换句话说:x[0]< = > & *(x + 0)< = >(x + 0)< = > x

  3. In all other contexts, the value of x[0] will decay into a pointer to the first element in the array. That is, a pointer with the value "address of array" and the type int**. The effect is the same as if you had casted x to a pointer of type int**.

    在所有其他上下文中,x[0]的值将衰减为指向数组中第一个元素的指针。即一个指针,其值为“数组的地址”,类型为int**。效果与将x转换为int**类型的指针相同。

Due to the array-pointer decay in case 3., all uses of x[0] ultimately result in a pointer that points the beginning of the pointer array; the call printf("%p", x[0]) will print the contents of the memory cells labeled as "address of array".

由于数组指针在情形3中的衰减。,所有对x[0]的使用最终导致指向指针数组开头的指针;调用printf(“%p”,x[0])将打印标记为“数组地址”的内存单元的内容。

#4


18  

  • x[0] dereferences the outermost pointer (pointer to array of size 5 of pointer to int) and results in an array of size 5 of pointer to int;
  • x[0]去引用最外面的指针(指针大小为5的数组指向int),结果得到一个指针大小为5的数组指向int;
  • x[0][0] dereferences the outermost pointer and indexes the array, resulting in a pointer to int;
  • x[0][0]删除最外面的指针并对数组进行索引,从而产生指向int的指针;
  • x[0][0][0] dereferences everything, resulting in a concrete value.
  • x[0][0][0]将所有东西都去除,得到一个具体的值。

By the way, if you ever feel confused by what these kind of declarations mean, use cdecl.

顺便说一下,如果您对这些声明的含义感到困惑,请使用cdecl。

#5


11  

Let consider step by step expressions x[0], x[0][0] and x[0][0][0].

让我们一步一步地考虑表达式x[0], x[0][0]和x[0][0][0]。

As x is defined the following way

x的定义如下

int *(*x)[5];

then expression x[0] is an array of type int *[5]. Take into account that expression x[0] is equivalent to expression *x. That is dereferencing a pointer to an array we get the array itself. Let denote it like y that is we have a declaration

那么表达式x[0]是一个类型为int *[5]的数组。考虑到表达式x[0]等于表达式x。那就是取消指向数组的指针我们得到数组本身。我们把它表示成y这是一个声明

int * y[5];

Expression x[0][0] is equivalent to y[0] and has type int *. Let denote it like z that is we have a declaration

表达式x[0][0]等于y[0],类型为int *。我们把它表示成z我们有一个声明

int *z;

expression x[0][0][0] is equivalent to expression y[0][0] that in turn is equivalent to expression z[0] and has type int.

表达式x[0][0][0]等价于表达式y[0][0],它也等价于表达式z[0]并具有类型int。

So we have

所以我们有

x[0] has type int *[5]

x[0]类型为int *[5]

x[0][0] has type int *

[0][0]类型为int *

x[0][0][0] has type int

x[0][0][0]int类型

So they are objects of different types and by the way of different sizes.

所以它们是不同类型和大小的物体。

Run for example

例如运行

std::cout << sizeof( x[0] ) << std::endl;
std::cout << sizeof( x[0][0] ) << std::endl;
std::cout << sizeof( x[0][0][0] ) << std::endl;

#6


8  

First thing I have to say that

首先我要说的是

x [ 0 ] = * ( x + 0 ) = * x ;

x [0] = * (x + 0) = * x;

x [ 0 ] [ 0 ] = * ( * ( x + 0 ) + 0 ) = * * x ;

[0] [0] = * (* (x + 0) + 0) = * * x;

x [ 0 ] [ 0 ] [ 0 ] = * ( * ( * ( x + 0 ) + 0 ) ) = * * * x ;

x[0][0][0]= *(*(*(x + 0)+ 0))= * * * x;

So * x ≠ * * x ≠ * * * x

所以* x≠* * x≠* * * x

From the following picture all things are clear.

从下面的图片中,一切都很清楚。

  x[0][0][0]= 2000

  x[0][0]   = 1001

  x[0]      = 10

为什么x[0] != x[0][0] != x[0][0][0]?

It is just an example, where value of x[0][0][0]=10

它只是一个例子,其中x[0][0][0] =10的值。

and address of x[0][0][0] is 1001

x[0][0][0]的地址是1001。

that address is stored in x[0][0]=1001

该地址存储在x[0][0]=1001中

and address of x[0][0] is 2000

而x[0][0]的地址是2000

and that address is stored at x[0]=2000

这个地址存储在x[0]=2000处

So x[0][0][0] x[0][0] x[0]

所以x[0][0][0]≠x[0][0]≠x[0]

.

EDITINGS

编辑

Program 1:

项目1:

{
int ***x;
x=(int***)malloc(sizeof(int***));
*x=(int**)malloc(sizeof(int**));
**x=(int*)malloc(sizeof(int*));
***x=10;
printf("%d   %d   %d   %d\n",x,*x,**x,***x);
printf("%d   %d   %d   %d   %d",x[0][0][0],x[0][0],x[0],x,&x);
}

Output

输出

142041096 142041112 142041128 10
10 142041128 142041112 142041096 -1076392836

Program 2:

项目2:

{
int x[1][1][1]={10};
printf("%d   %d   %d   %d \n ",x[0][0][0],x[0][0],x[0],&x);
}

Output

输出

10   -1074058436   -1074058436   -1074058436 

#7


7  

If you were to view the arrays from a real-world perspective, it would appear as thus:

如果您从真实世界的角度来看这些数组,它将如下所示:

x[0] is a freight container full of crates.
x[0][0] is a single crate, full of shoeboxes, within the freight container.
x[0][0][0] is a single shoebox inside the crate, inside the freight container.

[0]是一个装满箱子的货柜。[0][0]是一个单独的板条箱,装满了鞋盒,装在货柜里。[0][0][0]是货柜里的一个鞋盒。

Even if it were the only shoebox in the only crate in the freight container, it is still a shoebox and not a freight container

即使它是货柜里唯一的鞋盒,它仍然是鞋盒,而不是货柜

#8


4  

There's a principle in C++ so that: a declaration of a variable indicates exactly the way of using the variable. Consider your declaration:

c++中有一个原则:一个变量的声明明确地指出了使用该变量的方式。考虑你的声明:

int *(*x)[5];

that can be rewritten as (for clearer):

可以重写为(为了更清楚):

int *((*x)[5]);

Due to the principle, we have:

由于这个原则,我们有:

*((*x)[i]) is treated as an int value (i = 0..4)
→ (*x)[i] is treated as an int* pointer (i = 0..4)
→ *x is treated as an int** pointer
→ x is treated as an int*** pointer

Therefore:

因此:

x[0] is an int** pointer
→ x[0][0] = (x[0]) [0] is an int* pointer
→ x[0][0][0] = (x[0][0]) [0] is an int value

So you can figure out the difference.

你可以算出它们的差值。

#9


2  

Being p a pointer: you're stacking dereferences with p[0][0], which is equivalent to *((*(p+0))+0).

p是一个指针:你在用p[0][0]堆叠去引用,它等于*(*(*(p+0))+0)。

In C reference (&) and dereference (*) notation:

在C引用(&)和取消引用(*)表示法中:

p == &p[0] == &(&p[0])[0] == &(&(&p[0])[0])[0])

Is equivalent to:

等价于:

p == &*(p+0) == &*(&*(p+0))+0 == &*(&*(&*(p+0))+0)+0

Look that, the &* can be refactored, just removing it:

看,&*可以重构,只需删除它:

p == p+0 == p+0+0 == p+0+0+0 == (((((p+0)+0)+0)+0)+0)

#10


1  

You are trying to compare different types by value

您正在尝试按值比较不同的类型

If you take the addresses you might get more of what you expect

如果你取地址,你可能会得到更多你想要的

Keep in mind that your declaration makes a difference

请记住,您的声明会产生影响

 int y [5][5][5];

would allow the comparisons you want, since y, y[0], y[0][0], y[0][0][0] would have different values and types but the same address

将允许比较,因为y, y[0], y[0][0], y[0][0][0]会有不同的值和类型,但是相同的地址?

int **x[5];

does not occupy contiguous space.

不占用相邻的空间。

x and x [0] have the same address, but x[0][0] and x[0][0][0] are each at different addresses

x和x[0]有相同的地址,但是x[0][0]和x[0][0][0]各有不同的地址

#11


1  

The other answers are correct, but none of them emphasize the idea that it is possible for all three to contain the same value, and so they're in some way incomplete.

其他的答案是正确的,但是没有一个强调这三个都包含相同的值是可能的,所以它们在某种程度上是不完整的。

The reason this can't be understood from the other answers is that all the illustrations, while helpful and definitely reasonable under most circumstances, fail to cover the situation where the pointer x points to itself.

从其他答案中无法理解这一点的原因是,虽然所有的插图在大多数情况下都是有用的,而且绝对合理的,但它们并没有涵盖指针x指向自己的情况。

This is pretty easy to construct, but clearly a bit harder to understand. In the program below, we'll see how we can force all three values to be identical.

这很容易构造,但显然有点难理解。在下面的程序中,我们将看到如何使这三个值都相同。

NOTE: The behavior in this program is undefined, but I'm posting it here purely as an interesting demonstration of something that pointers can do, but shouldn't.

注意:这个程序中的行为是没有定义的,但是我把它发布到这里纯粹是为了演示指针可以做的事情,但是不应该这样做。

#include <stdio.h>

int main () {
  int *(*x)[5];

  x = (int *(*)[5]) &x;

  printf("%p\n", x[0]);
  printf("%p\n", x[0][0]);
  printf("%p\n", x[0][0][0]);
}

This compiles without warnings in both C89 and C99, and the output is the following:

这在C89和C99中编译时没有任何警告,输出如下:

$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c

Interestingly enough, all three values are identical. But this shouldn't be a surprise! First, let's break down the program.

有趣的是,这三个值都是相同的。但这不应该是一个惊喜!首先,让我们分解这个程序。

We declare x as a pointer to an array of 5 elements where each element is of type pointer to int. This declaration allocates 4 bytes on the runtime stack (or more depending on your implementation; on my machine pointers are 4 bytes), so x is referring to an actual memory location. In the C family of languages, the contents of x are just garbage, something left over from previous usage of the location, so x itself doesn't point anywhere—certainly not to allocated space.

我们将x声明为指向5个元素的数组的指针,其中每个元素的类型都是指向int的指针。在我的机器指针上是4字节),所以x指的是一个实际的内存位置。在C族语言中,x的内容只是垃圾,是以前使用位置时遗留下来的东西,所以x本身没有指向任何地方——当然也没有指向分配的空间。

So, naturally, we can take the address of the variable x and put it somewhere, so that's exactly what we do. But we'll go ahead and put it into x itself. Since &x has a different type than x, we need to do a cast so we don't get warnings.

自然地,我们可以取变量x的地址,把它放在某个地方,这就是我们要做的。我们把它代入x。因为&x与x有不同的类型,所以我们需要进行强制转换,这样就不会收到警告。

The memory model would look something like this:

记忆模型是这样的

0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+

So the 4-byte block of memory at the address 0xbfd9198c contains the bit pattern corresponding to the hexadecimal value 0xbfd9198c. Simple enough.

所以地址为0xbfd9198c的4字节内存块包含与十六进制值0xbfd9198c对应的位模式。很简单。

Next, we print out the three values. The other answers explain what each expression refers to, so the relationship should be clear now.

接下来,我们打印出这三个值。其他的答案解释了每个表达式指的是什么,所以现在关系应该很清楚了。

We can see that the values are the same, but only in a very low level sense...their bit patterns are identical, but the type data associated with each expression means their interpreted values are different. For instance, if we printed out x[0][0][0] using the format string %d, we'd get a huge negative number, so the "values" are, in practice, different, but the bit pattern is the same.

我们可以看到这些值是相同的,但只是在非常低的层次上…它们的位模式是相同的,但是与每个表达式相关联的类型数据意味着它们的解释值是不同的。例如,如果我们使用格式字符串%d打印出x[0][0][0],我们会得到一个巨大的负数,因此“值”实际上是不同的,但是位模式是相同的。

This is actually really simple...in the diagrams, the arrows just point to the same memory address rather than to different ones. However, while we were able to force an expected result out of undefined behavior, it is just that—undefined. This isn't production code but simply a demonstration for the sake of completeness.

这其实很简单……在图中,箭头指向相同的内存地址,而不是不同的内存地址。然而,尽管我们能够迫使未定义的行为产生预期的结果,但这正是未定义的。这不是生产代码,而是为了完整性而进行的演示。

In a reasonable situation, you will use malloc to create the array of 5 int pointers, and again to create the ints that are pointed to in that array. malloc always returns a unique address (unless you're out of memory, in which case it returns NULL or 0), so you'll never have to worry about self-referential pointers like this.

在合理的情况下,您将使用malloc创建5个int指针的数组,并再次创建指向该数组的int类型。malloc总是返回一个唯一的地址(除非内存不足,在这种情况下它返回NULL或0),所以您不必担心像这样的自引用指针。

Hopefully that's the complete answer you're looking for. You shouldn't expect x[0], x[0][0], and x[0][0][0] to be equal, but they could be if forced. If anything went over your head, let me know so I can clarify!

希望这就是你要找的完整答案。你不应该期望x[0], x[0][0],和x[0][0][0]是相等的,但它们可能是*的。如果你有什么不明白的地方,请告诉我,以便我能说清楚!

#1


256  

x is a pointer to an array of 5 pointers to int.
x[0] is an array of 5 pointers to int.
x[0][0] is a pointer to an int.
x[0][0][0] is an int.

x是指向5个指针的数组,x[0]是指向int的5个指针,x[0][0]是指向int的指针,x[0][0][0]是int。

                       x[0]
   Pointer to array  +------+                                 x[0][0][0]         
x -----------------> |      |         Pointer to int           +-------+
               0x500 | 0x100| x[0][0]---------------->   0x100 |  10   |
x is a pointer to    |      |                                  +-------+
an array of 5        +------+                        
pointers to int      |      |         Pointer to int                             
               0x504 | 0x222| x[0][1]---------------->   0x222                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x508 | 0x001| x[0][2]---------------->   0x001                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x50C | 0x123| x[0][3]---------------->   0x123                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x510 | 0x000| x[0][4]---------------->   0x000                    
                     |      |                                             
                     +------+                                             

You can see that

你可以看到,

  • x[0] is an array and will converted to pointer to its first element when used in an expression (with some exceptions). Therefore x[0] will give the address of its first element x[0][0] which is 0x500.
  • x[0]是一个数组,在表达式中使用时将转换为指向第一个元素的指针(有些例外)。所以x[0]会给出第一个元素x[0][0]的地址也就是0x500。
  • x[0][0] contains address of an int which is 0x100.
  • [0][0]包含int的地址,即0x100。
  • x[0][0][0] contains an int value of 10.
  • x[0][0][0]包含10的int值。

So, x[0] is equal to &x[0][0]and therefore, &x[0][0] != x[0][0].
Hence, x[0] != x[0][0] != x[0][0][0].

所以,x[0]= x[0][0]因此,x[0][0]! = x[0][0]。因此,x[0] != x[0][0] != x[0][0][0]。

#2


131  

x[0] != x[0][0] != x[0][0][0]

is, according to your own post,

是,根据你自己的帖子,

*(x+0) != *(*(x+0)+0) != *(*(*(x+0)+0)+0)`  

which is simplified

这是简化

*x != **x != ***x

Why should it be equal?
The first one is the address of some pointer.
The second one is the address of another pointer.
And the third one is some int value.

为什么它应该是相等的?第一个是某个指针的地址。第二个是另一个指针的地址。第三个是某个int值。

#3


47  

Here is the memory layout of your pointer:

这里是你的指针的内存布局:

   +------------------+
x: | address of array |
   +------------------+
            |
            V
            +-----------+-----------+-----------+-----------+-----------+
            | pointer 0 | pointer 1 | pointer 2 | pointer 3 | pointer 4 |
            +-----------+-----------+-----------+-----------+-----------+
                  |
                  V
                  +--------------+
                  | some integer |
                  +--------------+

x[0] yields "address of array",
x[0][0] yields "pointer 0",
x[0][0][0] yields "some integer".

x[0]产生“数组地址”,x[0][0]产生“指针0”,x[0][0][0]产生“某个整数”。

I believe, it should be obvious now, why they are all different.

我相信,现在应该很明显了,为什么它们都不一样。


The above is close enough for basic understanding, which is why I wrote it the way I wrote it. However, as haccks rightly points out, the first line is not 100% precise. So here come all the fine details:

上面的内容非常接近于基本的理解,这就是为什么我写它的方式。然而,正如haccks正确指出的那样,第一行并非100%准确。这里是所有的细节:

From the definition of the C language, the value of x[0] is the whole array of integer pointers. However, arrays are something you can't really do anything with in C. You always manipulate either their address or their elements, never the entire array as a whole:

根据C语言的定义,x[0]的值是整型指针的数组。但是,数组在c中是你做不到的,你总是操作它们的地址或元素,而不是整个数组:

  1. You can pass x[0] to the sizeof operator. But that's not really a use of the value, its result depends of the type only.

    您可以将x[0]传递给sizeof运算符。但这并不是值的使用,它的结果只取决于类型。

  2. You can take its address which yields the value of x, i. e. "address of array" with the type int*(*)[5]. In other words: &x[0] <=> &*(x + 0) <=> (x + 0) <=> x

    你可以取它的地址,得到x的值,即。“数组地址”,类型为int*(*)[5]。换句话说:x[0]< = > & *(x + 0)< = >(x + 0)< = > x

  3. In all other contexts, the value of x[0] will decay into a pointer to the first element in the array. That is, a pointer with the value "address of array" and the type int**. The effect is the same as if you had casted x to a pointer of type int**.

    在所有其他上下文中,x[0]的值将衰减为指向数组中第一个元素的指针。即一个指针,其值为“数组的地址”,类型为int**。效果与将x转换为int**类型的指针相同。

Due to the array-pointer decay in case 3., all uses of x[0] ultimately result in a pointer that points the beginning of the pointer array; the call printf("%p", x[0]) will print the contents of the memory cells labeled as "address of array".

由于数组指针在情形3中的衰减。,所有对x[0]的使用最终导致指向指针数组开头的指针;调用printf(“%p”,x[0])将打印标记为“数组地址”的内存单元的内容。

#4


18  

  • x[0] dereferences the outermost pointer (pointer to array of size 5 of pointer to int) and results in an array of size 5 of pointer to int;
  • x[0]去引用最外面的指针(指针大小为5的数组指向int),结果得到一个指针大小为5的数组指向int;
  • x[0][0] dereferences the outermost pointer and indexes the array, resulting in a pointer to int;
  • x[0][0]删除最外面的指针并对数组进行索引,从而产生指向int的指针;
  • x[0][0][0] dereferences everything, resulting in a concrete value.
  • x[0][0][0]将所有东西都去除,得到一个具体的值。

By the way, if you ever feel confused by what these kind of declarations mean, use cdecl.

顺便说一下,如果您对这些声明的含义感到困惑,请使用cdecl。

#5


11  

Let consider step by step expressions x[0], x[0][0] and x[0][0][0].

让我们一步一步地考虑表达式x[0], x[0][0]和x[0][0][0]。

As x is defined the following way

x的定义如下

int *(*x)[5];

then expression x[0] is an array of type int *[5]. Take into account that expression x[0] is equivalent to expression *x. That is dereferencing a pointer to an array we get the array itself. Let denote it like y that is we have a declaration

那么表达式x[0]是一个类型为int *[5]的数组。考虑到表达式x[0]等于表达式x。那就是取消指向数组的指针我们得到数组本身。我们把它表示成y这是一个声明

int * y[5];

Expression x[0][0] is equivalent to y[0] and has type int *. Let denote it like z that is we have a declaration

表达式x[0][0]等于y[0],类型为int *。我们把它表示成z我们有一个声明

int *z;

expression x[0][0][0] is equivalent to expression y[0][0] that in turn is equivalent to expression z[0] and has type int.

表达式x[0][0][0]等价于表达式y[0][0],它也等价于表达式z[0]并具有类型int。

So we have

所以我们有

x[0] has type int *[5]

x[0]类型为int *[5]

x[0][0] has type int *

[0][0]类型为int *

x[0][0][0] has type int

x[0][0][0]int类型

So they are objects of different types and by the way of different sizes.

所以它们是不同类型和大小的物体。

Run for example

例如运行

std::cout << sizeof( x[0] ) << std::endl;
std::cout << sizeof( x[0][0] ) << std::endl;
std::cout << sizeof( x[0][0][0] ) << std::endl;

#6


8  

First thing I have to say that

首先我要说的是

x [ 0 ] = * ( x + 0 ) = * x ;

x [0] = * (x + 0) = * x;

x [ 0 ] [ 0 ] = * ( * ( x + 0 ) + 0 ) = * * x ;

[0] [0] = * (* (x + 0) + 0) = * * x;

x [ 0 ] [ 0 ] [ 0 ] = * ( * ( * ( x + 0 ) + 0 ) ) = * * * x ;

x[0][0][0]= *(*(*(x + 0)+ 0))= * * * x;

So * x ≠ * * x ≠ * * * x

所以* x≠* * x≠* * * x

From the following picture all things are clear.

从下面的图片中,一切都很清楚。

  x[0][0][0]= 2000

  x[0][0]   = 1001

  x[0]      = 10

为什么x[0] != x[0][0] != x[0][0][0]?

It is just an example, where value of x[0][0][0]=10

它只是一个例子,其中x[0][0][0] =10的值。

and address of x[0][0][0] is 1001

x[0][0][0]的地址是1001。

that address is stored in x[0][0]=1001

该地址存储在x[0][0]=1001中

and address of x[0][0] is 2000

而x[0][0]的地址是2000

and that address is stored at x[0]=2000

这个地址存储在x[0]=2000处

So x[0][0][0] x[0][0] x[0]

所以x[0][0][0]≠x[0][0]≠x[0]

.

EDITINGS

编辑

Program 1:

项目1:

{
int ***x;
x=(int***)malloc(sizeof(int***));
*x=(int**)malloc(sizeof(int**));
**x=(int*)malloc(sizeof(int*));
***x=10;
printf("%d   %d   %d   %d\n",x,*x,**x,***x);
printf("%d   %d   %d   %d   %d",x[0][0][0],x[0][0],x[0],x,&x);
}

Output

输出

142041096 142041112 142041128 10
10 142041128 142041112 142041096 -1076392836

Program 2:

项目2:

{
int x[1][1][1]={10};
printf("%d   %d   %d   %d \n ",x[0][0][0],x[0][0],x[0],&x);
}

Output

输出

10   -1074058436   -1074058436   -1074058436 

#7


7  

If you were to view the arrays from a real-world perspective, it would appear as thus:

如果您从真实世界的角度来看这些数组,它将如下所示:

x[0] is a freight container full of crates.
x[0][0] is a single crate, full of shoeboxes, within the freight container.
x[0][0][0] is a single shoebox inside the crate, inside the freight container.

[0]是一个装满箱子的货柜。[0][0]是一个单独的板条箱,装满了鞋盒,装在货柜里。[0][0][0]是货柜里的一个鞋盒。

Even if it were the only shoebox in the only crate in the freight container, it is still a shoebox and not a freight container

即使它是货柜里唯一的鞋盒,它仍然是鞋盒,而不是货柜

#8


4  

There's a principle in C++ so that: a declaration of a variable indicates exactly the way of using the variable. Consider your declaration:

c++中有一个原则:一个变量的声明明确地指出了使用该变量的方式。考虑你的声明:

int *(*x)[5];

that can be rewritten as (for clearer):

可以重写为(为了更清楚):

int *((*x)[5]);

Due to the principle, we have:

由于这个原则,我们有:

*((*x)[i]) is treated as an int value (i = 0..4)
→ (*x)[i] is treated as an int* pointer (i = 0..4)
→ *x is treated as an int** pointer
→ x is treated as an int*** pointer

Therefore:

因此:

x[0] is an int** pointer
→ x[0][0] = (x[0]) [0] is an int* pointer
→ x[0][0][0] = (x[0][0]) [0] is an int value

So you can figure out the difference.

你可以算出它们的差值。

#9


2  

Being p a pointer: you're stacking dereferences with p[0][0], which is equivalent to *((*(p+0))+0).

p是一个指针:你在用p[0][0]堆叠去引用,它等于*(*(*(p+0))+0)。

In C reference (&) and dereference (*) notation:

在C引用(&)和取消引用(*)表示法中:

p == &p[0] == &(&p[0])[0] == &(&(&p[0])[0])[0])

Is equivalent to:

等价于:

p == &*(p+0) == &*(&*(p+0))+0 == &*(&*(&*(p+0))+0)+0

Look that, the &* can be refactored, just removing it:

看,&*可以重构,只需删除它:

p == p+0 == p+0+0 == p+0+0+0 == (((((p+0)+0)+0)+0)+0)

#10


1  

You are trying to compare different types by value

您正在尝试按值比较不同的类型

If you take the addresses you might get more of what you expect

如果你取地址,你可能会得到更多你想要的

Keep in mind that your declaration makes a difference

请记住,您的声明会产生影响

 int y [5][5][5];

would allow the comparisons you want, since y, y[0], y[0][0], y[0][0][0] would have different values and types but the same address

将允许比较,因为y, y[0], y[0][0], y[0][0][0]会有不同的值和类型,但是相同的地址?

int **x[5];

does not occupy contiguous space.

不占用相邻的空间。

x and x [0] have the same address, but x[0][0] and x[0][0][0] are each at different addresses

x和x[0]有相同的地址,但是x[0][0]和x[0][0][0]各有不同的地址

#11


1  

The other answers are correct, but none of them emphasize the idea that it is possible for all three to contain the same value, and so they're in some way incomplete.

其他的答案是正确的,但是没有一个强调这三个都包含相同的值是可能的,所以它们在某种程度上是不完整的。

The reason this can't be understood from the other answers is that all the illustrations, while helpful and definitely reasonable under most circumstances, fail to cover the situation where the pointer x points to itself.

从其他答案中无法理解这一点的原因是,虽然所有的插图在大多数情况下都是有用的,而且绝对合理的,但它们并没有涵盖指针x指向自己的情况。

This is pretty easy to construct, but clearly a bit harder to understand. In the program below, we'll see how we can force all three values to be identical.

这很容易构造,但显然有点难理解。在下面的程序中,我们将看到如何使这三个值都相同。

NOTE: The behavior in this program is undefined, but I'm posting it here purely as an interesting demonstration of something that pointers can do, but shouldn't.

注意:这个程序中的行为是没有定义的,但是我把它发布到这里纯粹是为了演示指针可以做的事情,但是不应该这样做。

#include <stdio.h>

int main () {
  int *(*x)[5];

  x = (int *(*)[5]) &x;

  printf("%p\n", x[0]);
  printf("%p\n", x[0][0]);
  printf("%p\n", x[0][0][0]);
}

This compiles without warnings in both C89 and C99, and the output is the following:

这在C89和C99中编译时没有任何警告,输出如下:

$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c

Interestingly enough, all three values are identical. But this shouldn't be a surprise! First, let's break down the program.

有趣的是,这三个值都是相同的。但这不应该是一个惊喜!首先,让我们分解这个程序。

We declare x as a pointer to an array of 5 elements where each element is of type pointer to int. This declaration allocates 4 bytes on the runtime stack (or more depending on your implementation; on my machine pointers are 4 bytes), so x is referring to an actual memory location. In the C family of languages, the contents of x are just garbage, something left over from previous usage of the location, so x itself doesn't point anywhere—certainly not to allocated space.

我们将x声明为指向5个元素的数组的指针,其中每个元素的类型都是指向int的指针。在我的机器指针上是4字节),所以x指的是一个实际的内存位置。在C族语言中,x的内容只是垃圾,是以前使用位置时遗留下来的东西,所以x本身没有指向任何地方——当然也没有指向分配的空间。

So, naturally, we can take the address of the variable x and put it somewhere, so that's exactly what we do. But we'll go ahead and put it into x itself. Since &x has a different type than x, we need to do a cast so we don't get warnings.

自然地,我们可以取变量x的地址,把它放在某个地方,这就是我们要做的。我们把它代入x。因为&x与x有不同的类型,所以我们需要进行强制转换,这样就不会收到警告。

The memory model would look something like this:

记忆模型是这样的

0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+

So the 4-byte block of memory at the address 0xbfd9198c contains the bit pattern corresponding to the hexadecimal value 0xbfd9198c. Simple enough.

所以地址为0xbfd9198c的4字节内存块包含与十六进制值0xbfd9198c对应的位模式。很简单。

Next, we print out the three values. The other answers explain what each expression refers to, so the relationship should be clear now.

接下来,我们打印出这三个值。其他的答案解释了每个表达式指的是什么,所以现在关系应该很清楚了。

We can see that the values are the same, but only in a very low level sense...their bit patterns are identical, but the type data associated with each expression means their interpreted values are different. For instance, if we printed out x[0][0][0] using the format string %d, we'd get a huge negative number, so the "values" are, in practice, different, but the bit pattern is the same.

我们可以看到这些值是相同的,但只是在非常低的层次上…它们的位模式是相同的,但是与每个表达式相关联的类型数据意味着它们的解释值是不同的。例如,如果我们使用格式字符串%d打印出x[0][0][0],我们会得到一个巨大的负数,因此“值”实际上是不同的,但是位模式是相同的。

This is actually really simple...in the diagrams, the arrows just point to the same memory address rather than to different ones. However, while we were able to force an expected result out of undefined behavior, it is just that—undefined. This isn't production code but simply a demonstration for the sake of completeness.

这其实很简单……在图中,箭头指向相同的内存地址,而不是不同的内存地址。然而,尽管我们能够迫使未定义的行为产生预期的结果,但这正是未定义的。这不是生产代码,而是为了完整性而进行的演示。

In a reasonable situation, you will use malloc to create the array of 5 int pointers, and again to create the ints that are pointed to in that array. malloc always returns a unique address (unless you're out of memory, in which case it returns NULL or 0), so you'll never have to worry about self-referential pointers like this.

在合理的情况下,您将使用malloc创建5个int指针的数组,并再次创建指向该数组的int类型。malloc总是返回一个唯一的地址(除非内存不足,在这种情况下它返回NULL或0),所以您不必担心像这样的自引用指针。

Hopefully that's the complete answer you're looking for. You shouldn't expect x[0], x[0][0], and x[0][0][0] to be equal, but they could be if forced. If anything went over your head, let me know so I can clarify!

希望这就是你要找的完整答案。你不应该期望x[0], x[0][0],和x[0][0][0]是相等的,但它们可能是*的。如果你有什么不明白的地方,请告诉我,以便我能说清楚!