Suppose you will need several sprites in your program. You could do something like
Sprite s1;
initSprite(model, &s1, x, y);
Sprite s2;
initSprite(model, &s2, x, y);
Sprite s3;
initSprite(model, &s3, x, y);
And then later, if you needed a few more, you could do it the same way:
Sprite s4;
initSprite(model, &s4, x, y);
Sprite s5;
initSprite(model, &s5, x, y);
Sooner or later, though, this gets tedious and unworkable, so you want dynamic memory allocation. That's what the createSprite
function is doing. Key within it is that call
Sprite* self = malloc(sizeof(Sprite));
which dynamically allocates memory for one more sprite. That way, your program can have as many sprites in it as you want, quite likely a number that won't be known until runtime, once the user has started doing things. But dynamically allocated memory always ends up involving pointers. It can't use static variable names like your int a
or my Sprite s1
, because by definition, there can only ever be a fixed, static number of those (that is, the number you picked the day you wrote the program).
For comparison, it may be instructive to look at three other ways the createSprite
function could have been written, without using dynamic memory allocation.
Sprite* createSprite2(Sprite* model, int x, int y) {
Sprite self;
initSprite(model, &self, x, y);
return &self;
}
This creates a local variable of type Sprite
(not pointer-to-Sprite
), but it doesn't work, at all. That local variable disappears when createSprite2
returns, so the pointer to it is immediately invalid.
Sprite* createSprite3(Sprite* model, int x, int y) {
static Sprite self;
initSprite(model, &self, x, y);
return &self;
}
Here we make the local Sprint
variable static
, so it doesn't disappear when the createSprite3
returns. But this doesn't work, either, because now there's really only one Sprite
object, shared by all the callers who have ever called createSprite3
, which is almost certainly not what was wanted, and won't work.
But there's one more possibility, which actually would work:
Sprite createSprite4(Sprite* model, int x, int y) {
Sprite self;
initSprite(model, &self, x, y);
return self;
}
Notice that this createSprite4
does not return a pointer -- it returns an actual instance of Sprite
. So the caller might look like
Sprite s1 = createSprite4(model, x, y);
or
Sprite manysprites[10];
for(int i = 0; i < 10; i++)
manysprites[i] = createSprite4(model, x, y);
As I said, this could work fine, and is a bit of a counterargument to my assertion that "dynamically allocated memory always ends up involving pointers". (Technically, though, there's still no dynamically allocated memory here, as we can see from the source code that there are exactly 1, or 10, Sprites allocated.)