【问题标题】:Weird behavior of mallocmalloc 的奇怪行为
【发布时间】:2014-12-03 10:14:59
【问题描述】:

我正在尝试动态初始化队列。这是我的功能。

typedef struct{
    int size;
    int max_size;
    short * eles;
} queue;

void dump_queue(queue *q)
{
    //print a bunch of information
}

void init_queue(queue *q, int max_size)
{
    q = (queue)malloc(sizeof(queue));
    q->size = 0;
    q->max_size = max_size;
    q->eles = (short *)malloc(max_size * sizeof(short));
    int i;
    for(i = 0; i < max_size; i++)
        q->eles[i] = -1;
    dump_queue(q);
}

task_queue 是一个全局变量。例程的结构是这样的:(不是确切的代码)

//globally defined here but not initialized 
queue * task_queue;
void init_scheduler()
{
    init_queue(task_queue, 32);

    dump_queue(task_queue);
    //other staff
}

注意dump_queue有两个,一个是init_queue(),一个是init_queue之后。由于 task_queue 是 malloced,我希望 dump_queue 的两次调用应该给出相同的结果。但第二个实际上报告了一个 SIG_FAULT。

我查了一下,第二次调用dump_queue,task_queue其实是NULL。这是为什么呢?

【问题讨论】:

  • 你 malloc 一些内存,然后扔掉指向它的指针。这就像把钱放在你的钱包里,把那个扔掉,然后问你的钱去了哪里。 (“它还在你的钱包里”就是答案。)
  • 您不能通过没有间接的赋值来更改不同范围的值。 q = ... 永远不会工作,你需要*q = ...
  • 这也行不通@perreal。他需要返回指针或传递queue ** 参数,以便他可以为实际指针分配地址。更简洁的方法是在本地声明 q 并返回它,而不是使用指针到指针的参数通过参数传递它。
  • 请将解决方案发布为您自己问题的答案,而不是编辑问题以包含答案。
  • 我回滚了最后一次编辑;正如Introductory Tour 中所述,它使 Stack Overflow 作为“问答网站”的目的无效。

标签: c linux struct malloc system


【解决方案1】:

为什么不呢?您正在init_queue()函数本地范围中分配内存。

返回指针的作用域有效,但赋值无效。

q = malloc(sizeof(queue));

这个q 不会在init_queue() 函数之外保持它的值。

如果queue * task_queue;是全局的,是否真的需要将其作为函数参数传递?

另外,请注意do not castmalloc()的返回值。


编辑:

不,c 中没有 auto-free() 的概念。如果应用程序没有明确free()-d,它将导致内存泄漏

【讨论】:

  • 您能具体解释一下吗?函数返回后内存会自动释放吗?
  • 特别是,不要对 malloc 的返回值使用非法强制转换!
  • 不是DV,而是malloc分配的内存不是函数本地的。您的意思是说指向该内存的指针仅存储在本地范围内;所以调用代码看不到它
  • 谢谢。这就说得通了。我不知道反对票从何而来。我会支持你!
  • @MattMcNabb 是的,这就是我想要表达的意思。 assignment 是本地的,而不是返回的指针。
【解决方案2】:

您永远不会为task_queue 分配任何东西。请注意,您通过值而不是通过引用将task_queue 传递给init_queue。您应该修改init_queue 以返回queue *,或修改其第一个参数以采用queue ** 并从init_scheduler 传入&amp;task_queue

或者也许是最简单的解决方法,因为它是一个全局的,只需在 init_queue 的末尾加上 task_queue = q;

【讨论】:

    【解决方案3】:

    它应该是 init_queue(&task_queue);或 task_queue=init_queue();

    【讨论】:

    • 不,一点也不。 init_queue 的返回类型是 void
    • 请不要将其放在评论中,为什么不更新您的答案?
    【解决方案4】:

    如果你只使用这个函数来初始化 task_queue 你应该这样做

    void init_global_queue(int max_size)
    {
        queue *task_queue = malloc(sizeof(queue));
        task_queue->size = 0;
        task_queue->max_size = max_size;
        task_queue->eles = malloc(max_size * sizeof(short));
        int i;
        for(i = 0; i < max_size; i++)
            task_queue->eles[i] = -1;
    }
    

    但不幸的是,这不是一个好的模式,因为你不能多次使用这个函数

    我认为最好的方法是这样

    queue *init_queue(int max_size)
    {
        queue *q = malloc(sizeof(queue));
        q->size = 0;
        q->max_size = max_size;
        q->eles = malloc(max_size * sizeof(short));
        int i;
        for(i = 0; i < max_size; i++)
            q->eles[i] = -1;
        return q;
    }
    

    当你想初始化任何队列时,你只需要调用这个函数

    queue * task_queue;
    void init_scheduler()
    {
        task_queue = init_queue(32);
    
        dump_queue(task_queue);
    }
    

    还有两件事:

    - 强制转换 malloc 调用的返回值并不是很糟糕,事实上它无论如何都会被强制转换,显式或隐式

    - 执行 malloc 并(对于本示例)返回其值的最佳方式如下:

    type *my_pointer = NULL;
    my_pointer = malloc(sizeof (type))
    if (my_pointer == NULL)
        return NULL;
    my_pointer->foo = 0;
    my_pointer->bar = NULL;
    ...
    return my_pointer
    

    这样,如果 malloc 不能正常工作(例如:如果你的 RAM 已满,malloc 将返回 NULL(并将 errno 设置为 ENOMEM)),你可以正常退出程序

    如果你喜欢极简编程,你可以这样做;)

    type *my_pointer = NULL;
    if (!(my_pointer = malloc(sizeof (type))))
        return NULL;
    

    更多?人malloc,人errno

    【讨论】:

      猜你喜欢
      • 2015-06-05
      • 2011-01-21
      • 2018-10-22
      • 1970-01-01
      • 2018-04-10
      • 1970-01-01
      • 2013-06-16
      相关资源
      最近更新 更多