Reputation: 383
I allocated memory with malloc
to pointer to struct
but I allocated nothing to actual struct. However I can access/use the struct
.
typedef struct A
{
int w;
int x;
int y;
int z;
}A;
int main(void)
{
A* a = malloc(sizeof(A*)); //Here I allocate memory just to pointer to A
//Why can I do this than?:
a->z = 10;
a->w = 456;
return 0;
}
Why does this work? Is it just coincidence or is it always supposed to work this way? Some notes:
I couldn't do that with non-dynamic allocation
Tested in repl.it
Upvotes: 0
Views: 75
Reputation: 18503
Indeed it will depend on the actual CPU architecture and the operating system to say if this will work or not:
The first question is: What is sizeof(A)
and what is sizeof(A *)
?
I don't know any CPU where the inequality sizeof(A) <= sizeof(A *)
is true but CPUs (or computers with external memory circuits) where this is the case are at least possible.
In this case your code will work fine because there is enough memory allocated by malloc
to hold the structure A
.
If this condition is not given it depends on the actual implementation of malloc
. Many implementations will round up the argument of malloc
so malloc(5)
will actually allocate 16 bytes, not 5 bytes.
If malloc
will allocate as many as or more than sizeof(A)
bytes everything is fine.
If malloc
allocates less than sizeof(A)
bytes it depends on the question if the memory after the memory allocated is used or not and if it is present or not:
If the memory after the memory allocated is not present (e.g. not mapped when using an MMU) you'll get an error depending on the system - on most modern computers there will be an "exception" and your program will crash.
If the memory after that memory is occupied by some other data you'll overwrite that data which will probably lead to errors.
If the memory after that memory is present but not used your program will work fine.
Upvotes: 1
Reputation: 13580
The malloc
call allocates the requested number of bytes and returns a pointer
to the start of the allocated memory block.
A* a = malloc(sizeof(A*));
Here you are requesting sizeof(A*)
bytes, but the amount of bytes you are
requesting are for a pointer to A
. You need however the amount of bytes for a
A
object, which may not be the same. This seems like a minor difference but it
is a huge one. What you should have done is this:
A *a = malloc(sizeof(A));
or even better
A *a = malloc(sizeof *a);
The second one is better, because you cannot do mistakes, it will always pass to
malloc the correct amount of bytes. When using sizeof(<type>)
is easy to make
mistakes and add *
when it's not needed, like you did with sizeof(A*)
.
I couldn't do that with non-dynamic allocation
Well, you can. For a simple structure you can initialize it without requesting memory from the
heap (through malloc
):
A a;
a.z = 10;
a.w = 456;
or
A a = { .z = 10, .w = 456 };
would do the same.
The reason why we usually choose to use malloc
for structs, is that structs
may be very large and may need many bytes of memory. The amount of space you have in
the stack frame of the function for variables is very small in comparison with
the memory you have in the heap section. So it's better to request memory from
the heap using malloc
. Also it allows you to pass that pointer to other
functions, even after the function that requested the memory ended.
You've forgotten two things though:
malloc
, it may be NULL
.Free the memory at the end. When you don't need the memory:
free(a);
Upvotes: 2
Reputation: 223927
When you do this:
A* a = malloc(sizeof(A*));
You don't allocate enough memory for an instance of A
. So if you read / write any member that happens to sit beyond the bounds of what was actually allocated, you invoke undefined behavior.
With undefined behavior, you can't accurately predict your program's output. It may crash, it may output strange results, or (in your case) it may appear to work properly. How undefined behavior manifests can change by making a seemingly unrelated modification such as an extra local variable, a call to printf
for debugging, or by recompiling with different options.
Just because a program could crash doesn't mean it will.
If you use a tool such as valgrind, it can capture when you use memory incorrectly such as in your example.
Upvotes: 2
Reputation: 50190
nobody said what you should actually do. Do this:
int main(void)
{
A* a = malloc(sizeof(A)); // Here I allocate an ins6tance of A and set a pointer to it
a->z = 10;
a->w = 456;
return 0;
}
Upvotes: 0