简体   繁体   English

将变量永久设为指针而不是仅在 C 中需要时将其用作指针有什么好处?

[英]What are the benefits of making a variable permanently a pointer as opposed to only using it as a pointer when needed in C?

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* 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:此代码将 sprite 对象永久转换为指针:

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?人们为什么要这样做,这样做有什么好处?

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. 'a' 存在于堆栈中,因此它有一个您可以使用并获取地址等的名称。

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您可以引用动态分配的内存的唯一方法是通过指针

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.这就是createSprite函数正在做的事情。 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).它不能使用像你的int a或我的Sprite s1这样的静态变量名,因为根据定义,它们只能有一个固定的、静态的数字(即你在编写程序的那天选择的数字)。

For comparison, it may be instructive to look at three other ways the createSprite function could have been written, without using dynamic memory allocation.为了比较,看看createSprite函数的其他三种编写方式可能会有所启发,而无需使用动态内存分配。

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.这会创建一个Sprite类型的局部变量(不是指向Sprite的指针),但它根本不起作用。 That local variable disappears when createSprite2 returns, so the pointer to it is immediately invalid.createSprite2返回时,该局部变量消失了,因此指向它的指针立即无效。

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.这里我们将本地Sprint变量设置为static ,所以它不会在createSprite3返回时消失。 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.但这也不起作用,因为现在实际上只有一个Sprite对象,由所有调用过createSprite3的调用者共享,这几乎肯定不是想要的,也不会起作用。

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 .请注意,此createSprite4返回指针——它返回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.) (但从技术上讲,这里仍然没有动态分配的内存,正如我们从源代码中看到的那样,恰好分配了 1 或 10 个 Sprite。)

createSprite returns a pointer to self ; createSprite返回一个指向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;到函数执行结束时,分配给self的内存将无效; trying to access it through the returned pointer would most likely result in a segfault.尝试通过返回的指针访问它很可能会导致段错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM