为什么索引没有越界,尽管直观上应该如此?

GiT*_*ato 1 c pointers sizeof multidimensional-array

我对 C 编程比较陌生,在运行以下代码并使用 gdb 和 lldb 对其进行调试时,我偶然发现了一个对我来说无法解释的行为。

简而言之:当交换索引 i 和 j (max i != max j) 时,在双重嵌套 for 循环内访问二维数组中的值时,如果使用array[i访问该值似乎并不重要][j] 或数组[j][i]

这两个循环和数组大部分是相同的。

 unsigned matrix[3][1] =
   {
       {3},
       {4},
       {5}
   };

   //Loop1
   for (size_t i = 0; i < sizeof(matrix) / sizeof(*matrix); i++)
   {
        for (size_t j = 0; j < sizeof(matrix[i]) / sizeof(*matrix[i]); j++)
        {
            matrix[i][j] <<= 1;
            printf("matrix[%zu][%zu]  has the value: %d\n", i, j, matrix[i][j]);
        }
   }

   //same two dimensional array as matrix
   unsigned matrix2[3][1] =
   {
       {3},
       {4},
       {5}
   };

   //Loop2, basically the same loop as Loop1
   for (size_t i = 0; i < sizeof(matrix2) / sizeof(*matrix2); i++)
   {
        for (size_t j = 0; j < sizeof(matrix2[i]) / sizeof(*matrix2[i]); j++)
        {
            //swapped i and j here
            matrix2[j][i] <<= 1;
            printf("matrix2[%zu][%zu]  has the value: %d\n", j, i, matrix2[j][i]);
        }
   }

Run Code Online (Sandbox Code Playgroud)

我在这里错过了什么吗?

在这两种情况下,i 在外循环结束时传递值 2,而 j 在内循环结束时传递值 0。

直观上,matrix[0][2] 应该抛出异常,因为每一行只有一个元素。

cha*_*eon 6

我将采取与其他受访者略有不同的方法。

从技术上讲,就内存布局而言,您并不是在数组边界之外进行读取。从人类的角度来看你是(索引[0][2]不存在!),但是数组的内存布局是连续的。矩阵的每一“行”彼此相邻存储。

在内存中,您的数组存储为: | ?| 3 | 4 | 5 | ?| 因此,当您索引matrix[1][0]matrix [0][1]访问内存中的同一位置时。如果数组的宽度大于 1 维,则情况并非如此。

例如,将您的阵列替换为以下阵列并进行实验。您可以通过索引matrix[0][2]或 来访问整数“4” matrix [1][0]。位置 [0][2]不应该存在,但它确实存在,因为内存是连续的。

unsigned matrix[3][2] =
   {
       {3, 6},
       {4, 8},
       {5, 10}
   };
Run Code Online (Sandbox Code Playgroud)

  • 是的,我同意你的看法。从技术上讲,这是一种未定义的行为,人们不应该习惯这种编程。其他答案涵盖了这部分。我采用这种方法向OP解释程序的行为,希望能够回答“为什么索引没有越界”的问题。**严格**来说,并没有超出数组边界。 (2认同)