为什么错位的 2D 数组的地址不是我所期望的?

Why are the addresses of malloced 2D array not what I expect?

提问人:hhh3 提问时间:2/14/2023 最后编辑:Vlad from Moscowhhh3 更新时间:2/14/2023 访问量:76

问:

为了在 C 中为 2D 数组分配内存,我运行

double (*t)[2] = malloc(sizeof(*t)*4);

我预计这将分配 64 个字节(两个双精度大小的 4 倍)。也就是说,我预计 t[0] 和 t[1] 各有 4 个双打的空间。出于这个原因,我认为 t[0] 和 t[1] 的地址应该分隔 32 个字节。但是,我发现它们之间有 16 个字节的隔音(仅对应于两个双精度)。

printf("Address of t[0]: %p\n", t[0]);  // Address of t[0]: 00C92490
printf("Address of t[1]: %p\n", t[1]);  // Address of t[1]: 00C924A0

我在这里错过了什么?

数组 C malloc 指针算术

评论

2赞 Support Ukraine 2/14/2023
每个由两个双打组成。因此,和之间以 16 个字节分隔也就不足为奇了(假设 a 是 8 个字节)。分配允许您访问 .就像会一样。如果你真的想要,你需要交换和t[n]t[0]t[1]doublet[0][0], t[0][1], t[1][0], t[1][1], t[2][0], t[2][1], t[3][0], t[3][1]double t[4][2]double t[2][4]24
0赞 Lundin 2/14/2023
什么点会变成 .但是,etc 对项目执行指针算术。如果您从那里编写并视为数组,可能会更容易理解代码。double (*t)[2]double [2]t[0]double [2]double (*t)[2] = malloc( sizeof(double[4][2]) );tdouble [4][2]

答:

3赞 Some programmer dude 2/14/2023 #1

这似乎是这里的声明和分配中的误解。声明为数组,其中数组中的每个元素都是由两个元素组成的数组。然后,为 中的四个元素分配足够的空间。ttdoublet

您的定义和分配等同于:

double t[4][2];

如果要创建包含两个元素的数组,其中每个元素都是一个动态分配的数组,则需要一个指针数组:

double *t[2] = { malloc(sizeof(*t[0]) * 4), NULL };

上面定义为一个由两个元素组成的数组,每个元素都是一个指向 的指针,你初始化第一个元素 () 以指向一个由四个元素组成的数组,将第二个元素 () 初始化为空指针。tdoublet[0]doublet[1]


重要的部分是两者之间的区别

double (*t)[2];`

double *t[2];

使用顺时针/螺旋规则,第一个定义为“指向两个数组的指针”。第二个定义为“指向 ” 的两个指针的数组。tdoubletdouble

1赞 Vlad from Moscow 2/14/2023 #2

我预计这将分配 64 个字节(两个双精度大小的 4 倍)

这是您的期望是正确的。但这是你的结论

也就是说,我预计 t[0] 和 t[1] 各有 4 个双打的空间。为 这个原因,

是错误的。

这条线

double (*t)[2] = malloc(sizeof(*t)*4);

相当于

double (*t)[2] = malloc( sizeof( double[4][2] ) );

因为表达式的类型是 。*tdouble[2]

所以并具有数组类型。 等于 。t[0]t[1]double[2]sizeof( double[2] )16

这是一个演示程序。

#include <stdio.h>
#include <stdlib.h>

int main( void )
{
    double( *t )[2] = malloc( sizeof( double[4][2] ) );

    printf( "sizeof( double[2] ) = %zu\n", sizeof( *t ) );
    printf( "Address of t[0]: %p\n", ( void * )t[0] );
    printf( "Address of t[1]: %p\n", ( void * )t[1] );
    printf( "(char * )t[0] + sizeof( double[2] ) = %p\n",
        ( void * )( ( char * )t[0] + sizeof( double[2] ) ) );
}

程序输出可能如下所示

sizeof( double[2] ) = 16
Address of t[0]: 00B971D8
Address of t[1]: 00B971E8
(char * )t[0] + sizeof( double[2] ) = 00B971E8
1赞 John Bode 2/14/2023 #3
double (*t)[2] = malloc( sizeof *t * 4 );

创建为 的 4x2 数组,而不是 2x4 数组。结果如下所示:tdouble

   +---+        +---+
t: |   | -----> |   | t[0][0]
   +---+        + - +
                |   | t[0][1]
                +---+
                |   | t[1][0]
                + - +
                |   | t[1][1]
                +---+
                |   | t[2][0]
                + - +
                |   | t[2][1]
                +---+
                |   | t[3][0]
                + - +
                |   | t[3][1]
                +---+

因此,为什么 和 的地址相距 16 (2 *) 字节。t[0]t[1]sizeof (double)

如果要动态分配 的 2x4 数组,则需要将double

double (*t)[4] = malloc( sizeof *t * 2 );

T (*p)[COLUMNS] = malloc( sizeof *p * ROWS );

您正在为 的实例分配足够的空间。ROWST [COLUMNS]