【问题标题】:Dynamically allocating memory for a variable inside a struct as int,double etc为结构内的变量动态分配内存,如 int、double 等
【发布时间】:2020-11-18 14:16:17
【问题描述】:

我有一个结构

struct myStruct {
int message;
void*packet;
};

像这样在运行时从函数中动态分配内存可以吗

struct myStruct* create(int type, int length)
{
if(type==1)
myStruct->packet = (int *)malloc(length * sizeof(int));
if(type==2)
myStruct->packet = (double *)malloc(length * sizeof(double));

}

以便我的数据包可以配置为 double 和 int?

【问题讨论】:

  • 最好使用包含两种指针类型的union。生成的代码会更清晰,并且会使用相同数量的内存。
  • 您还需要了解packet 是指向int 数组还是double 数组。

标签: c linux struct


【解决方案1】:

按照 cmets 中的建议,您可以使用 union 解决此问题。

typedef enum {INT_ARR, DOUBLE_ARR} myType;
struct myStruct {
    myType type;
    union {
        int *iArr;
        double *dArr;
    } value;
}

使用 union 的好处是 iArr 指针和 dArr 指针占用相同的内存。您应该访问哪个字段由type 字段决定。

您提供的create 函数似乎不完整,因为它从不为结构分配内存或返回任何内容。如果你选择使用联合方案,你可以这样写:

struct myStruct *create(myType type, int length) {

    // Allocate struct
    struct myStruct *res = malloc(sizeof(struct myStruct));
    res->type = type;

    if(type == INT_ARR)
        res->iArr = malloc(length * sizeof(int));
    else if(type == DOUBLE_ARR)
        res->dArr = malloc(length * sizeof(double));

    return res;
    
}

注意,一旦你完成了结构,你应该free()这个create函数返回的结果。

