简体   繁体   English

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

[英]malloc for struct and pointer in C

Suppose I want to define a structure representing length of the vector and its values as:假设我想定义一个表示向量长度及其值的结构:

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

Now, suppose I want to define a vector y and allocate memory for it.现在,假设我想定义一个向量 y 并为其分配内存。

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

My search over the internet show that I should allocate the memory for x separately.我在互联网上的搜索表明我应该单独为 x 分配内存。

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

But, it seems that I am allocating the memory for y->x twice, one while allocating memory for y and the other while allocating memory for y->x, and it seems a waste of memory.但是,似乎我为 y->x 分配了两次内存,一次为 y 分配内存,另一次为 y->x 分配内存,这似乎是浪费内存。 It is very much appreciated if let me know what compiler really do and what would be the right way to initialize both y, and y->x.如果让我知道编译器真正做了什么以及初始化 y 和 y->x 的正确方法是什么,我将不胜感激。

Thanks in advance.提前致谢。

No, you're not allocating memory for y->x twice.不,您不会y->x分配内存两次。

Instead, you're allocating memory for the structure (which includes a pointer) plus something for that pointer to point to.相反,你的结构分配内存(其中包括一个指针),加上一些为指针指向。

Think of it this way:可以这样想:

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

So you actually need the two allocations ( 1 and 2 ) to store everything.因此,您实际上需要两个分配( 12 )来存储所有内容。

Additionally, your type should be struct Vector *y since it's a pointer, and you should never cast the return value from malloc in C since it can hide certain problems you don't want hidden - C is perfectly capable of implicitly converting the void* return value to any other pointer.此外,你的类型应该是struct Vector *y因为它是一个指针,你不应该在 C 中转换malloc的返回值,因为它可以隐藏你不想隐藏的某些问题 - C 完全能够隐式转换void*将值返回给任何其他指针。

And, of course, you probably want to encapsulate the creation of these vectors to make management of them easier, such as with:而且,当然,您可能希望封装这些向量的创建,以便更轻松地管理它们,例如:

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);
    }
}

By encapsulating the creation like that, you ensure that vectors are either fully built or not built at all - there's no chance of them being half-built.通过像这样封装创建,您可以确保向量要么完全构建,要么根本没有构建——它们不可能是半构建的。 It also allows you to totally change the underlying data structures in future without affecting clients (for example, if you wanted to make them sparse arrays to trade off space for speed).它还允许您在未来完全更改底层数据结构而不会影响客户端(例如,如果您想让它们成为稀疏数组以换取速度空间)。

The first time around, you allocate memory for Vector , which means the variables x , n .第一次,您为Vector分配内存,这意味着变量xn

However x doesn't yet point to anything useful .但是x还没有指向任何有用的东西

So that is why second allocation is needed as well .这就是为什么还需要第二次分配的原因。

Few points几点

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

it should be struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));它应该是struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector)); since y holds pointer to struct Vector .因为y持有指向struct Vector指针。

1st malloc() only allocates memory enough to hold Vector structure (which is pointer to double + int)第一个malloc()只分配足够的内存来保存 Vector 结构(它是指向 double + int 的指针)

2nd malloc() actually allocate memory to hold 10 double.第二个malloc()实际上分配内存来容纳 10 个双精度。

In principle you're doing it correct already.原则上你已经做对了。 For what you want you do need two malloc() s.对于你想要的,你需要两个malloc() s。

Just some comments:只是一些评论:

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

should be应该

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

In the first line, you allocate memory for a Vector object.在第一行中,您为 Vector 对象分配内存。 malloc() returns a pointer to the allocated memory, so y must be a Vector pointer. malloc()返回一个指向分配内存的指针,所以 y 必须是一个 Vector 指针。 In the second line you allocate memory for an array of 10 doubles.在第二行中,您为 10 个双精度数组分配内存。

In C you don't need the explicit casts, and writing sizeof *y instead of sizeof(struct Vector) is better for type safety, and besides, it saves on typing.在 C 中,您不需要显式强制转换,并且编写sizeof *y而不是sizeof(struct Vector)更适合类型安全,此外,它可以节省打字时间。

You can rearrange your struct and do a single malloc() like so:您可以重新排列结构并执行单个malloc()如下所示:

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

You could actually do this in a single malloc by allocating for the Vector and the array at the same time.您实际上可以通过同时分配 Vector 和数组在单个 malloc 中执行此操作。 Eg:例如:

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

This allocates Vector 'y', then makes y->x point to the extra allocated data immediate after the Vector struct (but in the same memory block).这将分配 Vector 'y',然后使 y->x 指向 Vector 结构之后的额外分配数据(但在同一内存块中)。

If resizing the vector is required, you should do it with the two allocations as recommended.如果需要调整向量的大小,您应该按照建议使用两个分配来进行。 The internal y->x array would then be able to be resized while keeping the vector struct 'y' intact.然后可以调整内部 y->x 数组的大小,同时保持向量结构 'y' 完整。

When you allocate memory for struct Vector you just allocate memory for pointer x , ie for space, where its value, which contains address, will be placed.当您为struct Vector分配内存时,您只需为指针x分配内存,即用于空间,其中包含地址的值将被放置。 So such way you do not allocate memory for the block, on which yx will reference.因此,您不会为yx将引用的块分配内存。

First malloc allocates memory for struct, including memory for x (pointer to double).首先 malloc 为 struct 分配内存,包括为 x(指向 double 的指针)的内存。 Second malloc allocates memory for double value wtich x points to.第二个 malloc 为 x 指向的双精度值分配内存。

When you malloc(sizeof(struct_name)) it automatically allocates memory for the full size of the struct, you don't need to malloc each element inside.当您malloc(sizeof(struct_name))它会自动为结构的完整大小分配内存,您不需要 malloc 内部的每个元素。

Use -fsanitize=address flag to check how you used your program memory.使用-fsanitize=address标志来检查你如何使用你的程序内存。

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

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