如何通过数组索引修改C结构体?



我正在制作的游戏中使用结构体,而结构体保存着关于人形的信息(位置,速度等)。我有一个结构体用于玩家,一个结构体用于僵尸。我将僵尸结构添加到数组中(并计划对其他敌人做同样的事情),以便在每帧循环中迭代它们,并将它们向前推进一步或解决游戏逻辑。(声明一下,这款游戏是在任天堂DS上运行的)。不幸的是,我似乎无法通过数组索引修改结构的值,因为值不会改变。直接修改结构可以工作,但是独立地更新每个结构将是一个巨大的痛苦(这就是循环遍历结构数组的原因)。下面是更深入的代码:

typedef struct{
int x;
float y;
float speed;
bool isSwordActive;
bool facingRight;
} humanoid;
void game(){
humanoid player = {12, 12, 0, false, false};
humanoid zombie = {226, 12, 0, false, false};
humanoid objects[1] = {zombie};
while(1){
// This works
zombie.y += zombie.speed;
zombie.speed += 0.125;
// This does not work
for(int i = 0; i < sizeof(objects)/sizeof(objects[0]); i++){
objects[i].y += objects[i].speed;
objects[i].speed += 0.125;
}
}
}

谁能解释一下为什么这不起作用,和一个可能的解决方案?谢谢你!

objects应该是指针数组。您正在数据复制到数组中,因此原始对象没有受到影响。

下面是重构的代码。注释:

#define bool int
#define false 0
#define true 1
typedef struct {
int x;
float y;
float speed;
bool isSwordActive;
bool facingRight;
} humanoid;
void
game()
{
humanoid player = { 12, 12, 0, false, false };
humanoid zombie = { 226, 12, 0, false, false };
// ORIGINAL
#if 0
humanoid objects[1] = { zombie };
// FIXED
#else
humanoid *objects[2] = { &zombie, &player };
#endif
// ORIGINAL
#if 0
while (1) {
// This works
zombie.y += zombie.speed;
zombie.speed += 0.125;
// This does not work
for (int i = 0; i < sizeof(objects) / sizeof(objects[0]); i++) {
objects[i].y += objects[i].speed;
objects[i].speed += 0.125;
}
}
#endif
// BETTER
#if 0
while (1) {
// This works
zombie.y += zombie.speed;
zombie.speed += 0.125;
// This does not work
for (int i = 0; i < sizeof(objects) / sizeof(objects[0]); i++) {
objects[i]->y += objects[i]->speed;
objects[i]->speed += 0.125;
}
}
#endif
// BEST
#if 1
while (1) {
// This works
zombie.y += zombie.speed;
zombie.speed += 0.125;
// This does not work
for (int i = 0; i < sizeof(objects) / sizeof(objects[0]); i++) {
humanoid *obj = objects[i];
obj->y += obj->speed;
obj->speed += 0.125;
}
}
#endif
}

在上面的代码中,我使用了cpp条件来表示旧代码和新代码:

#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif

这个工作,谢谢!指针总是捉弄我。如果你不介意,你能解释一下为什么最好的解决方案比更好的解决方案好吗?它是性能明智的吗?如果有太多对象并为每个对象创建新变量,性能不会降低一点吗?谢谢你!- - - - - -JuanR4140

我们不是创建/复制数组元素的内容(例如20字节)。我们只是计算数组元素的地址。无论如何都必须这样做,所以没有额外的代码。

这是一个根本的区别,我认为这仍然是你困惑的地方。

如果编译时没有对进行优化,则"更好";溶液会重新评估objects[i]3次。才能"使用"。object[i],那里的值必须取出并放入CPU寄存器中。也就是说,它会这样做:

regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something

同样,重复3次:

regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something
regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something
regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something
如果我们用优化编译,生成的代码将类似于"BEST"解决方案。也就是说,编译器意识到objects[i]在给定的循环迭代中是不变量,因此它只需要计算一次:
regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something
regA->something
regA->something

注意编译器必须总是将计算出的地址值放入寄存器中才能使用它。编译器会假设obj应该在寄存器中。所以,没有生成额外的代码。

在"best"版本,我告诉过你。编译器如何生成高效的代码。并且,它将生成高效的代码,而不需要优化。

并且,在几个不同的地方执行obj->something更容易阅读["humanoid"]程序员;-)]比objects[i]->something在多个地方。

如果是2D数组,它的值会更明显。

最新更新