【问题标题】:Returning a struct pointer返回一个结构指针
【发布时间】:2011-02-11 18:35:41
【问题描述】:

假设我有以下结构和函数返回一个指针:

typedef struct {
  int num;
  void *nums;
  int size;
} Mystruct;

Mystruct *mystruct(int num, int size)
{ 
   //Is the following correct? Is there a more efficient way?
   Mystruct mystruct;
   mystruct.num = num;
   mystruct.size = size;
   mystruct.nums = malloc(num*sizeof(size));
   Mystruct *my;
   *my = mystruct;
   return my;
}

我想使用上述函数定义任何 Mystruct 指针。我应该声明一个 Mystruct 变量,定义 Mystruct 的属性,为其分配一个指针,然后返回指针还是立即通过指针定义 mystruct 属性的属性?

【问题讨论】:

  • 也许您可以编写这两个选项。从描述中,不清楚您的意图是什么。
  • 记住......永远不要将指针“从堆栈”向上传播。

标签: c pointers struct


【解决方案1】:

我应该声明一个 Mystruct 变量吗? 定义 Mystruct 的属性, 分配一个指向它的指针,并返回 指针

绝对不会,因为函数中定义的变量(在“auto”存储类中)将随着函数退出而消失,并且您将返回一个悬空指针。

您可以接受指向Mystruct 的指针(调用者有责任分配它)并填写它;或者,您可以使用malloc 创建一个新的(调用者有责任在完成后释放它)。第二个选项至少可以让您保留您似乎热衷的功能签名:

Mystruct *mystruct(int num, int size)
{
   Mystruct *p = malloc(sizeof(MyStruct));
   ....
   return p;
}

但它通常是次等的——因为调用者无论如何都必须承担责任,不妨选择第一个选项并有可能获得性能(如果调用者可以使用自动类实例,因为它知道使用范围有界)。

【讨论】:

  • 你为什么用 (Mystruct*) 对 malloc 进行类型转换?有必要吗?
  • @idealistikz:不,没必要。
  • 在 C 语言中没有必要(并且在该语言中通常被认为是不好的风格) - 但在 C++ 中反之亦然。
  • ... malloc(sizeof(MyStruct)); -- Mystruct 拼写错误?
  • @caf 使用 malloc 在 C++ 中被认为是不好的风格
【解决方案2】:

你不能使用这个变量,因为它会在函数退出时被释放。例如:

Mystruct *mystruct(int num, int size)
{
   MyStruct x;
   x.num = 1;
   ...
   return &x;
}

将给出分段错误或访问冲突,因为 x 的内存在您退出后立即被释放。所以你必须为结构分配内存(并确保稍后释放它)或声明一个将永远存在的全局。后者的例子...

Mystruct *mystruct(int num, int size)
{
   MyStruct *x;
   x = (MyStruct*)malloc( sizeof( MyStruct ) );
   x->num = 1;
   ...
   return x;
}

【讨论】:

  • 实际上return *x 不会在第一个函数中编译(我猜你的意思是return &x会给出你认为的更微妙的错误,或者更有可能更微妙错误)。
【解决方案3】:

如果您正在编写通用代码并且您不知道如何使用它,最好同时提供这两个选项:

int mystructm(Mystruct *storage, int num, int size)
{
    int rv = 0;

    storage->num = num;
    storage->size = size;
    storage->nums = malloc(num*sizeof(size));
    if (!storage->nums)
        return -1;

    return 0;
}

Mystruct *mystruct(int num, int size)
{
    Mystruct *mp = (Mystruct *)malloc(sizeof(Mystruct));
    if (mp)
    {
        if (mystructm(mp, num, size) == -1)
        {
            free(mp);
            mp = NULL;
        }
    }

    return mp;
}

这个想法是,作为库编写者,您不应该指定策略(例如必须动态分配每个 Mystruct),而应该让应用程序编写者来决定。

【讨论】:

    【解决方案4】:

    重要的是要记住,指针不是您分配给结构的东西,而是指针指示您希望将其视为结构的内存位置。根据您的问题,您真的想分配内存来保存数据结构。这为您提供了一个指向已分配内存位置的指针。拿到之后就可以退货了。


    编辑(编辑原始问题后) 查看您对问题的编辑,您肯定会遇到“我的”指针问题。这是未初始化的,可能指向内存中的任何位置。当您尝试将结构复制到其中时,您可能会遇到 seg-fault。

    【讨论】:

      【解决方案5】:

      分配一个新的Mystruct 并返回一个指向它的指针通常看起来或多或少像这样:

      Mystruct *mystruct(int num, int size)
      {
         Mystruct *result;
      
         result = malloc(sizeof(MyStruct));
         if (!result)
           return NULL;
      
         result->num = num;
         ...
      
         return result;
      }
      

      稍后,当您使用malloc 分配此处的Mystruct 完成后,应该使用free() 再次释放它。

      仅仅声明一个局部变量并返回一个指向该局部变量的指针是行不通的。局部变量在函数结束时超出范围,并且存储它的内存很可能被重用于其他目的。返回的指针仍将指向本地变量曾经所在的内存位置,但由于该变量不再存在,该指针将没有多大用处。

      【讨论】:

        【解决方案6】:

        另一种方法..

        int mystruct(Mystruct *mystruct, int num, int size){
           if(mystruct == NULL)
              return -1;
        
           mystruct->num = num;
           mystruct->size = size;
           ::
           return 0;
        }
        
        int main(){
           Mystruct my;
        
           if(mystruct(&my, 3, 4) != 0){
              fprintf(stderr, "Cannot init!\n");
              exit(0);
           }
           ::
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-08-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-13
          • 1970-01-01
          • 2014-12-30
          • 1970-01-01
          相关资源
          最近更新 更多