3

I'm working my way through the learn c the hard way book and have run into a few issues on Exercise 19. The author said that ex19 was intended for the learners to get to know the macro in c. I have no problem in understanding the concept of that, but I just don't understand everything else. I can't understand how the object prototype is created.

Especilly,what does the following sentense mean?

Since C puts the Room.proto field first, that means the el pointer is really only pointing at enough of the block of memory to see a full Object struct. It has no idea that it's even called proto.

the relevant code is this:

// this seems weird, but we can make a struct of one size,
// then point a different pointer at it to "cast" it
Object *el = calloc(1, size);
*el = proto;
  1. can anyone tell me how on earth malloc/calloc exactly works? As far as i know, it just allocate the required number of memory and return the first address. If so, how can the computer know the data struct of the allocated memory? like in the code, after Room *arena = NEW(Room, "The arena, with the minotaur");,you can do this directly arena->bad_guy = NEW(Monster, "The evil minotaur"); how does the computer know there is a bad_guy??
  2. what on earth is the content of *el after the above two statements(Object *el = calloc(1, size); and *el = proto;)?

Any help will be appreciated!!

the link to the exercise: http://c.learncodethehardway.org/book/ex19.html

bmargulies
  • 97,814
  • 39
  • 186
  • 310
linuxfish
  • 89
  • 1
  • 8

2 Answers2

4

calloc has the additional feature that it fills the allocated memory with zero bytes, whereas using the equivalent malloc call would require an additional step if all or some of the allocation needs to be zero initially.

In the code

arena->bad_guy = NEW(Monster, "The evil minotaur"); 

the compiler knows the layout of the struct because the access is through the arena variable, which is declared as a pointer to Room, which is presumably a typedef of a struct.

For the other part, the guarantee of ordering within structs allows a limited form of inheritance in composite structs, or extended structs.

struct A {
    int x;
};

struct B {
    int foo;
    double baloney;
};

struct B (or a pointer to it) can be cast to a (pointer to a) struct A because they both begin with an int. Of course, if you cast the other way, the struct A must have been originally a struct B or access to the baloney field will be undefined. In other words, struct B essentially begins with a struct A.

This may be easier to see if I rewrite my example like this:

struct A {
    int x;
};

struct B {
    struct A foo;
    double baloney;
};

Now you can get a struct A out of struct B in different ways.

struct A a;
struct B b;

a = b.foo;  // regular member variable access

struct A *ap = &a;
struct B *bp = &b;

ap = (struct A *)bp;  // cast the pointer

ap = & b.foo;         // take a pointer from the member variable
ap = & bp->foo;       // take a pointer from the member variable via a pointer
luser droog
  • 18,988
  • 3
  • 53
  • 105
  • Thanks! I understand a little bit... but I just want to know what `Object *el = calloc(1, size);`means when the normal way of doing that is `Object *el = calloc(1, sizeof(Object));`,and what happened in the memory after you do this `*el = proto;` since what el is pointing is larger than what proto needs. – linuxfish Apr 01 '14 at 11:31
  • Since `calloc` fills the memory with zero bytes, the result in memory will be the value of proto followed by zero bytes up to `size`. In my example, `struct A` is a proper subset of `struct B` so a `struct B` can always be used as if it were a `struct A`. They contain the same prefix, an `int`. Essentially, `struct B` *contains* a `struct A` at the beginning, even though the member variables have different names. – luser droog Apr 01 '14 at 11:36
  • Many thanks to the quick answer! I think I got this, really thanks! – linuxfish Apr 01 '14 at 11:40
0

All it does is to alloc 1*size bytes. There's nothing magic with malloc/calloc. He is passing the sizeof(T) to the function through that NEW macro and putting it in Object_new's size parameter. So all the function knows is the size in bytes.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • The type of the memory "malloc"ed is implied by the type of pointer you assign the returned value to. The size of the malloc is stored somewhere by the "malloc" routine (typically in the memory before the returned address) this is how "free" magically knows how much memory to return when it is called. – AnthonyLambert Apr 01 '14 at 10:16