直接寻址阵列存储器

时间:2014-12-29 19:45:41

标签: c arrays memory struct

我现在正试图学习如何以各种方式写入内存,即我正在玩。

我创建了一个结构如下:

struct strProjectile
{
    int Damage;
    int ParticlesPerSecond;
    short Fire;
    short Plasma;
};

然后我按如下方式创建了一个数组:

strProjectile Projectiles[40];

从那个数组中,我创建了一个指向数组开头的指针:

strProjectile *ptrProjectiles;
ptrProjectiles = Projectiles;

使用该指针,您可以像这样设置变量中的值(我知道这可以直接使用指针而不是使用。符号):

ptrProjectiles->Damage = 0;
ptrProjectiles->ParticlesPerSecond = 0;
ptrProjectiles->Fire = 0;
ptrProjectiles->Plasma = 0;

我还发现我可以通过创建指向数组每个结构中每个变量的指针来设置变量中的值。例如,以下内容将Damage设置为0:

int *Damage = (int *)ptrProjectiles;
*Damage = 0;

我的问题是我可以直接使用指向数组的指针来直接在内存中设置结构中的每个变量,因为我使用单独的指针进行上面的损坏吗?使用类似的东西:

*ptryProjectiles = 0;

然后跳过4个字节的内存来获取struct中的下一个变量(在本例中为ParticlesPerSecond),设置它,然后再跳过4个字节并设置下一个变量(在本例中为Fire),然后跳过接下来的2个字节并设置下一个变量(在本例中为Plasma),然后再跳过2个字节以获取数组中的下一个对象,然后重复....

我无法看到我需要这样做的原因,但只是想知道是否可以完成我的理解......

提前致谢!

5 个答案:

答案 0 :(得分:1)

通常,您可以直接通过数组寻址结构数组,如下所示:

strProjectiles [2] .Damage = 0;

如果你想要一个单独的元素:

Projectile * p= &strProjectiles[3];
p->Damage=0;
(*p).Fire=1;

答案 1 :(得分:0)

使用此声明,您假设int Damage;始终是第一个字段:

int *Damage = (int *)ptrProjectiles;

这很容易出现未来的错误,不应该使用。如果您只想在每个结构中设置int Damage;字段,请使用循环:

strProjectile Projectiles[MAX_PROJECTILES];
strProjectile *ptrProjectiles = Projectiles;

for(i = 0; i < MAX_PROJECTILES; i++)
    (ptrProjectiles + i)->Damage = 0;

<强>更新

虽然很危险,但可以计算每个结构的第一个字段的地址,如下所示:

int *pDamage = (int *)Projectiles;

for(i = 0; i < MAX_PROJECTILES; i++)
{
    *pDamage = 0;
    pDamage = (void *)pDamage + sizeof(Projectiles[0]);
}

答案 2 :(得分:0)

TLDR:是的,但你可能不应该。

您可以在C中完成此操作。您甚至可以接受字节流并将其强制转换为结构并立即填写所有数据成员。

对此的细微差别在于它不是可维护的代码,因此......可能不是一个好主意IRL。另一点需要注意的是,一旦您完成了这种类型的变量访问/设置,您就已经与您的数据结构结合了。您无法真正更改它,移动变量,添加其他数据成员或任何其他内容,而无需重新编写所有代码。

答案 3 :(得分:0)

好的,感谢您的提示和建议,但想出了我想做的事情......

首先,要在我需要使用的数组中的每个条目之间跳过:

ptrProjectiles = (strProjectile *)((char *)ptrProjectiles + sizeof(strProjectile));

基本上使它一次跳过12个字节。

假设正确填充结构的一致填充,则可以使用以下内容直接在内存中设置每个变量的值:

*(int *)ptrProjectiles = 0;
*(int *)((char *)ptrProjectiles + 4) = 0;
*(short *)((char *)ptrProjectiles + 8) = 0;
*(short *)((char *)ptrProjectiles + 10) = 0;

这就是我想要的。将所有这些组合在一起,然后我可以使用以下内容对数组中的每个条目进行0:

int lenProjectiles = sizeof(Projectiles);

for (int i = 0; i < lenProjectiles; i = i + sizeof(strProjectile))
{
    ptrProjectiles = (strProjectile *)((char *)ptrProjectiles + sizeof(strProjectile));
    *(int *)ptrProjectiles = 0;
    *(int *)((char *)ptrProjectiles + 4) = 0;
    *(short *)((char *)ptrProjectiles + 8) = 0;
    *(short *)((char *)ptrProjectiles + 10) = 0;
}

答案 4 :(得分:0)

你写的几乎所有内容都是正确的,但是,有一些重要的细节:

将结构指针转换为指向其第一个元素的指针是完全有效的代码,如行

int *Damage = (int *)ptrProjectiles;

这一事实在面向对象编程中得到了大量使用,其中struct(读取类)的第一个成员是包含基类子对象(另一个struct)的变量。这样,指向子类的指针可以直接转换为指向基类的指针,反之亦然。

但是,尝试以这种方式访问​​结构的第二个元素是无效的,i。即

int* ParticlesPerSecond = (int*)ptrProjectiles + 1;    //Wrong!

不保证产生与

相同的结果
int* ParticlesPerSecond = &ptrProjectiles->ParticlesPerSecond;    //Correct.

原因是对齐:编译器可以自由地在数组中禁止的结构元素之间添加填充。

对于其他两个成员,情况更糟:他们的类型与第一个成员不同,因此他们可能有不同的对齐要求。这使得他们的补偿非常难以预测。不过,您可以使用以下代码计算其偏移量:

size_t FireOffset = (size_t)&((struct strProjectile*)0)->Fire;
size_t PlasmaOffset = (size_t)&((struct strProjectile*)0)->Plasma;

这个技巧经常用于offsetof()宏(offsetof in wikipedia)的实现,这是获得偏移的更规范的方法:

#include <stddef.h>

size_t FireOffset = offsetof(struct strProjectile, Fire);
size_t PlasmaOffset = offsetof(struct strProjectile, Plasma);

有了这些知识,您可以自己生成正确的成员指针:

short* Fire = (short*)((char*)ptrProjectiles + FireOffset);
short* Plasma = (short*)((char*)ptrProjectiles + PlasmaOffset);

我希望我没有必要提到你不应该这样做,除非你有充分的理由这样做。学习目的几乎可以满足任何要求,但是......