【问题标题】:Pass a structure to a function and store values in the structure's element将结构传递给函数并将值存储在结构的元素中
【发布时间】:2018-03-22 19:19:32
【问题描述】:

我想将结构传递给函数并将值存储在结构的元素中。这是我的代码。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef struct {
    uint32_t len;
    uint16_t *arr;
} seq;

void write_seq(seq *q, int val)
{
    // How to implement this function?

    uint16_t *tmp;
    tmp = (uint16_t *)malloc(sizeof(uint16_t));
    *tmp = val;

    *(q->arr + q->len) = *tmp;
    q->len += 1;

}

int main(int argc, char *argv[])
{
    seq q;
    q.len = 0;
    q.arr = NULL;
    int i;
    for (i = 0; i < 10; i++) {
        write_seq(&q, i);
    }

    printf("length is %d\n", q.len);
    for (i = 0; i < q.len; i++) {
        printf("%d\n", *(q.arr+i));

    }

    return 0;
}

我想将 0 到 9 写入 q.arr 指向的内存块。
我不想在 main() 中使用 malloc,因为在调用 write_seq 之前我不知道需要多少字节。每次调用 write_seq 时,我都想定位新内存。输出应该是这样的。

length is 10
0
1
2
3
4
5
6
7
8
9

我的 write_seq() 实现会导致核心转储。我不知道如何解决它。谢谢。

【问题讨论】:

  • 与您的问题无关,但您知道对于任何指针或数组p 和索引i,表达式*(p + i) 完全等于p[i]?您不必使用指针算法,并且可以省去输入几个字符。
  • 另外,您有内存泄漏,您在write_seq 中分配的指针永远不会被释放。甚至没有need 来动态分配单个值。只需执行q-&gt;arr[q-&gt;len++] = val; 即可完成所有功能。
  • 还不明白你想要实现什么,但是为单个uint16_t分配内存是没有意义的。
  • 在另一个不相关的注释中,对于一个大小(如结构成员len),我建议您改用size_t。虽然它可能等于 uint32_t(至少在 32 位平台上),但它向代码的读者显示了意图。
  • uint32_t 类型用于一般的 32 位无符号整数。它可以存储任何类型的数据,除了“32位无符号整数”之外的类型没有任何意义。类型size_t 真的说“我是一个大小的类型”。所以读者会自动知道用该类型定义的变量是某种大小。

标签: c arrays pointers memory-management malloc


【解决方案1】:

你需要使用realloc(),而不是malloc(),像这样:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef struct {
    int len;
    int *arr;
} seq;

void write_seq(seq *q)
{
    q->arr = realloc (q->arr, (q->len + 1) *  sizeof(int));
    q->arr[q->len] = q->len;
    q->len++;
}

int main(void)
{
    seq q;
    q.len = 0;
    q.arr = NULL;

    for(int i = 0; i < 10; ++i)
        write_seq(&q);


    printf("length is %d\n", q.len);
    for (int i = 0; i < q.len; i++) {
        printf("%d\n", q.arr[i]);
    }

    free(q.arr);

    return 0;
}

输出:

length is 10
0
1
2
3
4
5
6
7
8
9

【讨论】:

  • 首先,请避免发布多个答案。修改你拥有的那个。其次,不鼓励使用没有 cmets 或任何解释的纯代码答案。为什么这段代码会比 OP 已有的代码更好?它如何解决 OPs 问题?最后,不要将realloc 的结果重新分配给作为参数传递给realloc 的指针。 realloc 调用可能会失败并返回 NULL,然后您将丢失原始指针并发生内存泄漏。
  • write_seq 的每次调用都使用realloc 效率低下。
  • 另外,您只是在写长度 - OP 的函数将给定数字添加到 seq
【解决方案2】:

当您事先不知道该数组的大小时,要向该数组添加成员,您需要使用realloc() 来按需增加大小。但是,对于数组大小的每一次更改,这样做效率低下,因此更通常的做法是在缓冲区。

因此,您需要存储缓冲区的当前 容量 以及相对于 当前 使用量的偏移量。

这也意味着会有一定数量的内存浪费,但这是你必须做出的权衡。

我的方法看起来像这样,抽象您可能希望在 seq 上执行的操作。

typedef struct {
    size_t    capacity;
    size_t    offset;
    uint16_t *arr;
} seq;

static const size_t SEQ_INITIAL = 8;
static const size_t SEQ_INCREMENT = 8;

int seq_init(seq *seq) {
    assert(seq != NULL);         /* catch null seq */
    assert(seq->arr == NULL);    /* error to call on already init'd seq */
    seq->capacity = SEQ_INITIAL;
    seq->offset = 0;
    seq->arr = malloc(seq->capacity * sizeof(seq->arr[0]));
    return seq->arr == NULL ? -1 : 0;
}

static int seq_grow(seq *seq) {  /* private implementation detail */
    size_t new_capacity = seq->capacity + SEQ_INCREMENT;
    void *p = realloc(seq->arr, new_capacity * sizeof(seq->arr[0]));
    if (p == NULL) {             /* realloc failed, seq unmodified */
        return -1;
    }
    seq->arr = p;
    seq->capacity = new_capacity;
    return 0;
}

int seq_write(seq *seq, uint16_t value) {
    assert(seq != NULL);         /* catch null seq */ 
    if ((seq->offset == seq->capacity) && seq_grow(seq) < 0) {
        return -1;               /* write failed */
    }
    assert(seq->arr != NULL);    /* catch bad seq */
    assert(seq->offset < seq->capacity); /* ensure seq really has room */
    seq->arr[seq->offset++] = value;
    return 0;
}

void seq_free(seq *seq) {
    if (seq != NULL) {
        free(seq->arr);
        seq->arr = NULL;
    }
}

【讨论】:

  • 您的代码运行良好。顺便说一句,我把一行改成size_t new_capacity = seq-&gt;capacity * 2;,我想也许效率更高。
  • @ZianLai 这是您必须在浪费内存或提高性能之间做出的权衡。我选择了“增量增加”方法,因为它将内存浪费限制为 8 个元素。每次将容量翻倍意味着您使用的内存最多是您需要的两倍。更好的折衷方案可能是seq-&gt;capacity * 1.4
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-15
  • 2012-05-09
  • 2018-02-13
  • 1970-01-01
相关资源
最近更新 更多