C 编程:另一个函数中的 malloc()

C Programming: malloc() inside another function

提问人:HaggarTheHorrible 提问时间:5/15/2010 最后编辑:Jonathan LefflerHaggarTheHorrible 更新时间:6/2/2020 访问量:116919

问:

我需要有关另一个函数的帮助。malloc()

我正在从我的函数传递指大小,我想使用调用的函数内部动态地为该指针分配内存,但我看到的是......正在分配的内存是为我调用的函数中声明的指针,而不是为 .main()malloc()main()

我应该如何传递指向函数的指针,并从被调用函数内部为传递的指针分配内存?


我编写了以下代码,并得到如下所示的输出。

源:

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(input_image, bmp_image_size)==NULL)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     
   return 0;
}

signed char alloc_pixels(unsigned char *ptr, unsigned int size)
{
    signed char status = NO_ERROR;
    ptr = NULL;

    ptr = (unsigned char*)malloc(size);

    if(ptr== NULL)
    {
        status = ERROR;
        free(ptr);
        printf("\nERROR: Memory allocation did not complete successfully!");
    }

    printf("\nPoint1: Memory allocated: %d bytes",_msize(ptr));

    return status;
}

程序输出:

Point1: Memory allocated ptr: 262144 bytes
Point2: Memory allocated input_image: 0 bytes
C 函数 指针 malloc

评论


答:

92赞 Mark Ransom 5/15/2010 #1

您需要将指向指针的指针作为函数的参数传递。

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size) == NO_ERROR)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     
   return 0;
}

signed char alloc_pixels(unsigned char **ptr, unsigned int size) 
{ 
    signed char status = NO_ERROR; 
    *ptr = NULL; 

    *ptr = (unsigned char*)malloc(size); 

    if(*ptr== NULL) 
    {
        status = ERROR; 
        free(*ptr);      /* this line is completely redundant */
        printf("\nERROR: Memory allocation did not complete successfully!"); 
    } 

    printf("\nPoint1: Memory allocated: %d bytes",_msize(*ptr)); 

    return status; 
} 

评论

6赞 James Morris 5/15/2010
<S>为什么要在保证具有 NULL 指针的条件代码块中调用 free?!?</S> 从尝试到自由时的意志,嗯,这个词回避了我......不是动态分配的。free(*ptr)main()input_image
0赞 HaggarTheHorrible 5/15/2010
和@James:我按照 Mark 和 Matti 的建议做了,但这次我在 main() 中的 _mize(input_image) 和 alloc_pixels(...) 函数中的 _msize(**ptr) 都返回大小为 0。而如果是 _msize(*ptr) (single *) 返回 262144。?
2赞 Mark Ransom 5/15/2010
@James Morris,我只是复制了问题中发布的代码,并进行了最少的更改。我不想陷入对重点的分心。
0赞 Mark Ransom 5/15/2010
@vikramtheone,对不起,我有点匆忙,没有把这个答案说得那么完整。我已经编辑了它以使其更完整。我希望你能看到它与你的原始代码有何不同,以及为什么它必须这样。
0赞 Zeeshan 4/7/2016
我在 MSVS 上尝试了同样的事情,但没有奏效。input_image仍然是“坏指针”。可能是什么原因?
8赞 Matti Virkkunen 5/15/2010 #2

如果希望函数修改指针本身,则需要将其作为指针的指针传递。下面是一个简化的示例:

void allocate_memory(char **ptr, size_t size) {
    void *memory = malloc(size);
    if (memory == NULL) {
        // ...error handling (btw, there's no need to call free() on a null pointer. It doesn't do anything.)
    }

    *ptr = (char *)memory;
}

int main() {
   char *data;
   allocate_memory(&data, 16);
}

评论

