【问题标题】:How to properly malloc for array of struct in C如何正确 malloc 用于 C 中的结构数组
【发布时间】:2013-11-05 23:35:43
【问题描述】:

我将使用strtok 读取两组char*(或字符串),并且由于这两组字符是相关的,(address : command\n) 我决定使用一个结构。

struct line* array = (struct line*)malloc(sizeof(file) * sizeof(struct line*));

mallocing 函数的这一行给了我一个分段错误,想知道你是否可以告诉我一个正确的方法来给它malloc 空间。对于上下文,这是我的其余代码:

struct line
{
    char* addr;
    char* inst;
};
while loop{
    x = strtok(line,": ");
    y = strtok(NULL,"\n");
    strcpy(array[i].addr,x); //assume that x and y are always 3characters
    strcpy(array[i].inst,++y);
    i++;
}

【问题讨论】:

  • 请记住,为struct line 数组分配内存不会为addrinst 字符串分配内存。根据struct line 中这些指针的使用方式,您可能还需要为字符串数据分配内存。

标签: c arrays struct malloc


【解决方案1】:

所有类型的分配都是一样的。如果您需要分配 line 结构的数组,您可以这样做:

struct line* array = malloc(number_of_elements * sizeof(struct line));

在您的代码中,您为line 指针分配了一个具有适当大小的数组,而不是为line 结构分配了一个数组。另请注意,没有理由强制转换 malloc() 的返回值。

请注意,这是更好的样式:

sizeof(*array)

代替:

sizeof(struct line)

这样做的原因是,如果您更改array 的类型,分配仍将按预期工作。在这种情况下,这是不太可能的,但这只是一个值得习惯的普遍现象。

还请注意,通过typedefing 结构可以避免一遍又一遍地重复单词struct

typedef struct line
{
    char* addr;
    char* inst;
} line;

然后你可以这样做:

line* array = malloc(number_of_elements * sizeof(*array));

当然不要忘记也为array.addrarray.inst 分配内存。

【讨论】:

  • 如果更喜欢每次都写 struct,因为关键字的作用是记住您分配的是复杂类型而不是原始类型(如 intchar * )。我也更喜欢sizeof(struct line),因为如果你写sizeof(*array),似乎你在分配它之前取消引用指针,如果它没有初始化为NULL,我敢打赌你会崩溃。
  • @Bemipefe sizeof(*array) 不会取消引用。 sizeof 是一个 static 运算符,用于检查其参数的 type。由于*array 的类型是line,所以sizeof(*array) 表示sizeof(line)
  • 好的,它没有崩溃,因为它是在编译时评估的。无论如何,如果不了解这种语言“内部”,这种语法就会产生误导。此外,您不会获得很多好处,因为如果您在函数中更改类型,您还需要更改代码中的其他内容,因为可能某些字段名称已更改或某些字段大小已更改,并且静默允许编译会导致一整套问题。
  • @Bemipefe sizeof(obj) 而不是 sizeof(type) 是 C 程序员使用的一种非常常见的模式。显然这是个人喜好。但是,请注意,当类型更改时,没有任何内容表明您也需要更改 sizeof 使用。 sizeof 只计算一个大小,不管你传递给它什么。所以即使你得到的大小是错误的,一切都会很好地编译并且没有任何警告。这就是为什么这么多人像这样使用sizeof
  • 好吧,你是对的,代码无论如何都会编译。当然只是个人意见。我在代码中看不到该语法,因为它仅在该上下文中具有该含义。也许如果您将 calloc、malloc 或 realloc 返回的指针显式转换为特定类型,您至少会收到来自编译器的警告。这可能取决于编译器和指定的选项。
【解决方案2】:

对于您所描述的,您不需要为您的结构分配内存而是,您需要为成员char *addr;char *inst;。如果您想拥有该结构的单个副本,代码的第一部分说明了如何初始化和分配值。如果你想要一个数组,第二个代码示例说明了不同之处。

这说明了如何为单个结构行的成员分配内存:

typedef struct
{
    char* addr;
    char* inst;
}LINE;

LINE line;  

int main(void)
{   

    strcpy(line.addr, "anystring"); //will fail
    line.addr = malloc(80);
    line.inst = malloc(80);
    strcpy(line.addr, "someString");//success;
    strcpy(line.inst, "someOtherString");//success;

}

对于结构行数组...

typedef struct
{
    char* addr;
    char* inst;
}LINE;  //same struct definition

LINE line[10]; //but create an array of line here.

int main(void)
{   
    int i;
    
    for(i=0;i<10;i++)
    {
      line[i].addr = malloc(80);
      line[i].inst = malloc(80);
    }

    for(i=0;i<10;i++)
    {
        strcpy(line[i].addr, "someString");
        strcpy(line[i].inst, "someOtherString");
    }
    //when done, free memory
    for(i=0;i<10;i++)
    {
        free(line[i].addr);
        free(line[i].inst);
    }      


}

添加到地址评论
针对@Adam Liss 的此答案下的评论,以下代码使用strdup() 说明了以下改进:1) 仅使用所需的内存。 2) 一步完成内存创建和复制操作,所以如下块:

for(i=0;i<10;i++)
{
  line[i].addr = malloc(80);
  line[i].inst = malloc(80);
}

for(i=0;i<10;i++)
{
    strcpy(line[i].addr, "someString");
    strcpy(line[i].inst, "someOtherString");
}

变成:

for(i=0;i<10;i++)
{
  line[i].addr = strdup("someString");
  line[i].inst = strdup("someOtherString");
}

还有一点需要注意:上面的示例中没有包含错误处理以避免混淆主要概念:但是为了完整起见,因为@987654328 @ strdup() 可能会失败,这两个函数的实际用法,在使用前应该包括一个测试,例如:

而不是

  line[i].addr = strdup("someString");
  line[i].inst = strdup("someOtherString");

代码应包括

  line[i].addr = strdup("someString");
  if(!line[i].addr)
  {
      //error handling code here
  }
  line[i].inst = strdup("someOtherString");
  if(!line[i].inst)
  {
      //error handling code here
  }

【讨论】:

  • 或使用strdup() 并使用剩余的 80 个字符以获得更有用的信息。 :-)
猜你喜欢
  • 2018-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-21
  • 2018-12-22
  • 1970-01-01
  • 2012-09-19
相关资源
最近更新 更多