牺牲内存管理意图的表达

时间:2011-11-05 08:15:10

标签: c memory-management

我在C编程方面很陌生,而且这种类型的东西不断涌现。举个简单的例子,假设我有struct http_headerchar个指针:

struct http_header {
    char* name;
    char* value;
};

我想填充http_header,其中value是int的字符串表示形式。我感觉"就像在语义上一样,我应该能够编写一个函数,它接受一个空的头指针,一个名称字符串和一个int并适当地填充标题。

void fill_header(struct http_header *h, char* name, int value)
{
    h->name = name;
    char *value_str = malloc(100);
    sprintf(value_str, "%d", value);
    h->value = value_str;
}

int main(int argc, const char * argv[])
{
    struct http_header h;
    char *name = "Header Name";
    int val = 42;
    fill_header(&h, name, val);
    ...
    free(h.value);
}

在这里,调用代码完全按照我的意图读取,但在这种情况下,我动态创建value字符串,这意味着我必须在以后释放它。那对我来说没有味道;似乎调用者对fill_header的实现了解得太多了。在实际实现中,知道要释放什么可能并不容易:考虑填充http_header个数组,其中只有一个需要其值malloc

要解决这个问题,我必须事先创建字符串:

void fill_header2(struct http_header *h, char* name, char *value_str)
{
    h->name = name;
    h->value = value_str;
}

int main(int argc, const char * argv[])
{
    struct http_header h;
    char *name = "Header Name";
    int value = 42;

    char value_str[100];
    sprintf(value_str, "%d", value);
    fill_header2(&h, name, value_str);
}

随着这种模式继续沿着指向其他结构的结构链向下延伸,我最终在顶级函数中做了很多工作,而较低级别的函数似乎不值得。此外,我基本上牺牲了用int"填充标题的标题。我打算在第一时间写出来的想法。我在这里遗漏了什么?是否有一些模式或设计选择可以让我的生活更轻松让我的函数调用表达我的意图?

P.S。感谢Stackoverfow的所有人都是我曾经拥有的最好的教授。

4 个答案:

答案 0 :(得分:3)

好吧,我会采用第一种方法(带有扭曲),并提供destroy功能:

struct http_header *make_header(char *name, int value)
{
    struct http_header *h = malloc(sizeof *h);
    /* ... */
    return h;
}

void destroy_header(struct http_header *h)
{
    free(h->name);
    free(h);
}

这样调用者就不必了解http_header

您可能还会使用一个版本,将主要分配(结构本身)留给调用者并进行自己的内部分配。然后你必须提供clear_header,它只释放fill分配的内容。但是这个clear_header会给你一个部分有效的对象。

答案 1 :(得分:0)

我认为你的问题只是你编程不对称。你应该一劳永逸地决定谁对你结构中的字符串负责。那么你应该有两个函数,而不仅仅是一个,应该被称为header_initheader_destroy的函数。

对于init函数,我会更加小心。检查指针的0参数,并完全初始化DS,例如*h = (http_header){ .name = name }。您永远不知道您或某人是否会最终在您的结构中添加另一个字段。因此,至少所有其他字段都使用0初始化。

答案 2 :(得分:0)

如果您是C编程的新手,您可能想要使用Boehm's conservative garbage collector。 Boehm的GC在实践中非常有效,并且通过在您自己的代码中系统地使用它,您可以使用GC_malloc而不是malloc,而且从不打扰调用freeGC_free。< / p>

在C(甚至C ++)代码中寻找内存泄漏通常是一件令人头疼的事。有一些工具(如valgrind)可以帮助你,但是你可以决定不使用Boehm的GC。

垃圾收集(和内存管理)是程序的全局属性,所以如果你使用Boehm的GC,你应该尽早做出决定。

答案 3 :(得分:0)

您的问题的一般解决方案是对象所有权,正如其他人所建议的那样。但是,针对您的特定问题的最简单解决方案是为char使用value数组,即char value[12]。 2 ^ 32有10个十进制数字,+1表示符号,+1表示空终止符。

你应该确保1)int在编译时不大于32位,2)在调用sprintf之前确保该值在某个可接受的范围内(HTTP代码只有3位数),3)使用{{ 1}}。

因此,通过使用静态数组,您可以摆脱所有权问题,并且使用更少的内存。