7

我正在使用 GBDK 编写一个 Gameboy ROM,它有一个不稳定的 malloc 版本,我无法开始工作。我也无法在结构中返回结构。这让我试图返回一个指针,这就是为什么我想知道是否有办法在返回结构指针时避免使用 malloc?

我基本上想做的是我希望能够写出这样的东西:

create_struct(struct_name, char member_x, char member_y);

这是我使用 malloc 编写的代码:

 struct point {
    char member_x;
    char member_y;
};


struct point *makepoint(char member_x, char member_y) {
    struct point *temp = malloc(sizeof(struct point));

    temp->member_x = member_x;
    temp->member_y = member_y;

    return temp;
};
4

7 回答 7

6

有多种有效的方法可以返回指针(指向结构或任何类型的对象),但返回指向在调用函数之前不存在的新对象malloc的指针的唯一方法是使用, realloc, calloc, aligned_alloc( C11),或一些实现定义的分配函数(例如mmap在 POSIX 系统上等)。

您可以返回有效指针的其他方法包括:

  1. 指向具有static存储持续时间的对象的指针。这种对象的实例只存在一次,因此这通常是一种不好的方法。

  2. 作为参数传递给函数的指针,用作存储结果的位置。这通常是一个好方法,因为您将获取存储的责任转嫁给了调用者。

  3. 指向从某种全局池中获得的对象的指针。这在嵌入式系统和低端游戏设备的游戏设计中可能是一个非常好的方法。

于 2013-06-28T16:09:37.100 回答
3

是否可以在不使用 malloc 的情况下返回指向结构的指针?

I.从技术上讲,是的。你可以让你的结构体static在函数调用中存活下来:

struct foo *bar()
{
    static struct foo f = { 1, 2, 3 };
    return &f;
}

但我怀疑你真的想这样做(因为这有有趣的副作用,请阅读static关键字的含义)。您有几种不同的可能性:

二、C 标准库采用的方法总是让调用者隐式地负责提供结构和管理内存。因此,该函数不是返回一个指针,而是接受一个指向 struct 的指针并填充它:

void dostuff(struct foo *f)
{
    foo->quirk = 42;
}

三、或者返回结构本身,它不会伤害它(它甚至可以被移动优化):

struct foo bar()
{
    struct foo f = { 1, 2, 3 };
    return f;
}

所以,选择你的毒药。

于 2013-06-28T15:51:36.730 回答
0

如果无法malloc()修复,那么您可能只想管理自己预先分配的点数,并限制可以“创建”的点数。您需要稍微改变您的观点以便于管理:

union free_point {
    union free_point *next;
    struct point data;
};

union free_point free_point_pool[MAX_POINTS];
union free_point *free_point_list;

struct point *makepoint(char member_x, char member_y) {
    static int i;
    union free_point *temp;

    temp = 0;
    if (i == MAX_POINTS) {
        if (free_point_list) {
            temp = free_point_list;
            free_point_list = temp->next;
        }
    } else {
        temp = free_point_pool + i++;
    }

    if (temp) {
        temp->data.x = x;
        temp->data.y = y;
    }

    return &temp->data;
};

然后,您应该创建一个新函数free()makepoint()其放在free_point_list.

void unmakepoint (struct point *p) {
    union free_point *fp = (union free_point *)p;
    if (fp) {
        fp->next = free_point_list;
        free_point_list = fp;
    }
}
于 2013-06-28T16:09:28.477 回答
0

请注意,在这种情况下(struct point仅占用 2 个字节)您可以返回struct point而不是struct point *,(这不应该在大型结构中完成)

#include <stdio.h>

struct point {
    char member_x;
    char member_y;
};

struct point makepoint(char member_x, char member_y)
{
    struct point temp;

    temp.member_x = member_x;
    temp.member_y = member_y;
    return temp;
}

int main(void)
{
    struct point t = makepoint('a', 'b');

    printf("%c %c\n", t.member_x, t.member_y);
    return 0;
}
于 2013-06-28T15:43:47.100 回答
0

只需执行以下操作:

void makepoint(struct point *dest, char member_x, char member_y) {
     dest->member_x = member_x; // you had these wrong in your code, by the way
     dest->member_y = member_y;
}

该结构需要在其他地方“分配”(可能在堆栈上是您最好的选择)。

于 2013-06-28T15:10:50.627 回答
0

您可以将结构作为参数传递并让函数对其进行初始化:

struct point *makepoint(struct point *pt, char x, char y) {
    pt->x = x;
    pt->y = y;
    return pt;
}

然后这样称呼它:

struct point pt;
makepoint(&pt, 'a', 'b');

但是你也可以这样做:

struct point pt = { 'a', 'b' };
于 2013-06-28T15:11:16.023 回答
0

最简单的事情就是返回一个使用命名初始化器创建的结构,并在一个内联函数中这样做,这样就可以实现零开销:

static inline struct point makepoint(char x, char y) {
  return (struct point) { .x = x, .y = y };
}

然后你可以这样称呼它:

struct point foo = makepoint(10, 20);

再简单不过了!

于 2015-08-21T07:46:08.377 回答