简体   繁体   English

C++ 中的二维数组指针操作

[英]2Dimensional Array Pointer manipulation in C++

int main(){
    int a[10][10];
    int **ptr =(int **)a;
    cout<<a<<endl<<ptr<<endl;
    cout<<*a<<endl<<*ptr<<endl;
    return 0;
}

Output of this code on my computer is此代码在我的计算机上的输出是

0021FC20
0021FC20
0021FC20
CCCCCCCC

Why is " a " equal to " *a "?为什么“ a ”等于“ *a ”? why isn't *a equal to *ptr?为什么*a 不等于*ptr?

Why is a equal to *a ?为什么a等于*a

When used in a context that requires a pointer, an array will be converted to a pointer to its first element.当在需要指针的上下文中使用时,数组将被转换为指向其第一个元素的指针。 a is an array of arrays; a是一个数组数组; so it will decay to a pointer to the first array.所以它会衰减到指向第一个数组的指针。 *a is the first array, and will decay to a pointer to the first integer in that array. *a是第一个数组,并将衰减为指向该数组中第一个整数的指针。 Both of these exist at the same location, so the two pointers will have equal values.它们都存在于同一位置,因此两个指针将具有相等的值。

why isn't *a equal to *ptr?为什么*a 不等于*ptr?

Because the conversion from an array of arrays, to a pointer-to-pointer, is not valid.因为从数组数组到指针到指针的转换是无效的。 You have forced the conversion using a cast - the dangerous C-style cast, which in this case acts like reinterpret_cast - so *ptr will read the first few bytes of the array and interpret that as a pointer (probably - the behaviour here is undefined, so in principle anything could happen).您已经使用强制转换强制转换 - 危险的 C 样式转换,在这种情况下它的作用类似于reinterpret_cast - 所以*ptr将读取数组的前几个字节并将其解释为一个指针(可能 - 这里的行为是未定义的,所以原则上任何事情都可能发生)。 There is no pointer in the memory pointed to by ptr , so *ptr will certainly not give you a valid pointer. ptr指向的内存中没有指针,所以*ptr肯定不会给你一个有效的指针。

Why is a equal to *a?为什么a等于*a?

Since you cannot print an array, a is implicitly converted from int[10][10] to int(*)[10] .由于您无法打印数组,因此a会从int[10][10]隐式转换为int(*)[10] So what actually gets printed instead of a is a pointer to the first line of a .所以实际打印a是指向 a 第一的指针而不是a

*a is the first line of the array, and that in turn gets converted to a pointer to the first element . *a是数组的第一行,它依次被转换为指向第一个元素的指针。

Since an array has the same address as its first element, you get the same value twice.由于数组与其第一个元素具有相同的地址,因此您会得到两次相同的值。

A 2D C array is NOT a pointer to a pointer.二维 C 数组不是指向指针的指针。 IT is effectively a pointer with rows * columns elements in it.它实际上是一个包含行 * 列元素的指针。

int main(){
    int a[10][10];
    int *ptr =(int *)a;
    cout<<a<<endl<<ptr<<endl;
    cout<<*a<<endl<<*ptr<<endl;
    return 0;
}

The above will give you what you are after.以上将给你你所追求的。

Although when you de-reference a or ptr you will find you get an "undefined value"虽然当你取消引用 a 或 ptr 时,你会发现你得到一个“未定义的值”

if you set a[4][4] to say 5如果您将 a[4][4] 设置为 5

Then you will find the value stored at然后你会发现存储在

ptr[(row * 10) + column) will return that value where row = 4 and column = 4. ptr[(row * 10) + column) 将返回该值,其中 row = 4 和 column = 4。

然后我建议避免大矩阵的静态堆栈分配,而是选择动态分配(在堆上)......

The mechanics of 2D arrays are actually easier than they first appear but it's usually poorly taught.二维数组的机制实际上比它们最初出现的更容易,但通常教得不好。 Nevertheless, it does take a lot of experience to quickly decipher things and even experienced developers sometimes have to stop and think for a moment (or two).尽管如此,快速破译事物确实需要很多经验,即使是经验丰富的开发人员有时也必须停下来思考片刻(或两片)。 Basically, when you see a 2D array such as int a[5][10] (I'm changing the size of your array to 5 to simplify things), you need to stop thinking about it as 2D.基本上,当您看到诸如 int a[5][10] 之类的 2D 数组(我将数组的大小更改为 5 以简化事情)时,您需要停止将其视为 2D。 Think of it as 1D instead.将其视为 1D。 The first subscript specifies the number of elements in this 1D array, just like any other 1D array.第一个下标指定此一维数组中的元素数,就像任何其他一维数组一样。 When you index into the array, such as a[3], you're therefore accessing the object at index 3. This is no different than any other array.当您对数组进行索引时,例如 a[3],您访问的是索引 3 处的对象。这与任何其他数组没有什么不同。 Let's say "a" was defined like this instead:假设“a”是这样定义的:

// Note: The size of the array, 5, can be omitted
int a[5] = {5, 10, 15, 20, 25};

Subscripting then yields this:下标然后产生这个:

a[0] = 5
a[1] = 10
a[2] = 15
a[3] = 20
a[4] = 25

That's easy enough and most get it.这很容易,大多数人都明白了。 But if you now do this:但如果你现在这样做:

// Note: Like above, the size of the array, 5, can be omitted
int a[5][10] = {{  5,  10,  15,  20,  25,  30,  35,  40,  45,  50},
                { 55,  60,  65,  70,  75,  80,  85,  90,  95, 100},
                {105, 110, 115, 120, 125, 130, 135, 140, 145, 150},
                {155, 160, 165, 170, 175, 180, 185, 190, 195, 200},
                {205, 210, 220, 225, 230, 235, 240, 245, 250, 255}};
          