1赞 Carl Norum 5/15/2010
调用空指针是安全的,该注释是关于什么的?free()
1赞 Matti Virkkunen 5/15/2010
@Carl Norum:这很安全,但毫无意义。IMO,不做任何事情的代码只会导致人们的困惑,他们最终会在以后阅读它,应该避免。
0赞 James Morris 5/15/2010
@Matti Virkkunen:告诉人们不要在空指针上免费调用是毫无意义的,而且是错误的信息 - 当人们看到违背你的建议的代码时,你会导致他们感到困惑。
0赞 Matti Virkkunen 5/15/2010
@James Morris:好吧,好吧......现在更喜欢措辞了吗?
1赞 Donal Fellows 5/15/2010
@Carl:我遇到过(不是很好)C 库,如果被要求崩溃,所以无论如何都要避免。(不,我不记得是哪个了。那是很久以前的事了。free(NULL);
2赞 Bertrand Marron 5/15/2010 #3

这没有意义:

if(alloc_pixels(input_image, bmp_image_size)==NULL) 

alloc_pixels返回一个 ( 或 ),然后将其与(应该用于指针)进行比较。signed charERRORNO_ERRORNULL

如果要更改,则需要将指向它的指针传递给 。 签名如下:input_imagealloc_pixelsalloc_pixels

signed char alloc_pixels(unsigned char **ptr, unsigned int size)

你可以这样称呼它:

alloc_pixels(&input_image, bmp_image_size);

和内存分配

*ptr = malloc(size);
114赞 jamesdlin 5/15/2010 #4

我应该如何传递指向 函数并为 从被调用的内部传递指针 功能?

问问自己:如果你必须编写一个必须返回 的函数,你会怎么做?int

你可以直接返回它:

int foo(void)
{
    return 42;
}

或者通过添加间接级别(即,使用 而不是 ):int*int

void foo(int* out)
{
    assert(out != NULL);
    *out = 42;
}

因此,当您返回指针类型 () 时,情况是一样的:您可以直接返回指针类型:T*

T* foo(void)
{
    T* p = malloc(...);
    return p;
}

或者添加一个间接级别:

void foo(T** out)
{
    assert(out != NULL);
    *out = malloc(...);
}

评论

1赞 Donal Fellows 5/15/2010
我喜欢这个断言;它是函数合约的一部分,调用者应该系统地正确。当然,更微妙的代码可能会使 NULL 成为允许的,使其对应于可选的 out-parameter。但这不是所需要的;这个问题不需要如此复杂。outalloc_pixels
1赞 William Everett 1/10/2014
在调用函数(在本例中为 main)内释放(*out)是否安全?
2赞 jamesdlin 1/10/2014
@Pinyaka:调用方调用生成的指针是安全的(否则调用方将如何释放分配的内存?但是,调用方要么正在执行(以第一种形式),要么(以第二种形式)。在这两种情况下,调用方都必须调用 ,而不是 。free()T* out = foo();T* out; foo(&out);free(out)free(*out)
4赞 t0mm13b 5/15/2010 #5

你需要通过引用而不是复制来传递指针,函数中的参数需要 & 号和 & 来传回指针的地址 - 即在 C 语言中通过引用调用alloc_pixels

main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size)==NULL)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     

}

signed char alloc_pixels(unsigned char **ptr, unsigned int size)
{
    signed char status = NO_ERROR;
    *ptr = NULL;

    *ptr = (unsigned char*)malloc(size);

    if((*ptr) == NULL)
    {
        status = ERROR;
        /* free(ptr);
        printf("\nERROR: Memory allocation did not complete successfully!"); */
    }

    printf("\nPoint1: Memory allocated: %d bytes",_msize(*ptr));

    return status;
}

我已经注释掉了这两行和“错误:......”在函数中,因为这令人困惑。如果内存分配失败,则不需要指针。free(ptr)alloc_pixelsfree

编辑:在查看了 OP 提供的 msdn 链接后,建议,代码示例与我的回答中的前面相同......但。。。在 中的调用中将格式说明符更改为类型。%usize_tprintf(...)main()

main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size)==NULL)
     printf("\nPoint2: Memory allocated: %u bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     

}

评论

0赞 HaggarTheHorrible 5/15/2010
我明白我做错了什么。然而,有一个问题仍未解决。当我进行这些更改并使用 _msize(input_image);在我的 main() 中,_msize(...) 返回一个 0。同时为_msize(*ptr);在另一个函数中,我得到的大小为 262144。这是怎么回事?我不知道。
0赞 t0mm13b 5/15/2010
@vikramtheone:您能展示一下_msize(...)的功能原型吗?修改您的问题以强调......
0赞 HaggarTheHorrible 5/15/2010
没关系,它现在工作正常:)这是一个深夜的工作,我的头脑都变得模糊了,我忘了更改main()。当我在main()中调用alloc_memory(...)时,我没有发送input_image的地址。
1赞 juventus 5/15/2010 #6

