通过构造函数为结构指针成员分配空间

时间:2020-07-19 17:31:11

标签: c oop malloc

我想在C语言中使用类似对象的结构。

假设我有以下内容:

typedef struct {
    /* ... */
    size_t *pages_len;
} book;

我使用以下方法构造它:

int book_init(/* some args... */, book * b) {
    /* do some validation */
    /* compute the number of pages n_pages */
    b->pages_len = (size_t*) calloc(n_pages, sizeof(size_t));
    /* compute pages_len based on some args */
    return 0;
}

然后我构造一个这样的对象:

book *my_book = (book*)malloc(sizeof(my_book));
if (book_init(/* some args */, my_book) == 0) {
    /* do something */
}

然后销毁我的物体,例如:book_destroy(book *b),其中free(b->pages_len)

这是正确的还是我缺少什么?我无法显示原始代码,但遇到了麻烦:

  1. 在init方法之后访问b->pages_len
  2. 销毁对象。我的内存损坏。

根据要求,提供一个最小的可复制示例:

/* book.h */
#ifndef BOOK_HEADER_
#define BOOK_HEADER_
#include <ctype.h>

typedef struct
{
  size_t pages_count;
  size_t *pages_len;
} * book;

int book_create (book b);
#endif /* BOOK_HEADER_ */
/* book.c */
#include "book"

int
book_create (book b)
{
  b->pages_len = calloc (3, sizeof (b->pages_len));
  b->pages_len[2] = 20;
  return 0;
}
/* test.c */
#include "book.h"

int main(int argc, char** argv) {
  book my_book = (book)malloc (sizeof (book));
  int r = book_create (my_book);
  printf ("\n%lu\n", my_book->pages_len[2]);
  free (my_book->pages_len);
  free (my_book);
}

我从内存泄漏检测器得到的是free(my_book)给出了Memory corruption (written out of bounds?)错误。解决此错误的一件事是更改了pages_countpages_len的顺序,但我不知道为什么。

我刚刚输入了上面的示例,因此,如果有任何错别字或语法错误,请告诉我。谢谢。

1 个答案:

答案 0 :(得分:0)

book my_book = malloc(sizeof(book))是错误的。请注意,book的类型是指向您的结构的指针,但是您想为结构本身分配足够的空间。因此,如代码所示,您将需要编写malloc(sizeof(*my_book))

但是,使用typedef定义指针的名称通常是不好的方式。这会导致混乱,您会发现结构类型没有名称很尴尬。更好的书写方式就是

struct book
{
  size_t pages_count;
  size_t *pages_len;
};

struct book *my_book = malloc(sizeof(*my_book));

在这种情况下,malloc(sizeof(struct book))也可以使用,但是如果您更改my_book的类型,它将变得不可用。

通常建议您不要键入struct的类型,而应该继续在任何地方调用它struct book,因为通常最好记住要使用的对象类型。但是,如果必须,您仍然可以在之后执行typedef struct book book;。如上所述,我推荐typedef struct book *book;

在C中永远不需要铸造malloc的结果。大概包含了它是因为您收到关于malloc返回类型的警告,但是正确的解决方法是包括标准标头{ {1}}。确实,这正是人们通常建议您强制转换<stdlib.h>的结果的原因,因为它可以使表示真实错误的警告静音。有关该主题的更多信息,请参见Do I cast the result of malloc?

您还需要malloc中的<stdio.h>

此外,test.c应该返回一个值(但这不是导致崩溃的原因,因为您从未使用过它)。

毫不奇怪,重新排列结构成员使该错误似乎消失了。可能发生的事情是这样的。在典型的64位系统上,create_book和指针均为8个字节。因此,当结构的大小实际上为16时,您已经为结构分配了8个字节。但是实际上您只写了size_t成员。因此,如果pages_len是该结构的第一个成员,而您从未写过pages_len成员,那么您只在分配的8个字节内进行写操作,就不会出错。当然,代码仍然是坏的,一旦您添加了使用pages_count成员的任何代码,或者添加或重新排列了结构的任何成员,该错误就会再次出现。

但是,总的来说,用C语言编程时盲目更改直到错误消失是一个非常糟糕的主意。您可能很容易做一些仅掩盖错误并难以发现的事情。真正了解正在发生的事情是无可替代的。