在C语言中使用void函数处理结构

时间:2018-11-19 09:18:51

标签: c memory memory-management struct

因此,我被设置为创建一个人造字符串结构并在我的人造字符串结构上实现所有常用的字符串函数的任务。我被困在我的strcat实现的测试中,这个测试称为append,第一个测试失败(segfault)是第5行。我创建新结构的功能应该可以,因为它通过了所有测试,但是我只是以防万一。

我已经能够成功地为我的伪字符串结构实现length,get,set和copy函数。

结构:

struct text {
    int capacity;
    char *content;
};

typedef struct text text;

我用于创建新结构的功能:

text *newText(char *s) {
    printf("new Text from %s\n", s);
    int sizeNeeded = (strlen(s)+1);
    int sizeGot = 24;
    while (sizeNeeded > sizeGot) {
        sizeGot = sizeGot * 2;
      }
    text *out = malloc(sizeGot);
    char *c = malloc(sizeGot);
    strcpy(c, s);
    out->content = c;
    out->capacity = (sizeGot);
    printf("the capacity is %d\n", sizeGot);
    return out;
    free(c);
}

我的附加函数:

void append(text *t1, text *t2) {
  printf("t1 content is %s, t2 content is %d\n", t1->content, *t2->content);
  int sizeNeeded = (t1->capacity + t2->capacity);
  int sizeGot = 24;
  while (sizeNeeded > sizeGot) {
      sizeGot = sizeGot * 2;
    }
  char *stringy = calloc(sizeGot, 32);
  stringy = strcat(t1->content, t2->content);
  free(t1);
  t1 = newText(stringy);
}

最后是测试:

void testAppend() {
    text *t = newText("car");
    text *t2 = newText("pet");
    append(t, t2);
    assert(like(t, "carpet"));
    assert(t->capacity == 24);
    text *t3 = newText("789012345678901234");
    append(t, t3);
    assert(like(t, "carpet789012345678901234"));
    assert(t->capacity == 48);
    freeText(t);
    freeText(t2);
    freeText(t3);
}

2 个答案:

答案 0 :(得分:0)

您以错误的方式分配内存。您可以像这样使用 flexible数组成员来解决此问题:

typedef struct {
  int capacity;
  char content[];
} text;

text *out = malloc(sizeof(text) + sizeof(something));
strcpy(out->content, str);
...

显然,这样的代码是胡说八道:

  return out;
  free(c);
}

启用编译器警告并听取它们。

答案 1 :(得分:0)

Och,您遇到了一些错误:

  1. text_new内,如果text *out为常数,则使用text *out = malloc(sizeGot);sizeGot = 24分配内存。您应该为此分配sizeof(*out)sizeof(text)字节的内存。
  2. 我不知道int sizeGot = 24; while (sizeNeeded > sizeGot)text_new内的循环是干什么的。我猜想这样做的目的是用24的幂进行分配。而且看起来两个函数中的代码似乎都一样,看起来确实像代码重复,这是一件坏事。
  3. append内部,您传递了一个指向append的指针,而不是双指针,因此,如果您修改t1指针本身,则该修改在函数范围之外是不可见的。 t1毫无意义,并且会泄漏内存。您可以先t1 = newText(stringy);,然后再void append(text **t1, text *t2)。但是,您可以使用*t1 = newText(stringy)使用更好的方法-我希望将append添加到“追加”字符串,而不是创建新对象。因此,首先使用realloc,然后使用realloc调整缓冲区的大小。
  4. strcat(&t1->content[oldcapacity - 1], string_to_copy_into_t1)已关闭。您分配的容量为24的幂,它实际上不会与字符串长度发生交互。两个字符串和空终止符都需要有int sizeNeeded = (t1->capacity + t2->capacity);个字节。

尝试一下:

strlen(t1->content) + strlen(t2->content) + 1

这:

size_t text_newsize(size_t sizeNeeded)
{
      // I think this is just `return 24 << (sizeNeeded / 24);`, but not sure
      int sizeGot = 24;
      while (sizeNeeded > sizeGot) {
          sizeGot *= 2;
      }
      return sizeGot;
}

text *newText(char *s) {
    printf("new Text from %s\n", s);
    if (s == NULL) return NULL;
    int sizeNeeded = strlen(s) + 1;

    int sizeGot = text_newsize(sizeNeeded);

    text *out = malloc(sizeof(*out));
    if (out == NULL) {
         return NULL;
    }

    out->content = malloc(sizeGot);
    if (out->content == NULL) {
         free(out);
         return NULL;
    }

    strcpy(out->content, s);
    out->capacity = sizeGot;

    printf("the capacity is %d\n", sizeGot);

    return out;
}

一些评论:

  1. 尝试处理库中的错误。如果您有一个像int append(text *t1, text *t2) { printf("t1 content is %s, t2 content is %s\n", t1->content, t2->content); int sizeNeeded = strlen(t1->content) + strlen(t2->content) + 1; if (t1->capacity < sizeNeeded) { // this could a text_resize(text*, size_t) function int sizeGot = text_newsize(sizeNeeded); void *tmp = realloc(t1->content, sizeGot); if (tmp == NULL) return -ENOMEM; t1->content = tmp; t1->capacity = sizeGot; } strcat(t1->content, t2->content); return 0; } 这样的函数,则将其设为void append(text *t1, text *t2),并在成功时返回0,并在int append(text *t1, text *t2)错误时返回负数。
  2. 使用*alloc类型存储所有内容的大小。它在size_t中定义,应用于表示对象的大小。 stddef.h返回strlen,而size_t也返回sizeof
  3. 我喜欢将所有内容放在单个“命名空间”中,我可以通过在函数之前加上size_t这样的字符串来实现。
  4. 我有一些空闲时间,决定实施您的图书馆。以下是带有存储字符串的简单text_对象的代码,我使用text幻数作为分配块大小。

24