【问题标题】:C Pointer and Memory Allocation: Realloc Arrays and Pointer PassingC 指针和内存分配:Realloc 数组和指针传递
【发布时间】:2012-03-15 15:54:15
【问题描述】:

对于有 C 经验的人来说,这将是一个简单的内存分配/引用问题:

这是我的数据结构:

struct configsection {
    char *name;
    unsigned int numopts;
    configoption *options;
};
typedef struct configsection configsection;

struct configfile {
    unsigned int numsections;
    configsection *sections;
};
typedef struct configfile configfile;

这是我初始化配置部分或配置文件以及将配置部分添加到配置文件的例程:

// Initialize a configfile structure (0 sections)
void init_file(configfile *cf) {
    cf = malloc(sizeof(configfile));
    cf->numsections = 0;
}
// Initialize a configsection structure with a name (and 0 options)
void init_sec(configsection *sec, char *name) {
    sec = malloc(sizeof(configsection));
    sec->numopts = 0;
    sec->name = name;
    printf("%s\n", sec->name);
}
// Add a section to a configfile
void add_sec(configfile *cf, configsection *sec) {
    // Increase the size indicator by 1
    cf->numsections = cf->numsections + 1;
    // Reallocate the array to accommodate one more item
    cf->sections = realloc(cf->sections, sizeof(configsection)*cf->numsections);
    // Insert the new item
    cf->sections[cf->numsections] = *sec;
}

我相信我的问题源于我的 init_sec() 函数。这是一个例子:

int main(void) {

// Initialize test configfile
configfile *cf;
init_file(cf);

// Initialize test configsections
configsection *testcs1;
init_sec(testcs1, "Test Section 1");
// Try printing the value that should have just been stored
printf("test name = %s\n", testcs1->name);

虽然init_sec() 中的printf() 成功打印了我刚刚存储在配置部分中的名称,但在main() 的printf() 中尝试相同的操作会产生分段错误。此外,addsec() 会产生分段错误。

【问题讨论】:

  • @IntermediateHacker:谢谢。这是有原因的吗?
  • 好吧,如果您只是使用标准 C,则不会。但有时,使用 GObject 等可能会导致问题

标签: c pointers memory-management reference


【解决方案1】:

这个程序应该是

void init_file(configfile **cf) { 
    *cf = malloc(sizeof(configfile)); 
    (*cf)->numsections = 0;
    (*cf)->sections = NULL; // You forgot to initialise this.
}

即由init_file(&myconfigfilepointer); 调用,因此malloc 返回值被传回。

需要对init_sec做同样的把戏

这个函数不正确 - 这是一个更正的版本

void add_sec(configfile *cf, configsection *sec) {     
    // Increase the size indicator by 1     
    // Reallocate the array to accommodate one more item     
    cf->sections = realloc(cf->sections, sizeof(configsection)*(1 + cf->numsections));     
    // Insert the new item     
    cf->sections[cf->numsections] = *sec; // Since arrays start at 0     
    cf->numsections = cf->numsections + 1;     
} 

然后你需要调整main中的调用

【讨论】:

  • 加上 () 是这样的:(*cf)->sections,我认为这可能是解决方案。
  • 啊,是的。您注意到我错误地分配了我的数组值。太棒了!
【解决方案2】:

你从来没有初始化cf->sections,这意味着当你第一次尝试realloc时,你是在传递垃圾。添加:

 cf->sections = NULL;

init_file 应该会有所帮助。

您也没有检查任何返回码,但您知道是吗?

【讨论】:

  • 呵呵,我也错过了+1 :)
【解决方案3】:

您需要传递要更新的值的指针...例如:

// Initialize a configfile structure (0 sections)
void init_file(configfile **cf) {
    *cf = malloc(sizeof(configfile));
    (*cf)->numsections = 0;
}

configfile *var;
init_file(&var);
printf("%d\n", var->numsections);

否则你只是更新本地指针 *cf 而不是原来传入的值

【讨论】:

  • 嗯...到达那里。 *cf->numsections = 0; 产生“不是结构或联合”错误。
  • 在答案中添加了操作顺序支撑,试一试。
  • 这个答案是完全错误的。您需要 (*cf)->numsections = 0 或 (*cf).numsections = 0 - 它们是等效的 - 不是两者的组合。更新:我的错误 - 见下文。
  • @Geoffrey:哦,是的!我以前见过!谢谢。
  • @Tim - 我以为我修好了???它不是完全错误的,它是一个语法错误,并且(*cf).numsections 是无效的,它是一个指向定义中的指针的指针。
【解决方案4】:

您需要真正重新考虑在 C 中如何传递函数参数以及指针是什么。您的问题与内存分配无关。相反,您的代码仅将指向动态分配内存的指针分配给 局部变量,而调用代码对此一无所知。

虽然您可以通过将指针传递给调用者的指针(即双指针)来解决问题,但这不一定是最优雅或最常用的处理方式。相反,您应该返回函数的分配结果。当您使用它时,您还应该使用calloc 立即将内存清零。总结一下:

typedef struct substuff_
{
    int a;
    double b;
} substuff;

typedef struct stuff_
{
    unsigned int n;
    substuff * data;
} stuff;

substuff * init_substuff()
{
    substuff * const p = malloc(sizeof *p);
    if (p) { p->a = 5; p->b = -0.5; }
    return p;
}

stuff * init_stuff()
{
    substuff * const p = init_substuff();
    if (!p) return NULL;

    stuff * const q = malloc(sizeof *q);
    if (q) { q->n = 10; q->data = p; }
    return q;
}

作为练习,您应该编写相应的函数void free_substuff(substuff *) 和void free_stuff(stuff *)。

【讨论】:

  • 这个解决方案看起来更加优雅。我发现很难跟踪在双指针情况下指向的内容。我将尝试实现这一点。
【解决方案5】:

是的,init_sec有问题

// Initialize a configsection structure with a name (and 0 options)
void init_sec(configsection *sec, char *name) {
    sec = malloc(sizeof(configsection));
    sec->numopts = 0;
    sec->name = name;
    printf("%s\n", sec->name);
}

您只是在此处复制名称指针,这意味着它指向名称的原始存储。如果你像这样打电话给init_sec

configsection foobar()
{
    configsection sec;
    char name[80];

    get_name(name);
    init_sec(sec, name);
    return sec;    
}

name 指针在foobar 返回的那一刻变得无效。您需要复制字符串并保留您的私人副本。在init_sec:

    sec->name = strdup(name);

但还有更多。在init_sec 的第一行中,您将使用malloc 覆盖传递给init_sec 的指针。所以新的指针永远不会被传回给被调用者。要么使用指向指针的指针,根本不使用 configsection 指针(毕竟,你正在分配),而只是返回分配的指针:完成更正函数:

// Initialize a configsection structure with a name (and 0 options)
configsection* init_sec(char *name) {
    configsection *sec = malloc(sizeof(configsection));
    sec->numopts = 0;
    sec->name = name;
    printf("%s\n", sec->name);
    return sec;
}

【讨论】:

  • 是的,这似乎是正确的。如果我尝试在初始化函数之外访问名称值,那么我只会得到(null)。
  • @thoughtadvances:抱歉,我过早地点击了“回答”。你有两个问题。一个是不重复的名称字符串,另一个是您正在分配内存,但从不传回指针。
猜你喜欢
  • 2015-12-10
  • 2021-11-29
  • 1970-01-01
  • 2020-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-06
相关资源
最近更新 更多