101

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.

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

My search over the internet show that I should allocate the memory for x separately.

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

Thanks in advance.

Embedded_User
  • 211
  • 2
  • 11
Pouya
  • 1,793
  • 3
  • 19
  • 25
  • 7
    As pointed out eminently by paxdiablo, please don't cast the return value of `malloc()` in C. I'll never understand why everyone feels a need to do so. :( – unwind Feb 08 '13 at 08:37
  • 16
    @unwind, maybe they're old C++ programmers upgrading to C :-) – paxdiablo Feb 08 '13 at 08:55
  • @unwind When using Nvidia's nvcc compiler on C code, if I don't cast the result of malloc, it throws an error. – Nubcake Jul 12 '17 at 19:44
  • @Nubcake According to [this link](https://devtalk.nvidia.com/default/topic/508479/nvcc-forces-c-compilation-of-cu-files/) that might be because nvcc runs the underlying compiler in C++ mode, due to their CUDA interface being C++. In C, you will not get errors for this. In C++ `void *` does not automatically convert to other pointers, and the cast is needed (or, just don't use `malloc()` in C++, of course). – unwind Jul 15 '17 at 12:10
  • @unwind Yep, I later found about this :) Just wanted to state a situation where if you didn't cast the result then it would thrown an error. – Nubcake Jul 15 '17 at 14:36
  • @unwind but does `extern "C"` allow you to cast `void*` implicitly to something else while compiling with C++? – Tarick Welling Feb 14 '20 at 12:53
  • @TarickWelling No, I really don't think so. In C++ it's not allowed, but in C it is (and in my opinion this is a good thing in C, code with lots of casts is worse). – unwind Feb 17 '20 at 09:07

8 Answers8

182

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

paxdiablo
  • 814,905
  • 225
  • 1,535
  • 1,899
5

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.

Karthik T
  • 30,638
  • 5
  • 66
  • 86
4

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));
Wernsey
  • 5,362
  • 21
  • 38
  • "saves on typing" is never a valid argument for programming decisions. The real reason you would take *y is for safety reasons, ensuring that you allocate as much space as needed for the corresponding variable. – Lundin Feb 08 '13 at 09:19
  • @Lundin I've updated my answer, but to me the "type safety" argument is _almost_ in the same league as writing `if(NULL == foo)` – Wernsey Feb 08 '13 at 09:38
  • @Lundin Writing `sizeof *y` helps you fight errors like writing `sizeof(Vector)` when you meant `sizeof(Matrix)`. How often do you make mistakes like those? How quickly do you find and fix them when you do? I agree that it increases type safety, and I do write `sizeof *y` in my own code, but it is _almost_ as paranoid as writing `if(NULL == foo)` to prevent typos on the `==`. – Wernsey Feb 08 '13 at 12:57
  • @Wernsey, why is `struct Vector *y = malloc(sizeof *y);` the same as `struct Vector *y = malloc(sizeof(struct Vector));` Does `*y` dereference to the type Vector somehow? – Shmuel Kamensky Oct 12 '20 at 08:55
  • 1
    @ShmuelKamensky They are functionally equivalent. `y` is a pointer to `struct Vector` so `sizeof *y` is saying "size of what y points to", so `sizeof struct Vector`. – Wernsey Oct 13 '20 at 09:23
  • @Wernsey, wow it's simple when you say it like that. Thanks! – Shmuel Kamensky Oct 14 '20 at 09:01
3

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)); since y holds pointer to struct Vector.

1st malloc() only allocates memory enough to hold Vector structure (which is pointer to double + int)

2nd malloc() actually allocate memory to hold 10 double.

vinayawsm
  • 841
  • 9
  • 27
rajneesh
  • 1,689
  • 1
  • 13
  • 13
1

When you allocate memory for struct Vector you just allocate memory for pointer x, i.e. for space, where its value, which contains address, will be placed. So such way you do not allocate memory for the block, on which y.x will reference.

Andremoniy
  • 32,711
  • 17
  • 122
  • 230
1

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

oleg_g
  • 502
  • 3
  • 7
1

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.

PQuinn
  • 1,002
  • 6
  • 11
  • Why did you type cast y to char specifically? Why not (double*)y + sizeof(struct Vector)? – Vishnu Prasath Feb 24 '14 at 13:15
  • sizeof returns the struct size in bytes, and the pointer arithmetic '+' operator will add to the 'y' pointer is multiples of the sizeof(*y). If we did as you did above, y would be increased by sizeof(double)*sizeof(struct), which is too much. Casting y to char* lets us increment y by sizeof(char)*sizeof(struct) = 1*sizeof(struct) – PQuinn Feb 25 '14 at 08:16
  • Don't do this. It does not ensure that `y->x` is properly aligned to hold a `double`. If it's not, you have undefined behavior. – real-or-random Nov 09 '21 at 15:27
-1

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.

Emma
  • 26,487
  • 10
  • 35
  • 65
  • 1
    Wrong. x is just a pointer, you have to allocate memory for the value x points to. Read other answer to get more details. (ex: https://stackoverflow.com/a/14768280/5441253) – Maxime Ashurov Nov 20 '20 at 01:41