【问题标题】:Using malloc with a structure and strcpy使用具有结构和 strcpy 的 malloc
【发布时间】:2013-05-30 01:05:15
【问题描述】:

我正在尝试创建一个名为 StatusItem 的结构数组,如下所示:

typedef struct 
{
    char* name;
    char* index;
    int optional;
} StatusItem;

此外,由于我希望此数组为任意大小,因此我使用的是malloc。所以数组是这样定义的:

StatusItem* statusItem = NULL;

(然后将其传递给检索所有值的函数,如下所示。)

statusItem = (StatusItem*)malloc(cJSON_GetArraySize(items));

...

for (i = 0 ; i < cJSON_GetArraySize(items) ; i++)
{
    strcpy(statusItem[i].name,name->valuestring);
    strcpy(statusItem[i].index,index->valuestring);
    if(!parseInt(optional->valuestring, &statusItem[i].optional));
    {
         goto cleanup;
    }
}

有代码涉及 cJSON 库将nameindexoptional 的字符串值获取到上面引用的变量中,并将它们存储在这些变量的valuestring 字段中。

我检查了涉及 cJSON 库的所有内容都可以正常工作,并返回正确的值,但程序无法访问或存储 statusItems 数组中的值。

有什么想法吗?我几乎可以肯定这涉及到我对malloc 的一些滥用。

【问题讨论】:

  • 忘记了代码中的for循环,现在添加。

标签: c struct malloc strcpy cjson


【解决方案1】:

发现两个误用:

  1. Don't cast the return value of malloc(), it's dangerous and superfluous.

  2. 您没有为结构的成员分配任何内存 - 您 strcpy()ing 指向未初始化的指针,因此您的程序会调用未定义的行为。

编辑:实际上是三个:

malloc(cJSON_GetArraySize(items));

没有分配足够的内存,因为它不是魔法,并且它不知道您正在保留sizeof(StatusItem) 字节的内存,因此您必须将分配大小乘以sizeof(StatusItem),或者甚至更好,乘以@987654327 @为了安全。

【讨论】:

  • 1.如果没有演员表,它会给我一个错误。 2. 我该怎么办?
  • @Nealon 然后使用 C 编译器编译您的 C 代码,并且永远不要尝试使用 C++ 编译器编译 C 代码, 2. statusItem[i].name = malloc(128);(或其他)
  • @Nealon 你用的是什么糟糕的 C 编译器?在 C 中,void *malloc() 的返回值)隐式兼容任何数据指针类型(在 POSIX 下,也兼容任何函数指针类型)。
  • Visual Studio,并将其设置为自然
  • @Nealon 如果我错了,请纠正我,但这是一个 N IDE,其中 C++ 是默认设置,而 C 几乎完全未使用...
【解决方案2】:

此外,malloc 需要一些字节,而不是元素。传递给它的值必须乘以每个元素的大小。

【讨论】:

  • statusItem = (StatusItem*)malloc(cJSON_GetArraySize(items)*sizeof(StatusItem); -- ?
【解决方案3】:

1) cJSON_GetArraySize(items) 返回元素计数 - 您需要考虑对象的大小:malloc(cJSON_GetArraySize(items) * sizeof(StatusItem))

2) StatusItem 结构没有实际字符串的内存 - 只有一个指向字符串的指针。您可以使用strdup() 分配和复制字符串。

您可能希望您的代码看起来更像:

statusItem = (StatusItem*)malloc(cJSON_GetArraySize(items) * sizeof(StatusItem));

...

for (i = 0 ; i < cJSON_GetArraySize(items) ; i++)
{
    statusItem[i].name = strdup(name->valuestring);
    statusItem[i].index = strdup(index->valuestring);
    if(!parseInt(optional->valuestring, &statusItem[i].optional));
    {
         goto cleanup;
    }
}

当然,这意味着当您释放StatusItem 对象数组时,您还必须显式释放重复的字符串:

// to free the statusItem array, and the various strings it refers to:

for (i = 0 ; i < cJSON_GetArraySize(items) ; i++)
{
    free(statusItem[i].name);
    free(statusItem[i].index);
}

free(statusItem);

【讨论】:

  • 我将如何释放那些重复的字符串?
  • 我能想到的唯一方法就是单独释放它们,但这太糟糕了,我什至不知道 strdup 将值存储在哪里
  • @Nealon 是的,确切地说,你单独释放它们,你不能做任何其他事情。 strdup() 为副本执行 malloc(),因此 free() 的返回值也足够了(但这一切都在 strdup() 的手册页中)。
  • @H2CO3 但返回值存储在我的 malloc 数组中,无论如何我都会释放它,所以不应该照顾它吗?
  • @Nealon 您可以使用malloc()strcpy() strdup()。两者都不是。
【解决方案4】:

为了避免不得不使用有点“混乱”的strdup(),因为它将内存的释放留给调用者而不是自己处理所有事情,我修改了我现有的结构如下:

typedef struct 
{
    char name[32];
    char index[32];
    int optional;
} StatusItem;

这允许 32 个字节用于名称和索引,这应该绰绰有余。以前,结构字段没有指向任何内容,这导致尝试复制到该位置时出错。现在,有空(或垃圾)内存在等待放入字符串。

这允许strcpy() 仍被使用,并允许整体更清晰的实现。

【讨论】:

    猜你喜欢
    • 2014-04-07
    • 2011-07-18
    • 2018-05-26
    • 2011-12-12
    • 1970-01-01
    • 2011-06-26
    • 1970-01-01
    • 2018-06-21
    • 2021-01-15
    相关资源
    最近更新 更多