【问题标题】:Unable to malloc string in struct无法在结构中分配字符串
【发布时间】:2016-05-16 07:10:55
【问题描述】:

我的结构如下所示:

struct tree{
    char *name;
    int num_subdirs;
    struct tree **subdirs;
}

我正在接收一个缓冲区,其中包含在缓冲区中序列化的整个树。我试图在这个函数中反序列化它:

struct tree *t;
//buffer is filled, received from somewhere else.
int res = deserialize(t, buf); //call function deserialize

//deserialize function
            //buf = {../,2}{sd,0}{|}{sr,1}{sk,0}{|}{|}
   │406     int dfsDeserialize(struct tree *dt, void *buf, int *q){                                                                                                                       │
   │407         char name[MAXPATHLEN];                                                                                                                                                           │
   │408         char delim[3];                                                                                                                                                                   │
   │409         int len, numsubs, i;                                                                                                                                                             │
                                                                                                                                                        │
   │411         sscanf(buf+(*q),"%3s",delim);                                                                                                                                                    │
   │412         if(!strcmp(delim,"{|}")){                                                                                                                                                        │
   │413             (*q)+=3;                                                                                                                                                                     │
   │414             return 1;                                                                                                                                                                    │
   │415         }                                                                                                                                                                                │
   │416         sscanf((buf + (*q)), "{%[^,],%d}%n", name, &numsubs, &len);                                                                                                                      │                                                                                                                                          │
  >│419         int slen = strlen(name);                                                                                                                                                         │
   │420         dt->name = calloc(slen + 1, 1);                                                                                                                                                  │
   │421         dt->subdirs = malloc(numsubs*sizeof(struct tree *));                                                                                                                      │
   │422         strcpy(dt->name, name);                                                                                                                                                          │
   │423         dt->num_subdirs = numsubs;                                                                                                                                                       │
   │424         (*q)+=len;                                                                                                                                                                       │
   │425         for(i = 0; i< numsubs; i++){                                                                                                                                                     │
   │426             dt->subdirs[i] = malloc(sizeof(struct tree));                                                                                                                         │
   │427             dfsDeserialize(dt->subdirs[i], buf, q);                                                                                                                                      │
   │428         }                                                                                                                                                                                │
   │429         return 0;                                                                                                                                                                        │
   │430     }   

                                                                                                                                                                             │

我尝试了几种不同的为字符串分配内存的方法,但每次都失败!我不知道为什么 t->name 总是 0x0。请帮忙。

【问题讨论】:

  • 你是如何将t 传递给函数dfsDeserialize 的?
  • 我声明了一个 t 并通过了它。即结构树 *t;
  • 由于您跳过了解析缓冲区的代码并且我们可以看到的代码看起来没问题,我们不得不假设您省略的代码导致了问题 - 或者您在其他地方有一些内存问题这最终在这里引发了一个问题。您是否在可以使用valgrind 的平台上?如果是这样,请使用它。如果没有,生活会更艰难。
  • 请注意,t 就像一个局部变量,离开函数后它所指向的内容将会丢失。如果要永久更改t 指向的内容,则需要传递t 的地址
  • 你有一个缓冲区溢出。格式字符串的大小为 %3s,但数组只有 3 个字节长。不幸的是,scanf() 函数的大小不包括空终止符,因此您有可能覆盖一个字节,这可能是灾难性的。将delim 的大小至少增加到 4,或者将格式更改为指定 2 而不是 3。这是否是您所有麻烦的原因还有待商榷,但缓冲区溢出绝不是好消息。

标签: c string struct malloc


【解决方案1】:

我认为罪魁祸首是这个

t = malloc(sizeof(sizeof tree));

你可能是说

t = malloc(sizeof(struct tree));

你也可以使用更方便的 strdup 在堆上复制字符串

t->name = strdup(name);

【讨论】:

  • 我也这么认为。它看起来像一个错误。
  • @EdgarRokyan 是的,一个错字
  • 这绝对是一个错误,但不是唯一的。
  • @TomKarzes 我已将代表性代码更新为我正在使用的实际代码。
【解决方案2】:

C 使用“按值传递”。当您将参数传递给函数时,函数会收到参数的副本。所以当你有:

struct tree *t;
int res = deserialize(t, buf); //call function deserialize

该函数所做的任何事情都不会影响t。该函数获取t 的当前值的副本。 (由于t 未初始化,这可能会导致未定义的行为)。

相反,您需要告诉函数t 在内存中的位置:

int res = deserialize(&t, buf);

函数可能如下所示:

int deserialize(struct tree **p_t, void *buf)
{
    struct tree *t = malloc(sizeof *t);
    // ... set up t as before

    // tell the caller about what we did
    *p_t = t;
}

另一种方法是保留deserialize,但完全删除malloc;并要求调用者在调用函数之前分配空间。这更加灵活,因为调用者可以选择使用自动分配或动态分配。

【讨论】:

  • 好的,但是后续调用中的子节点呢?我需要 malloc 他们,对吧?
  • 注意:这个答案是在最新编辑之前写的,在任何阶段都不会分配内存
  • 很抱歉。为了清楚起见,我认为使用实际代码会更好。
  • @Neo 你的意思是subdirs?很难说,因为现有的代码是不完整的。
  • 是的。子目录。它们必须被分配,对吗?
猜你喜欢
  • 2017-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-31
  • 1970-01-01
  • 1970-01-01
  • 2021-04-29
  • 2017-06-12
相关资源
最近更新 更多