繁体   English   中英

C语言中结构体和指针的malloc

[英]malloc for struct and pointer in C

假设我想定义一个表示向量长度及其值的结构:

struct Vector{
    double* x;
    int n;
};

现在,假设我想定义一个向量 y 并为其分配内存。

struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));

我在互联网上的搜索表明我应该单独为 x 分配内存。

y->x = (double*)malloc(10*sizeof(double));

但是,似乎我为 y->x 分配了两次内存,一次为 y 分配内存,另一次为 y->x 分配内存,这似乎是浪费内存。 如果让我知道编译器真正做了什么以及初始化 y 和 y->x 的正确方法是什么,我将不胜感激。

提前致谢。

不,您不会y->x分配内存两次。

相反,你的结构分配内存(其中包括一个指针),加上一些为指针指向。

可以这样想:

         1          2
        +-----+    +------+
y------>|  x------>|  *x  |
        |  n  |    +------+
        +-----+

因此,您实际上需要两个分配( 12 )来存储所有内容。

此外,你的类型应该是struct Vector *y因为它是一个指针,你不应该在 C 中转换malloc的返回值,因为它可以隐藏你不想隐藏的某些问题 - C 完全能够隐式转换void*将值返回给任何其他指针。

而且,当然,您可能希望封装这些向量的创建,以便更轻松地管理它们,例如:

struct Vector {
    double *data;    // no place for x and n in readable code :-)
    size_t size;
};

struct Vector *newVector (size_t sz) {
    // Try to allocate vector structure.

    struct Vector *retVal = malloc (sizeof (struct Vector));
    if (retVal == NULL)
        return NULL;

    // Try to allocate vector data, free structure if fail.

    retVal->data = malloc (sz * sizeof (double));
    if (retVal->data == NULL) {
        free (retVal);
        return NULL;
    }

    // Set size and return.

    retVal->size = sz;
    return retVal;
}

void delVector (struct Vector *vector) {
    // Can safely assume vector is NULL or fully built.

    if (vector != NULL) {
        free (vector->data);
        free (vector);
    }
}

通过像这样封装创建,您可以确保向量要么完全构建,要么根本没有构建——它们不可能是半构建的。 它还允许您在未来完全更改底层数据结构而不会影响客户端(例如,如果您想让它们成为稀疏数组以换取速度空间)。

第一次,您为Vector分配内存,这意味着变量xn

但是x还没有指向任何有用的东西

这就是为什么还需要第二次分配的原因。

几点

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector)); 是错的

它应该是struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector)); 因为y持有指向struct Vector指针。

第一个malloc()只分配足够的内存来保存 Vector 结构(它是指向 double + int 的指针)

第二个malloc()实际上分配内存来容纳 10 个双精度。

原则上你已经做对了。 对于你想要的,你需要两个malloc() s。

只是一些评论:

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));
y->x = (double*)malloc(10*sizeof(double));

应该

struct Vector *y = malloc(sizeof *y); /* Note the pointer */
y->x = calloc(10, sizeof *y->x);

在第一行中,您为 Vector 对象分配内存。 malloc()返回一个指向分配内存的指针,所以 y 必须是一个 Vector 指针。 在第二行中,您为 10 个双精度数组分配内存。

在 C 中,您不需要显式强制转换,并且编写sizeof *y而不是sizeof(struct Vector)更适合类型安全,此外,它可以节省打字时间。

您可以重新排列结构并执行单个malloc()如下所示:

struct Vector{    
    int n;
    double x[];
};
struct Vector *y = malloc(sizeof *y + 10 * sizeof(double));

您实际上可以通过同时分配 Vector 和数组在单个 malloc 中执行此操作。 例如:

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector) + 10*sizeof(double));
y->x = (double*)((char*)y + sizeof(struct Vector));
y->n = 10;

这将分配 Vector 'y',然后使 y->x 指向 Vector 结构之后的额外分配数据(但在同一内存块中)。

如果需要调整向量的大小,您应该按照建议使用两个分配来进行。 然后可以调整内部 y->x 数组的大小,同时保持向量结构 'y' 完整。

当您为struct Vector分配内存时,您只需为指针x分配内存,即用于空间,其中包含地址的值将被放置。 因此,您不会为yx将引用的块分配内存。

首先 malloc 为 struct 分配内存,包括为 x(指向 double 的指针)的内存。 第二个 malloc 为 x 指向的双精度值分配内存。

当您malloc(sizeof(struct_name))它会自动为结构的完整大小分配内存,您不需要 malloc 内部的每个元素。

使用-fsanitize=address标志来检查你如何使用你的程序内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM