malloc 如何在包装函数中工作?[复制]

How does malloc work within wrapper function? [duplicate]

提问人:alex 提问时间:2/16/2021 最后编辑:anastaciualex 更新时间:2/16/2021 访问量:150

问:

我有一个问题专门针对:

void* malloc (size_t size);

在互联网上数百万个网站上可以找到的常规示例中,它表明正确的使用方式如下:malloc

int main()
{
   int* num;
   num = malloc(sizeof(int));

   *num = 10;
   printf("Value = %d\n", *num);
   
   free(num);

   return 0;
}

但是,如果我想在函数中分配内存并在 main 中使用它,如下所示,那么唯一的选择是以下方式实现该函数:

void func_alloc(int** elem, int num_value)
{
    *elem = malloc(sizeof(int));
    **elem = num_value;
}

int main()
{
    int* num;
    func_alloc(&num, 10);
    free(num);

    return 0;
}

我错误地认为,下面的代码会起作用:

void func_alloc(int* elem, int num_value)
{
    elem = malloc(sizeof(int));
    *elem = num_value;
}

int main()
{
    int* num;
    
    func_alloc(num, 10);
    free(num);

    return 0;
}

您能否解释一下,或者提供一个资源链接,并解释为什么它只能以这种方式工作?

我真的不明白为什么我需要双指针作为输入参数,为什么在另一种情况下会出现“分段错误”......

提前致谢;)

C 函数 指针 malloc

评论

1赞 StoryTeller - Unslander Monica 2/16/2021
“唯一的选择” - 不完全是。您始终可以返回指针,而不是采用输出参数。
1赞 Nate Eldredge 2/16/2021
因为 C 使用按值传递
0赞 user3386109 2/16/2021
C 按值传递参数。在最后一个代码片段中只是一个局部变量。更改它对 中没有影响。尝试释放尚未分配值的指针也是如此。启用编译器警告,编译器会告诉你。elemnummainfree(num)

答:

-1赞 ilkkachu 2/16/2021 #1

如果您有:

#include <stdio.h>

void foo(int x)
{
    x = 9;
}

int main(void)
{
    int a = 1;
    foo(a);
    printf("%d\n", a);
}

您可能不希望 in 的值仅仅因为分配给 而改变,对吧?它不会更改,因为参数是按值分配的。中的变量 , 和 in 是两个不同的变量。amain()foo()xxfoo()amain()

这同样适用于您的代码。 in 是与 in 不同的变量,赋值给前者不会改变后者的值。事实上,这两者是类型的,而不是 ,这与此没有区别。elemfunc_alloc()nummain()int *int

也就是说,您也可以返回从中获取的指针,例如malloc()

int *alloc_int(int value)
{
    int *p = malloc(sizeof(int));
    *p = value;
    return p;
}

(并不是说这似乎很有意义。int

1赞 anastaciu 2/16/2021 #2

我错误地认为,下面的代码会起作用。

在 C 中,参数是按值传递的,当你将指针作为函数的参数传递时,你传递的是指针的值,基本上是它的副本,而不是指针本身,会改变该指针的值,但由于你传递的是副本,所以这就是更改的内容,而不是原始指针, 那个保持不变。malloc


在第二个代码片段中,工作代码,大致意味着使此指针指向通过(假设它成功)提供给我的这个有效内存地址,指向您作为参数传递的指针的指针的值保持不变,它是一个副本并不重要,因为它没有更改,它仍然是作为参数传递的相同地址, 指针的地址,该指针现在指向 给出的内存位置。*elem = malloc(sizeof(int));elemmallocelemnummalloc

**elem = num_value表示存储在指针中存储的地址 哪里是指向的,这是哪里指向的地方,这是先前由 给出的新内存块。num_valueelemnummalloc


话虽如此,这不是唯一的选择,您可以使用本地指针,返回它并将其分配给调用方的另一个本地指针,这仍然是一个副本,但它是已更改指针的副本:

int *func_alloc(int num_value)
{
    int *elem = malloc(sizeof *elem); //more idiomatic

    if(elem == NULL){        // check for allocation errors
        perror("malloc" );
        exit(EXIT_FAILURE);
    }

    *elem = num_value;
    return elem;
}

int main()
{
    int* num = func_alloc(10);
    free(num);
    return EXIT_SUCCESS;
}

脚注:

在第三个代码片段中,鉴于它未初始化,释放是一个坏主意,我想你知道很多,但我想我会提到它。这可能是您遇到段错误的原因,无论垃圾值如何,都将假定为有效的内存地址,并尝试解除分配它,这样做将调用未定义的行为。如果它是 NULL,那就另当别论了,它是定义良好的行为(除了在一些非常古老的标准中)。在大多数情况下,在声明变量时初始化变量是一个好主意。numnumfree

0赞 Peartree 2/16/2021 #3

评论解释:

void func_alloc(int* elem, int num_value)
{
    /* elem points to address gave by malloc, let's say 0x12345678 */
    elem = malloc(sizeof(int));

    /* at address 0x12345678 you have now your num_value */
    *elem = num_value;

    /* end of the function. Changes made to parameters passed by value are lost */
}

int main()
{
    int* num;
    
    /* num is a pointer to an address you could not have write access to, you actually don't know */

    func_alloc(num, 10);
    /* As C arguments are passed by value, changes made into the function are lost */

    /* You try to free num which is still a pointer to an address you potentially have no access to => SEGFAULT */
    free(num);

    return 0;
}

编辑: 此示例中未显示,但最好始终检查 malloc 返回的指针是否为 NULL,否则应退出而不尝试为指针赋值。