如何使一个字段指向其结构?

时间:2016-01-28 10:04:07

标签: c pointers struct

总结我有两个结构,itemplayerplayer结构在其字段中包含两个item结构。
item结构有一个指向player结构的指针的字段,该指针必须指向拥有此项目的玩家。
当我初始化玩家时new_player() 1}}我想让项目指向在函数中创建的player
对我来说,它似乎不可能,因为项目将指向在堆栈上创建的结构,一旦返回结构,其项目成员指向释放的内存。我做了一些似乎证实这个理论的测试。

代码:

struct item
{
    int power;
    struct player* owner;
};
struct item new_item(int power, struct player* owner)
{
    struct item an_item;

    an_item.power = power;
    an_item.owner = owner;

    return an_item;
}

struct player
{
    int age;
    struct item item_1;
    struct item item_2;
};
struct player new_player(int age)
{
    struct player a_player;
    a_player.age = age;
    a_player.item_1 = new_item(1, &a_player);
    a_player.item_2 = new_item(2, &a_player);

    return a_player;
}

对此的解决方案可能是返回指向player new_player()的指针并将其分配到堆上:

struct player* new_player(int age)
{
    struct player* a_player = malloc(sizeof (struct player));
    a_player->age = age;
    a_player->item_1 = new_item(1, a_player);
    a_player->item_2 = new_item(2, a_player);

    return a_player;
}

试验:

int main()
{
    struct player* player_1 = new_player(77);

    printf("Age of the player: %d.\n", player_1->age);
    printf("Age of the player (from item_1): %d.\n", player_1->item_1.owner->age);
    printf("Age of the player (from item_2): %d.\n", player_1->item_2.owner->age);

    printf("Age of the player (from item_1 by owner): %d.\n",
            player_1->item_1.owner->item_1.owner->age);
    printf("Age of the player (from item_2 by owner): %d.\n",
            player_1->item_2.owner->item_2.owner->age);

    printf("Age of the player (from item_1 by owner to item_2): %d.\n",
            player_1->item_1.owner->item_2.owner->age);
    printf("Age of the player (from item_2 by owner to item_1): %d.\n",
            player_1->item_2.owner->item_1.owner->age);

    printf("Power of the first item: %d, power of the second item: %d.\n",
            player_1->item_1.power, player_1->item_2.power);
    printf("Power of the first item (from item_1): %d, power of the first item (from item_2): %d.\n",
            player_1->item_1.owner->item_1.power, player_1->item_2.owner->item_1.power);
    printf("Power of the second item (from item_1): %d, power of the second item (from item_2): %d.\n",
            player_1->item_1.owner->item_2.power, player_1->item_2.owner->item_2.power);

    free(player_1);

    return 0;
}

有些实验过的C程序员可以给我建议最好的方法是什么(或其他我想不到的方法)?

3 个答案:

答案 0 :(得分:3)

在你拥有的玩家结构中,这些项目是玩家的一部分。因此,当您在堆上分配播放器时,您只需将项目内的播放器指针设置为新创建的播放器即可。

你是对的,如果你在堆栈上创建玩家,这将不起作用,因为在返回后,玩家对象将被复制,包括指向项目的指针(然后指向"之前的& #34;播放器在堆栈中的位置。

另一种经常使用的解决方案是将播放器分配到new_player函数之外并将其作为指针传递:

void new_item(struct item *i, int power, struct player *p) {
    i->owner = p;
    i->power = power;
}

void new_player(struct player *p, int age) {
    p->age = age;
    new_item(&p->item_1, 1, p);
    new_item(&p->item_2, 2, p);
}

struct player p;
new_player(&p, 10);

这样,您可以将对象的分配与初始化分离。例如,你可以拥有一大堆玩家对象来容纳所有玩家并且只分配一次。然后通过将指针传递给数组中的对象来初始化播放器对象。

或者您可以堆积分配播放器并使用相同的功能初始化它。

答案 1 :(得分:1)

作为参考,专业的程序设计将涉及以下内容:

  • 为项目创建一个类,为玩家创建一个类。每个类都处理该类的一个对象的创建和删除。通常,您可以使用动态内存分配来执行此操作。
  • 通过实现opaque类型(私有封装)将结构的内容隐藏到调用者。所有对struct成员的访问都必须通过setter / getter函数来完成
  • 项构造函数将具有可选参数“owner”。如果项目没有所有者,则将其设置为NULL。
  • 在适用的情况下实施 const correctness 。例如,不应允许某个项目修改其所有者。
  • 罕见的“双向所有权”需要更多的前瞻声明。

你最终会得到这样的东西:

item.h

#ifndef ITEM_H
#define ITEM_H

#include "player.h"
#include <stdlib.h>

typedef struct item_t item_t;
typedef struct player_t player_t; // forward declaration needed to prevent linker errors

item_t* item_create (int power, const player_t* owner);

void item_delete (item_t* item);

#endif

item.c

#include "item.h"

struct item_t
{
  int power;
  const player_t* owner;
};


item_t* item_create (int power, const player_t* owner)
{
  item_t* new_item = malloc(sizeof(*new_item));

  if(new_item != NULL)
  {
    new_item->power = power;
    new_item->owner = owner;
  }

  return new_item;
}


void item_delete (item_t* item)
{
  free(item);
}

player.h

#ifndef PLAYER_H
#define PLAYER_H

#include "item.h"
#include <stdlib.h>

typedef struct player_t player_t;
typedef struct item_t item_t; // forward declaration needed to prevent linker errors

player_t* player_create (int age);

void player_delete (player_t* player);

#endif

player.c

#include "player.h"

struct player_t
{
  int age;
  struct item_t* item_1;
  struct item_t* item_2;
};


player_t* player_create (int age)
{
  player_t* new_player = malloc(sizeof(*new_player));

  if(new_player != NULL)
  {
    new_player->age = age;
    new_player->item_1 = item_create(1, new_player);
    new_player->item_2 = item_create(2, new_player);
  }

  return new_player;
}

void player_delete (player_t* player)
{
  item_delete(player->item_1);
  item_delete(player->item_2);
  free(player);
}

答案 2 :(得分:0)

将相同的原则应用于new_item()函数。它必须返回指向已分配结构的指针。

我想建议你提供另一个函数,它将负责释放所有这些指针。它可以是一个destroy_player(struct player *player),可以释放这两个项目和玩家本身。