在结构体内初始化动态数组

3

我正在尝试用C语言实现自己的矩阵乘法基本版本,根据另一个实现,我已经创建了一个矩阵数据类型。代码可以正常工作,但由于我是C的新手,我不明白为什么。

问题:我有一个结构体,里面有一个动态数组,我正在初始化它的指针。请参见下面:

// Matrix data type
typedef struct
{
    int rows, columns;      // Number of rows and columns in the matrix
    double *array;          // Matrix elements as a 1-D array
} matrix_t, *matrix;

// Create a new matrix with specified number of rows and columns
// The matrix itself is still empty, however
matrix new_matrix(int rows, int columns)
{
    matrix M = malloc(sizeof(matrix_t) + sizeof(double) * rows * columns);
    M->rows = rows;
    M->columns = columns;
    M->array = (double*)(M+1); // INITIALIZE POINTER
    return M;
}

为什么我需要将数组初始化为(double*)(M+1)?似乎(double*)(M+100)也可以正常工作,但是当我运行矩阵乘法函数时,(double *)(M+10000)就不能再工作了。

1
请不要在一个typedef中声明两种类型,不要在typedef中隐藏指针类型,不要使用带有_t的名称,它们被POSIX保留,请使用size_t来表示rowscolumns - Jens Gustedt
不,"_t"并不是为POSIX保留的。实际上,它没有被保留用于任何特定用途。尽管如此,在类型名称中应该只使用它。例如,"size_t"并不是POSIX。 - Jocke
3个回答

3
这种情况下推荐使用未指定大小的数组,与offsetof一起使用。这样可以确保正确的对齐方式。
#include <stddef.h>
#include <stdlib.h>

// Matrix data type
typedef struct s_matrix
{
    int rows, columns;      // Number of rows and columns in the matrix
    double array[];         // Matrix elements as a 1-D array
} matrix;

// Create a new matrix with specified number of rows and columns
// The matrix itself is still empty, however
matrix* new_matrix(int rows, int columns)
{
    size_t size = offsetof(matrix_t, array) + sizeof(double) * rows * columns;
    matrix* M = malloc(size);
    M->rows = rows;
    M->columns = columns;
    return M;
}

1
谢谢您,我同意Jens所指出的不要在typedef中隐藏指针类型的做法更为合理。然而,我认为您想要使用offsetof(matrix, array),因为matrix_t在您的代码中未定义... - Zni
什么是向数组添加数据的正确方法?我以前使用第一个版本代码时使用的方法不再起作用。无论我尝试什么,都只会得到“错误:无效使用灵活数组成员”的提示。 - Zni
哦,那个简单的东西似乎可以工作。然而,我在同时设置数组的所有值时遇到了问题。之前我写过 matrix* A = new_matrix(3, 2); double amatrix[] = { 3, 2, 8, 1, 9, 2 }; A->array = amatrix; 但现在不再起作用了。 - Zni
这段代码并没有填充数组,它用于更改指针(使得在结构体之后分配的所有内存都变得无用)。要复制数组的内容,请使用memcpy() - Medinoc

2

M+1指向紧随M内存之后的内存(即在两个int和一个double*之后)。这是您为矩阵数据分配的内存:

matrix M = malloc(sizeof(matrix_t) + sizeof(double) * rows * columns);
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

使用M+100M+10000,然后尝试填充矩阵将导致未定义行为。这可能会导致程序崩溃,或者程序看起来工作正常(但实际上是有问题的),或者介于两者之间。


0

你需要初始化它,否则(等着瞧)它就是未初始化的!

除了生成未定义的行为之外,您不能将未初始化的指针用于任何事情。

将其初始化为M + 1是完全正确的,也是非常好的代码。任何其他值都无法使用您为此目的分配的内存。

我的观点是,在结构体末尾的double *不会“自动”指向这个内存,这是您问题中暗示的信念,即为什么应该初始化它。因此,它必须设置为正确的地址。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接