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

时间:2012-03-06 11:46:55

标签: c++ pointers multidimensional-array

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

在我的电脑上输出此代码

0021FC20
0021FC20
0021FC20
CCCCCCCC

为什么“ a ”等于“ * a ”? 为什么不等于* ptr?

5 个答案:

答案 0 :(得分:4)

  

为什么a等于*a

在需要指针的上下文中使用时,数组将转换为指向其第一个元素的指针。 a是一个数组数组;所以它会衰减到指向第一个数组的指针。 *a是第一个数组,并将衰减为指向该数组中第一个整数的指针。这两个都存在于同一个位置,因此两个指针的值相等。

  

为什么不等于* ptr?

因为从数组数组到指针指针的转换无效。您已使用强制转换强制转换 - 这是一种危险的C样式转换,在这种情况下就像reinterpret_cast一样 - 所以*ptr将读取数组的前几个字节并将其解释为指针(可能 - 这里的行为是未定义的,因此原则上任何事情都可能发生。 ptr指向的内存中没有指针,因此*ptr肯定不会给你一个有效的指针。

答案 1 :(得分:2)

  

为什么等于* a?

由于您无法打印数组,a会从int[10][10]隐式转换为int(*)[10]。那么实际打印而不是a的是指向a的第一个的指针。

*a是数组的第一行,然后转换为指向第一个元素的指针

由于数组与第一个元素具有相同的地址,因此两次获得相同的值。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

2D阵列的机制实际上比它们第一次出现时更容易,但它通常很难教。然而,快速解读事物确实需要很多经验,即使是经验丰富的开发人员有时也必须停下来思考片刻(或两点)。基本上,当你看到一个2D数组,如int a [5] [10](我将数组的大小改为5以简化事物),你需要不再把它当作2D。可以把它想象为1D。第一个下标指定此1D数组中的元素数,就像任何其他1D数组一样。当您索引数组时,例如[3],您将访问索引3处的对象。这与任何其他数组没有什么不同。让我们说“a”的定义是这样的:

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

订阅然后产生这个:

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

这很容易,而且大多数都可以。但是,如果你现在这样做:

// 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}};

你仍然有一个1D数组,你可以像上一个例子一样下标,产生以下内容(不是真正的语法,你应该怎么想):

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

这里唯一的区别是,与前一个示例相比,每个元素都是一个“int”,而不是每个元素都是一个数组(10个整数)。因此,当您看到它时,每个索引(0到4)返回该行的10个整数数组。例如,a [3]返回包含值155到200的10个整数的数组。元素本身是“int [10]”,因此您可以这样对待它。 IOW,你得到了相当于这个:

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

因此,例如,以b [7] = 190,a [3] [7] = 190的相同方式,因为a [3]实际上返回b的等价物(10的数组)整数),[7]下标然后抓住该数组的索引7处的元素,就像b [7]。而且,就像b是指向数组的第一个元素的指针一样(因为所有的数组名都衰变成指向数组的第一个元素的指针),在这种情况下是155,a [3]也做了一样。为什么?因为它正如所描述的那样返回b的等价物,就像b一样,它衰变成指向其第一个元素的指针。 IOW,就像这样:

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

这也是如此:

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

最后,就像FredOverflow提到的那样,这也是如此:

int (*p)[10] = a;

语法需要习惯,但它很有意义。由于每个数组名称都会衰减为指向其第一个元素的指针,因此“a”会衰减为指向其第一个元素的指针。这个元素是什么?那么,“a”的每个元素是10个整数的数组,即“int [10]”,所以“a”必须衰减成指向这些“int [10]”元素中的第一个的指针。上面的语法就是你如何声明这个指针。它将“p”定义为指向10个整数数组的指针。由于C ++优先级规则,(圆形)括号是必需的。如果你删除它们,你会得到这个:

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

将“p”声明为10个元素的数组,其中每个元素都是指向int的指针。它不是同一个IOW所以括号需要改变优先级(因此这个声明的含义)。使用前面显示的正确语法,“p”因此将指向第一个元素(包含元素5到50的“int [10]”数组),p + 1将指向第二个元素(“int [10] “包含元素55到100的数组”等。加分点:以下将做什么?

(*(p + 3))[5]

它返回180,因为(p + 3)返回指向“a [3]”的10个整数数组的指针,当使用*运算符取消引用时,在这个位置得到实际的“int [10]”数组。然后[5]下标在此数组中产生值180。

毫无疑问,要解决这个问题仍需要大量的练习,但我希望有所帮助。

答案 4 :(得分:0)

2D C数组不是指向指针的指针。 IT实际上是一个带有行*列元素的指针。

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

以上内容将为您提供所需信息。

虽然当你取消引用某个或某个ptr时,你会发现你得到一个“未定义的值”

如果你设置[4] [4]来说5

然后你会发现存储在

的值

ptr [(row * 10)+ column)将返回row = 4和column = 4的值。