【讨论】:

    【解决方案2】:

    在您的示例中存在错误:未分配结构,create 函数未返回分配的结构。在分配 myStruct 之前,您不能这样做:myStruct->packet = (int *)malloc(length * sizeof(int));

    我编写了两个示例,其中使用enum 枚举结构中packet 数组的类型,使用union packet 管理 不同类型的数据。

    结构myStruct 将包含有关packet 联合的内容类型及其数组维度的信息。

    函数create,在第一个示例中,仅使用一个malloc 来分配结构空间和数据包空间。这种方式更简单地解除分配结构。此外,create 可能会在参数err 上返回错误以指示错误情况,另一方面,如果出现错误,则在此版本的第一个示例中,函数的返回值应为NULL

    如果您不需要分配结构,我已经编写了第二个示例,它只为联合 packet 分配空间(上面的第二个示例)。这里函数create为一个已经分配的结构分配packet,如果发生错误则返回0或错误值。

    这里是第一个示例:

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef enum myType {
        myTypeDouble,
        myTypeInt
    } myType;
    
    typedef struct myStruct {
        myType myType;
        size_t length;
        // int message; in this sample this has no mean!
        union  {
            int * i;
            double * d;
        } packet;
    } myStruct;
    
    myStruct * create(myType mtype, size_t length, int *err)
    {
        myStruct * ms = NULL;
        int retVal=0;
    
        size_t mlen = sizeof (myStruct);
    
        switch(mtype) {
        case myTypeInt:
            mlen += sizeof(int)*length;
            break;
    
        case myTypeDouble:
            mlen += sizeof(double)*length;
            break;
        default:
            mlen=0;
            retVal=1;
            break;
        }
        if (mlen) {
            ms = malloc(mlen);  // One malloc allocates struct and packet.
            if (ms != NULL) {
                ms->length = length;
                ms->myType=mtype;
                /* Don't care myType, the usable space is after
                   the structure dimension then ms->packet.i=[...]
                   should be also ms->packet.d=(double *)(ms+1);
                */
                ms->packet.i=(int *)(ms+1);
            } else {
                retVal=2;
            }
        }
        if (err)
            *err=retVal;
    
        return ms;
    }
    
    int main(void) {
    #define PACKLEN 20
        myStruct * ms[2]={NULL,NULL};
        int err=0;
        int i;
    
        ms[0]=create(myTypeInt,PACKLEN,&err);
        if (err)
            return 1;
    
        ms[1]=create(myTypeDouble,PACKLEN,&err);
        if (err) {
            if (ms[0])
                free(ms[0]);
            return 2;
        }
    
        for (i=0;i<PACKLEN;i++) {
            ms[0]->packet.i[i] = i*2+1;
            ms[1]->packet.d[i] = 2.1*(double)(i+1);
        }
    
        for (i=0;i<PACKLEN;i++) {
            printf("%d ",ms[0]->packet.i[i]);
        }
        puts("");
    
        for (i=0;i<PACKLEN;i++) {
            printf("%g ",ms[1]->packet.d[i]);
        }
        puts("");
    
        if (ms[0])
            free(ms[0]);
    
        if (ms[1])
            free(ms[1]);
    }
    

    这里是第二个示例:

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef enum myType {
        myTypeDouble,
        myTypeInt
    } myType;
    
    typedef struct myStruct {
        myType myType;
        size_t length;
        // int message; don't care in this sample.
        union  {
            int * i;
            double * d;
        } packet;
    } myStruct;
    
    int create(myStruct * ms, myType mtype, size_t length)
    {
        int retVal=0;
    
        size_t mlen = 0;
        
        if (!ms) {
           return 1;
        }
    
        switch(mtype) {
        case myTypeInt:
            mlen = sizeof(int)*length;
            break;
    
        case myTypeDouble:
            mlen = sizeof(double)*length;
            break;
        default:
            mlen=0;
            retVal=2;
            break;
        }
    
        if (mlen) {
            /* Don't care myType! ms->packet.i=[...]
               should be also ms->packet.d=malloc(mlen);
            */
            ms->packet.i=malloc(mlen);
            if (ms) {
                ms->length = length;
                ms->myType=mtype;
            } else {
                retVal=3;
            }
        }
    
        return retVal;
    }
    
    int main(void) {
    #define PACKLEN 20
        myStruct ms[2];
        int err=0;
        int i;
    
        ms[0].packet.i=NULL;
        ms[1].packet.d=NULL; // Although the use of .i has the same behaviour
    
        err=create(&ms[0],myTypeInt,PACKLEN);
        if (err)
            return 1;
    
        err=create(&ms[1],myTypeDouble,PACKLEN);
        if (err) {
            if (ms[0].packet.i)
                free(ms[0].packet.i);
            return 2;
        }
    
        for (i=0;i<PACKLEN;i++) {
            ms[0].packet.i[i] = i*2+1;
            ms[1].packet.d[i] = 2.1*(double)(i+1);
        }
    
        for (i=0;i<PACKLEN;i++) {
            printf("%d ",ms[0].packet.i[i]);
        }
        puts("");
    
        for (i=0;i<PACKLEN;i++) {
            printf("%g ",ms[1].packet.d[i]);
        }
        puts("");
    
        if (ms[0].packet.i)
            free(ms[0].packet.i);
    
        // Although the use of packet.i has the same behaviour.
        if (ms[1].packet.d)
            free(ms[1].packet.d);
    }
    

    【讨论】:

      【解决方案3】:

      当您为消息容器myStruct 分配内存时,您的 sn-p 并不清楚。假设它也是动态分配的,你可以同时为它和你的数组创建内存。

      此消息的接收者需要知道如何解释信息,因此我们也需要将有关类型和长度的信息编码到其中。这是实现这一目标的一种方法:

      struct myStruct {
          int message;
          int type;
          int length;
      };
      

      因此,这包含您原始结构的message,以及传递给create() 函数的信息。请注意,这只是标题,还没有分配任何数据。我们可以创建具有灵活数组的特化来表示该数据。

      struct myStructInt {
          struct myStruct hdr;
          int data[];
      };
      
      struct myStructDouble {
          struct myStruct hdr;
          double data[];
      };
      

      每个不同的受支持数组都可以有自己的特化。现在,您的 create() 函数可以对整个消息进行一次分配。

      struct myStruct * create (int type, int length) {
          struct myStruct hdr = { 0, type, length };
          struct myStruct *m;
          size_t total = 0;
          switch (type) {
          case 1: total = sizeof(struct myStructInt) + length * sizeof(int);
                  break;
          case 2: total = sizeof(struct myStructDouble) + length * sizeof(double);
                  break;
          /* ... */
          }
          if ((m = malloc(total)) != NULL) *m = hdr;
          return m;
      }
      

      调用者会知道它想要创建什么类型的消息,因此它可以在收到来自create() 的指针后正确地将指针转换为预期的类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-03-12
        • 2015-05-17
        • 2014-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多