在您的初始代码中,当您将input_image传递给函数alloc_pixels时,编译器正在创建它的副本(即 ptr)并将值存储在堆栈上。将 malloc 返回的值分配给 ptr。一旦函数返回到 main 并且堆栈展开,此值就会丢失。因此,内存仍在堆上分配,但内存位置从未存储在(或分配给)input_image中,因此存在问题。

您可以更改函数alloc_pixels的签名,这样更易于理解,并且您也不需要额外的“状态”变量。

unsigned char *alloc_pixels(unsigned int size)
{
    unsigned char *ptr = NULL;
    ptr = (unsigned char *)malloc(size);
    if (ptr != NULL)
       printf("\nPoint1: Memory allocated: %d bytes",_msize(ptr));
    return ptr;
}

您可以在 main 中调用上述函数:

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if((input_image = alloc_pixels(bmp_image_size))==NULL)
       printf("\nPoint3: Memory not allocated");    
   else
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image)); 
   return 0;

}
1赞 VELVETDETH 9/21/2014 #7

仅当您将值设置为其地址时,参数的赋值才有效。

在尝试解决此问题之前,您应该了解 2 点: 1. C 函数:
您传递给函数的所有参数都将是函数中的副本。

这意味着您在函数中所做的每个赋值都不会影响函数外部的变量,您实际上是在处理副本

int i = 1;
fun(i);
printf("%d\n", i);
//no matter what kind of changes you've made to i in fun, i's value will be 1

所以,如果你想改变函数中的i,你需要知道事物和它的副本之间的区别:

副本与事物共享,但不与地址共享。

这是他们唯一的区别。

因此,在函数中更改 i 的唯一方法是使用 i 的地址。

例如,有一个新函数fun_addr:

void fun_addr(int *i) {
    *i = some_value;
}

通过这种方式,您可以更改 i 的值。

  1. 马洛克

fun_addr函数的关键点是,你已将地址传递给该函数。您可以更改存储在该地址中的值。

malloc 会做什么?

malloc 将分配一个新的内存空间,并将指向该地址的指针返回。

请看这个说明:

int *array = (int*) malloc(sizeof(int) * SIZE);

您正在做的是让数组的值等于 malloc 返回的地址。

看?这是同一个问题,永久地为传递给函数的参数赋值。此时,值为 。address

现在,将地址(由 malloc 返回)分配给地址(存储旧地址)。

所以代码应该是:

void fun_addr_addr(int **p) {
    *p = (int*) malloc(sizeof(int) * SIZE);
}

这个会起作用的。

1赞 PeterS 11/25/2017 #8

我唯一可以获取指向指针解决方案的指针解决方案的方法,以解决我在这个函数中遇到的类似问题

    BOOL OpenBitmap2 ( LPCTSTR pszFileName, char** pszBMPFile)  

是通过分配一个临时指针来存储地址

    char* BMPFile;
    { BMPFile = (char*)GlobalAlloc(GPTR, dwFileSize + 1);   // allocate storage using GlobalAlloc + 1 for null term string

然后重新分配它

    {* pszBMPFile = BMPFile; return (0);} // Error = False

关于为什么直接在 GlobalAlloc 中使用“* pszBMPFile”不起作用的任何评论将不胜感激。 我回答了自己的问题。我忘了在其他代码行中用 pszBMPFile 携带“*”。所有贡献者的教训都很好。非常感谢。

3赞 Song Wang 6/2/2020 #9

正如其他答案中提到的,我们需要一个指向指针的指针。但是为什么?

我们需要通过指针传递值才能修改值。如果要修改 ,则需要通过 .intint*

在这个问题中,我们要修改的值是一个指针(指针从更改为分配的内存的地址),因此我们需要传递指针到指针。int*NULLint**

通过执行 followed,里面是参数的副本。当我们将内存分配给局部变量时,其中的内存是完整的。pIntfoo(int*)main()

void foo(int* pInt)
{
   pInt = malloc(...);
}
int main()
{
   int* pInt;
   foo(pInt);
   return 0;
}

所以我们需要一个指针到指针,

void foo(int** pInt)
{
   *pInt = malloc(...);
}
int main()
{
   int* pInt;
   foo(&pInt);
   return 0;
}