C语言 返回结构指针

dddzy1tm  于 2023-08-03  发布在  其他
关注(0)|答案(7)|浏览(125)

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

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属性的属性?

ibrsph3r

ibrsph3r1#

我应该声明一个Mystruct变量,定义Mystruct的属性,给它赋值一个指针,然后返回指针吗
当然不是,因为函数中定义的变量(在“auto”存储类中)将在函数退出时消失,并且您将返回一个悬空指针。
你可以 * 接受 * 一个指向Mystruct的指针(调用者负责分配它)并填充它;或者,您可以使用malloc创建一个新的(调用者的责任是在完成后释放它)。第二个选项至少可以让你保留你似乎热衷的函数签名:

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

字符串
但它通常是一个较低的选项--因为调用者无论如何都必须承担责任,所以也可以使用第一个选项并潜在地获得性能(如果调用者可以使用自动类示例,因为它知道使用范围是有限的)。

5m1hhzi4

5m1hhzi42#

您不能使用该变量,因为当函数退出时,它将被释放。举例来说:

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

6kkfgxo0

6kkfgxo03#

如果您正在编写泛型代码,并且不知道如何使用它,那么最好提供两种选择:

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必须动态分配),而应该让应用程序编写者来决定。

2w3kk1z5

2w3kk1z54#

重要的是要记住,指针不是你分配给结构的东西,而是指针指示内存中你希望作为结构对待的位置。根据您的问题,您确实希望分配内存来保存数据结构。这给了你一个指向分配的内存位置的指针。一旦你有了它,你可以把它还回去。

编辑(编辑到原问题后)看你对问题的编辑,你肯定会有“我的”指针的问题。这是未初始化的,可以指向内存中的任何位置。当你试图复制结构到它,你可能会得到一个seg-fault。

inb24sb2

inb24sb25#

分配一个新的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()再次释放它。
仅仅声明一个局部变量并返回指向该局部变量的指针是行不通的。局部变量在函数结束时超出范围,存储它的内存很可能被重新用于其他目的。返回的指针仍将指向局部变量曾经所在的内存位置,但由于该变量不再存在,该指针将没有多大用处。

v6ylcynt

v6ylcynt6#

还有一种方法。

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

字符串

icnyk63a

icnyk63a7#

还有一个答案。假设你需要将给定的数据解析成新创建的结构,如果数据无效,你应该返回NULL(并且你有多个退出点)。为了避免在每个退出点之前都出现free,你可以这样做。

Mystruct* mystruct(void* data)
{
    Mystruct temp;
    temp.field = ...;
    // there may be several exit points if data is corrupted
    // so you can just return NULL
    if (wrong) return NULL;
    ...
    Mystruct *res = malloc(sizeof(Mystruct));
    *res = temp;
    return res;
}

字符串
如果你能负担得起你的结构的单一复制。

相关问题