malloc for struct and pointer in C

前端 未结 8 1875
忘了有多久
忘了有多久 2020-12-04 04:57

Suppose I want to define a structure representing length of the vector and its values as:

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

Now,

相关标签:
8条回答
  • 2020-12-04 05:31

    The first time around, you allocate memory for Vector, which means the variables x,n.

    However x doesn't yet point to anything useful.

    So that is why second allocation is needed as well.

    0 讨论(0)
  • 2020-12-04 05:38

    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.

    Use -fsanitize=address flag to check how you used your program memory.

    0 讨论(0)
  • 2020-12-04 05:41

    No, you're not allocating memory for y->x twice.

    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.

    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.

    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).

    0 讨论(0)
  • 2020-12-04 05:42

    In principle you're doing it correct already. For what you want you do need two 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. malloc() returns a pointer to the allocated memory, so y must be a Vector pointer. In the second line you allocate memory for an array of 10 doubles.

    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.

    You can rearrange your struct and do a single malloc() like so:

    struct Vector{    
        int n;
        double x[];
    };
    struct Vector *y = malloc(sizeof *y + 10 * sizeof(double));
    
    0 讨论(0)
  • 2020-12-04 05:42

    First malloc allocates memory for struct, including memory for x (pointer to double). Second malloc allocates memory for double value wtich x points to.

    0 讨论(0)
  • 2020-12-04 05:45

    You could actually do this in a single malloc by allocating for the Vector and the array at the same time. 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).

    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.

    0 讨论(0)
提交回复
热议问题