【问题标题】:Can't understand this way of accessing 2-dimensional array in C无法理解这种在 C 中访问二维数组的方式
【发布时间】:2020-06-01 21:14:08
【问题描述】:

我遇到了这个 sn-p 代码,发现它设法打印 5 非常奇怪。我不明白为什么转换为 int* 设法使其基本上成为一个一维数组。谁能解释一下?

int main()
{
    int v[2][3] = {{1,2,3},{4,5,6}};
    int* c = (int*)v;
    printf("%d\n", c[4]);
}

【问题讨论】:

  • 这个程序有未定义的行为。 v 不是指向 int 的指针,并且与其中不兼容。该程序似乎可以做任何事情。
  • @n.'pronouns'm。具有不兼容的类型并不排除强制转换是有效的
  • @M.M 演员表本身是有效的,随后的取消引用是无效的。
  • @n.'pronouns'm。我同意超出前 3 个元素的访问存在问题,但我认为访问第一行是明确定义的。我们可以从转换规则中推断出转换的结果指向第一个 int 的相同内存位置,并且取消引用指向 int 的 int * 是明确定义的

标签: c arrays pointers multidimensional-array casting


【解决方案1】:

我们来谈谈数组下标的工作原理。

首先,请记住数组下标操作a[i] 定义为*(a + i) - 也就是说,给定地址a,偏移i 元素(不是字节!)地址并取消引用结果:

   +---+
a: |   |
   +---+
   |   |
   +---+
    ...
   +---+
   |   | <--- a + i
   +---+

这有两个原因:

除非它是sizeof_Alignof 或一元&amp; 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,表达式T 的 N 元素数组”类型的表达式将被转换(“衰减”)为“指向 T 的指针”类型的表达式,表达式的值将是数组第一个元素的地址。如果T 本身是一个数组类型(例如int [2][3],或“int 的 3 元素数组的 2 元素数组”),那么您最终会得到一个指向数组类型的指针(int (*)[3] , 或“指向int 的三元素数组的指针)。

指针算法考虑了指向类型的大小 - 如果pint * 并存储int 对象的地址,则p + 1 产生next 的地址int object,不是下一个字节。如果p 是一个指向int (int (*)[3]) 的三元素数组的指针并存储了一个数组的地址,那么p + 1 将产生@987654345 的下一个三元素数组的地址@。

图形化:

 int         int *            int [3]    int (*)[3] 
 +---+                        +---+            
 | 1 |  <--- p                | 1 | <--- p
 +---+                        + - +
 | 2 |  <--- p + 1            | 2 |  
 +---+                        + - +
 | 3 |                        | 3 |
 +---+                        +---+
 | 4 |                        | 4 | <--- p + 1
 +---+                        + - +
 | 5 |                        | 5 |
 +---+                        + - +
 | 6 |                        | 6 |
 +---+                        +---+

左图是带有int *指针的int对象序列,右图是带有int (*)[3]指针的int [3]对象序列。

所以发生的情况是,您获得了v 的第一个元素的地址,但您将其视为int *,而不是int (*)[3]

int* c = (int*)v;

你基本上是在拍右边的照片,然后假装是左边的照片。所以c[4]对应于序列中的第5个元素,在本例中为5

现在,此行为未定义 - int (*)[3]int * 不是兼容类型,并且无法保证以这种方式访问​​ v 的元素去工作。使用什么会更安全

int *c = &v[0][0]; // int * = int *

没有绕过不兼容类型的强制转换,并且您获得完全相同的效果。

【讨论】:

  • 与类型兼容性无关
猜你喜欢
  • 1970-01-01
  • 2012-08-22
  • 2016-12-03
  • 1970-01-01
  • 2013-06-29
  • 2021-10-11
  • 1970-01-01
  • 2015-03-05
  • 2013-06-27
相关资源
最近更新 更多