代码之家  ›  专栏  ›  技术社区  ›  DCR

如何访问具有1个索引的c2d数组

  •  1
  • DCR  · 技术社区  · 1 年前

    我有以下内容:

    #include <stdio.h>
    
    int main() {
    
        int a[2][2] = { 0,1,2,3};
        printf("\n%d %d \n%d %d\n",a[0][0],a[0][1],a[1][0],a[1][1]);
        printf("%d %d %d %d\n",*a[0],*a[1],*a[2],*a[3]);
    
        return 0;
    }
    

    其返回:

    0 1 
    2 3
    0 2 0 1491303602
    

    有没有一种方法可以访问具有1个索引的2d数组?既然数组保存在连续内存中,难道我们不应该这样做吗?

    而且

    printf("\n%d %d \n%d %d\n",&a[0][0],&a[0][1],&a[1][0],&a[1][1]);
    printf("%d %d %d %d\n",a[0],a[1],a[2],a[3]);
    

    产生以下内容:

    1137924528 1137924532 
    1137924536 1137924540
    1137924528 1137924536 1137924544 1137924552
    

    那么为什么前两个元素的存储器地址&a[0][0]=a[0] 和&a[0][1]=a[1],但最后两个不匹配?

    3 回复  |  直到 1 年前
        1
  •  1
  •   Andreas Wenzel    1 年前

    在您的代码片段中

    #include <stdio.h>
    
    int main() {
    
        int a[2][2] = { 0,1,2,3};
        printf("\n%d %d \n%d %d\n",a[0][0],a[0][1],a[1][0],a[1][1]);
        printf("%d %d %d %d\n",*a[0],*a[1],*a[2],*a[3]);
    
        return 0;
    }
    

    线路

    printf("%d %d %d %d\n",*a[0],*a[1],*a[2],*a[3]);
    

    相当于:

    printf("%d %d %d %d\n",a[0][0],a[1][0],a[2][0],a[3][0]);
    

    这意味着您正在访问对象 a 越界,这会调用 undefined behavior .

    您可能想做的事情如下:

    #include <stdio.h>
    
    int main() {
    
        int a[2][2] = { {0,1}, {2,3} };
        int *p = &a[0][0];
        printf("%d %d \n%d %d\n",a[0][0], a[0][1], a[1][0],a[1][1]);
        printf("%d %d %d %d\n", p[0],p[1], p[2], p[3] );
    
        return 0;
    }
    

    另一种写法是这样的:

    #include <stdio.h>
    
    int main() {
    
        int a[2][2] = { {0,1}, {2,3} };
        printf( "%d %d \n%d %d\n", a[0][0], a[0][1], a[1][0], a[1][1] );
        printf( "%d %d %d %d\n", a[0][0], a[0][1],a[0][2], a[0][3] );
    
        return 0;
    }
    

    这些程序在我的编译器上有以下输出:

    0 1 
    2 3
    0 1 2 3
    

    尽管这可能适用于所有编译器,但值得注意的是,这样做可能会调用未定义的行为,这取决于您对标准的解释有多严格。这是因为您正在访问第一个子数组 a[0] 越界,但不是对象 作为一个整体。有关更多信息,请参阅以下问题:

    One-dimensional access to a multidimensional array: is it well-defined behaviour?

    编译器gcc和clang实际上都为第二个程序提供了运行时警告,如果我使用 -fsanitize=undefined 。如果我启用所有警告,编译器clang还会提供编译时警告。

    出于这些原因,如果您想将1D阵列用作2D阵列,那么最好声明1D阵列而不是2D阵列,并自己对1D阵列执行索引计算。这样,你就可以确保你所做的是ISO C标准允许的。以下是一个示例:

    #include <stdio.h>
    
    #define ROWS 2
    #define COLUMNS_PER_ROW 2
    
    int calculate_1D_offset( int row, int column )
    {
        return row * COLUMNS_PER_ROW + column;
    }
    
    int main( void )
    {
        int a[ROWS*COLUMNS_PER_ROW] = { 0, 1, 2, 3 };
    
        //find the value of a[1][0], as if "a" were a 2D array
        printf( "%d\n", a[calculate_1D_offset(1,0)] );
    }
    

    该程序具有以下输出:

    2
    

    那么为什么前两个元素的存储器地址&a[0][0]=a[0]并且&a[0][1]=a[1],但最后两个不匹配?

    数组 由2个子阵列组成,每个子阵列由2个 int 元素。所以的总数 int 元素为4。

    在您的问题中,地址如下:

    1137924528 是元素的地址 a[0][0] .
    1137924532 是元素的地址 a[0][1] .
    1137924536 是元素的地址 a[1][0] .
    1137924540 是元素的地址 a[1][1] .

    在你的问题中,行

    printf("%d %d %d %d\n",a[0],a[1],a[2],a[3]);
    

    具有以下输出:

    1137924528 1137924536 1137924544 1137924552
    

    最后两个地址越界,因为子数组 a[2] a[3] 不存在。只有 a[0] a[1] 存在

    如果 a[2] 确实存在,其地址为 1137924544 ,这将是5的地址 th int 2D阵列的元素,即。 a[0][4] (因为C中的索引是基于0的)。

    然而,我怀疑这些地址实际上是正确的,因为你用错了 printf 用于打印地址的格式说明符。为了打印地址,您应该使用 %p 而不是 %d d 用于 int ,而不是指针。在指针为64位和 int 是32位的,32 most significant bits 可能会被剥离价值,或者更糟。

        2
  •  1
  •   0___________    1 年前
    #include <stdio.h>
    
    int main(void) {
    
        int a[2][2] = { 0,1,2,3};
        printf("\n%d %d %d %d\n",a[0][0],a[0][1],a[1][0],a[1][1]);
        printf("%d %d %d %d\n",*a[0],*(a[0] + 1), *a[1], *(a[1] + 1));
    }
    

    https://godbolt.org/z/3avvnssn5

    后果

    0 1 2 3
    0 1 2 3
    
        3
  •  0
  •   Some programmer dude    1 年前

    让我们“绘制”您的阵列:

    +---------+---------+---------+---------+
    | a[0][0] | a[0][1] | a[1][0] | a[1][1] |
    +---------+---------+---------+---------+
    

    从中很容易看出一种模式正在出现,它告诉我们可以使用单个数组来表示所有两个“维度”:

    +---------+---------+---------+---------+
    | a[0]    | a[1]    | a[2]    | a[3]    |
    +---------+---------+---------+---------+
    

    现在我们所要做的就是想出一个公式来计算矩阵x,y对的一个数组索引。

    在第一个“行”中,我们通过简单地使用列索引来获得索引。对于第二个“行”,我们需要添加“列”的数量。

    所以一般的计算是 current_row * total_columns + current_column .

    我把它编码成这样:

    const int total_rows = 2;
    const int total_columns = 2;
    
    char a[total_rows * total_columns] = { 1, 2, 3, 4 };
    
    for (unsigned current_row = 0; current_row < total_rows; ++ total_rows)
    {
        for (unsigned current_column = 0; current_column < total_columns; ++ total_columns)
        {
            printf("matrix[%d][%d] = %d\n", current_row, current_column,
                   a[current_row * total_columns + current_column);
        }
    }