Home > Net >  What are the benefits of making a variable permanently a pointer as opposed to only using it as a po
What are the benefits of making a variable permanently a pointer as opposed to only using it as a po

Time:05-20

I was looking through code as reference to a project I am currently working on. I noticed that instead of having a variable and then only casting a pointer to it temporarily to pass it as a parameter, it was just set to always be a pointer type. (The line where it says Sprite* createSprite)

Sprite* createSprite(Sprite* model, int x, int y) {
  Sprite* self = malloc(sizeof(Sprite));
  initSprite(model, self, x, y);
  return self;
}

What I assume this is doing, is making the variable permanently a pointer.

Instead of only using the pointer when I would need it:

int a;

someFunction(&a); // We can still use a, and we can also pass it to someFunction as a pointer

This code is permanently casting the sprite object to a pointer:

int *a;

someFunction(a); // While we can still use a, it will never be a normal variable.

Why would people want to do this and what are the benefits of it?

CodePudding user response:

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

CodePudding user response:

In your first example

 int a;
 someFunction(&a);

'a' exists on the stack , so it has a name you can use and take the address or etc.

The sprite example

Sprite* createSprite(Sprite* model, int x, int y) {
  Sprite* self = malloc(sizeof(Sprite));
  initSprite(model, self, x, y);
  return self;
}

is almost certainly dynamically allocating its data on the heap. The only way you can refer to dynamically allocated memory is via a pointer

CodePudding user response:

createSprite returns a pointer to self; if it was like this (which is what I guess you expected to also work):

Sprite* createSprite(Sprite* model, int x, int y) {
  Sprite self;
  initSprite(model, &self, x, y);
  return &self;
}

the memory allocated to self would be invalid by the time the function execution ended; trying to access it through the returned pointer would most likely result in a segfault.

  • Related