【问题标题】:Is it possible to return a pointer to a struct without using malloc?是否可以在不使用 malloc 的情况下返回指向结构的指针?
【发布时间】:2013-06-26 09:57:52
【问题描述】:

我正在使用 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;
};

【问题讨论】:

  • 你的问题是关于如何创建一个对象,而不是如何返回一个指针。

标签: c pointers struct malloc


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 我尝试了其他一些答案,但似乎没有一个适用于 GBDK。我对您关于全球池的第三个建议感兴趣。你有什么资源可以指点我吗?
  • 如果您尝试过它们并且它们“不起作用”,我认为这并不意味着您应该尝试其他方法。这可能意味着您应该阅读更多关于 C 的内容,并了解您做错了什么(或提出一些具体问题)。每当您的代码没有按照您的意愿行事时尝试一种全新的方法并不是一种高效或可靠的编码方式。
  • 谢谢,我知道了。欢迎阅读建议 :) 我仍在学习,但由于 GBDK 使用旧版本的 C,因此无法返回结构。此外,malloc 无法正常工作也是一个已知问题。我会再复习一遍所有的答案。
【解决方案2】:

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

我。 从技术上讲,是的。您可以使您的结构 static 使其在函数调用中继续存在:

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

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

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

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

三。或者返回结构本身,它没有伤害,是吗(它甚至可以被移动优化):

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

所以,选择你的毒药。

【讨论】:

    【解决方案3】:

    只需执行以下操作:

    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;
    }
    

    结构需要在别处“分配”(可能在堆栈上是您最好的选择)。

    【讨论】:

      【解决方案4】:

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

      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' };
      

      【讨论】:

        【解决方案5】:

        请注意,在这种情况下(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;
        }
        

        【讨论】:

          【解决方案6】:

          如果无法修复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;
          };
          

          然后,不要对makepoint() 返回的结果调用free(),而是应该创建一个新函数将其放在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;
              }
          }
          

          【讨论】:

            【解决方案7】:

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

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

            那么你可以这样称呼它:

            struct point foo = makepoint(10, 20);
            

            再简单不过了!

            【讨论】:

              猜你喜欢
              • 2015-06-28
              • 1970-01-01
              • 1970-01-01
              • 2017-03-10
              • 2018-12-03
              • 1970-01-01
              • 2014-12-30
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多