You still have a 1D array of 5 elements, and you can subscript into it just like the previous example, yielding the following (not real syntax, just how you should think about it):您仍然有一个包含 5 个元素的一维数组,您可以像前面的示例一样下标到它,产生以下内容(不是真正的语法,只是您应该如何考虑它):

a[0] =   5  10  15  20  25  30  35  40  45  50
a[1] =  55  60  65  70  75  80  85  90  95 100
a[2] = 105 110 115 120 125 130 135 140 145 150
a[3] = 155 160 165 170 175 180 185 190 195 200
a[4] = 205 210 220 225 230 235 240 245 250 255

The only difference here is that instead of each element being an "int" like the previous example, each element is an array instead (of 10 integers).这里唯一的区别是每个元素不是像前面的例子那样是一个“int”,而是每个元素都是一个数组(10 个整数)。 Therefore, when you subscript into it as seen, each index (0 to 4) returns the array of 10 integers for that row.因此,当您下标时,每个索引(0 到 4)返回该行的 10 个整数数组。 For instance, a[3] returns the array of 10 integers containing the values 155 to 200. The element itself is an "int[10]" and you can therefore treat it that way.例如,a[3] 返回包含 155 到 200 值的 10 个整数数组。元素本身是一个“int[10]”,因此您可以这样对待它。 IOW, you're getting back the equivalent of this: IOW,你得到的相当于这个:

int b[10] = {155, 160, 165, 170, 175, 180, 185, 190, 195, 200};

And so, for example, in the same way that b[7] = 190, a[3][7] = 190 as well, since a[3] is effectively returning the equivalent of b (an array of 10 integers), and the [7] subscript then grabs the element at index 7 of that array, just like b[7].因此,例如,以与 b[7] = 190 相同的方式,a[3][7] = 190 也是如此,因为 a[3] 有效地返回了 b 的等价物(10 个整数的数组),然后 [7] 下标抓取该数组索引 7 处的元素,就像 b[7] 一样。 Moreover, in the same way that b is a pointer to the first element of the array (since all array names decay into a pointer to the first element of the array), which in this case is 155 (ie, "b" decays to an int * pointing at 155), a[3] returns (decays into) the same thing.此外,以同样的方式,b 是指向数组第一个元素的指针(因为所有数组名称都衰减为指向数组第一个元素的指针),在这种情况下为 155(即,“b”衰减为指向 155 的 int *),a[3] 返回(衰减为)相同的东西。 Why?为什么? Because it's returning the equivalent of b as described, and just like b, it decays into a pointer to its first element.因为它像描述的那样返回 b 的等价物,并且就像 b 一样,它衰减为指向其第一个元素的指针。 IOW, just like this is true: IOW,就像这样:

int *p = b; // "b" decays into a pointer to its first element (an "int")
int val = *p; // Equals 155

This is also true:这也是事实:

int *p = a[3]; // a[3] returns the equivalent of "b", an int[10], and this decays into a pointer to its first element, just like "b"
int val = *p; // Equals 155

And finally, just like FredOverflow mentioned, this is also true:最后,就像 FredOverflow 提到的那样,这也是正确的:

int (*p)[10] = a;

The syntax takes getting used to but it makes perfect sense.语法需要习惯,但它非常有意义。 Since every array name decays into a pointer to its first element as discussed, "a" therefore decays into a pointer to its first element.正如所讨论的,由于每个数组名称都会衰减为指向其第一个元素的指针,因此“a”会衰减为指向其第一个元素的指针。 What is that element?那是什么元素? Well, each element of "a" is an array of 10 integers, ie, an "int[10]", so "a" must decay into a pointer to the first of these "int[10]" elements.好吧,“a”的每个元素都是一个由 10 个整数组成的数组,即“int[10]”,因此“a”必须衰减为指向这些“int[10]”元素中第一个元素的指针。 The syntax just above is how you declare this pointer.上面的语法就是你如何声明这个指针。 It defines "p" as a pointer to an array of 10 integers.它将“p”定义为指向 10 个整数数组的指针。 The (circular) brackets are required because of the C++ precedence rules.由于 C++ 优先规则,需要(圆)括号。 If you removed them you would get this:如果你删除它们,你会得到这个:

int *p[10] = a; // Compiler error!

Which declares "p" as an array of 10 elements, where each element is a pointer to an int.其中将“p”声明为一个包含 10 个元素的数组,其中每个元素都是一个指向 int 的指针。 It's not the same IOW so the brackets are required to change the precedence (and hence the meaning of this declaration).这与 IOW 不同,因此需要括号来更改优先级(以及此声明的含义)。 Using the proper syntax previously shown, "p" would therefore point to the first element (the "int[10]" array containing the elements 5 to 50), p + 1 would point to the second element (the "int[10]" array containing the elements 55 to 100), etc. Bonus points: What would the following therefore do?使用前面显示的正确语法,“p”将因此指向第一个元素(包含元素 5 到 50 的“int[10]”数组),p + 1 将指向第二个元素(“int[10]” " 包含元素 55 到 100 的数组) 等。 加分点:因此,以下会做什么?

(*(p + 3))[5]

It returns 180 because (p + 3) returns a pointer to the array of 10 integers at "a[3]" and when dereferenced using the * operator, you get the actual "int[10]" array at this location.它返回 180,因为 (p + 3) 返回一个指向“a[3]”处的 10 个整数数组的指针,当使用 * 运算符取消引用时,您将在此位置获得实际的“int[10]”数组。 The [5] subscript then yields the value 180 in this array. [5] 下标然后在这个数组中产生值 180。

No doubt it will still take a lot of practice to get your head around this but I hope that helps.毫无疑问,你仍然需要大量练习才能解决这个问题,但我希望这会有所帮助。

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

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